I want to make an SVG a random color every time s is hit

I managed to get the head and the color outline, two SVG files, lined up completely. But there’s one problem: I wanna make the head color change to a random color every time “s” is hit. But somehow its not changing the color of the head, although getRandomColor does work;

// Function to generate a random color
function getRandomColor() {
    const letters = '0123456789ABCDEF';
    let color = '#';
    for (let i = 0; i < 6; i++) {
        color += letters[Math.floor(Math.random() * 16)];
    }
    return color;
}

// Function to change the color of the path element
function changePathFillColor() {
    const pathElement = document.getElementById('path-to-change');
    if (pathElement) {
        const randomColor = getRandomColor();
        pathElement.setAttribute('fill', randomColor);
    }
}

// Listen for the 'S' key press
document.addEventListener('keydown', function(event) {
    if (event.key === 's' || event.key === 'S') {
        changePathFillColor();
    }
});

And as for the HTML code, I decided I would be getting the contents of the head color’s svg file and re-organizing the code like this:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Character Assembly</title>
    <link rel="stylesheet" href="player.css">
</head>
<body>
    <div class="character">
        <!-- Outline SVG -->
        <div class="head">
    <svg id="svg-to-change" xmlns="http://www.w3.org/2000/svg" width="150" height="90">


              <g transform="matrix(1.0, 0.0, 0.0, 1.0, 75.0, 45.0)">
    <path d="M75.0 0.0 Q75.0 18.65 53.0 31.8 31.05 45.0 0.0 45.0 -31.05 45.0 -53.05 31.8 -75.0 18.65 -75.0 0.0 -75.0 -18.65 -53.05 -31.85 -31.05 -45.0 0.0 -45.0 31.05 -45.0 53.0 -31.85 75.0 -18.65 75.0 0.0" fill="#ffcc66" fill-rule="evenodd" stroke="none"/>
  </g>
            <image href="/svgs/head/shapes/9.svg" id="headoutline"/>
  </svg>

</div>
      <!--  <object data="body.svg" type="image/svg+xml" class="part body"></object>
        <object data="leftarms.svg" type="image/svg+xml" class="part arms"></object>
        <object data="rightarms.svg" type="image/svg+xml" class="part arms"></object>
        <object data="leftlegs.svg" type="image/svg+xml" class="part legs"></object>
        <object data="rightlegs.svg" type="image/svg+xml" class="part legs"></object>-->
    </div> 

    <script src="player.js"></script>
</body>
</html>

and here is my CSS code.

.character {
    position: relative;
    width: 200px; /* Adjust the size as needed */
    height: 400px; /* Adjust the size as needed */
}

.part {
    position: absolute;
}

.head {
    animation: float 2s ease-in-out infinite;
    position: relative;
}
.headcolor {
   z-index: 1;
   margin-top: -500px;
   position: relative; 
}

.headoutline {
   z-index: 2;
   position: relative; margin
  width: 100%; 
  height: 100%; 
}

@keyframes float {
    0%, 100% {
        transform: translateY(0); /* Starting position */
    }
    50% {
        transform: translateY(-5px); /* Float up by 10 pixels */
    }
}

My guess on why this is not working is because there are two SVG files involved and the system does not know which one to change the color of. So I was thinking I should add an ID to the exposed SVG but I have no idea on how to point at it in the JavaScript code. So what can I do to make this work?

Vite / Browserslist: cover 99.5%

I want to use the browserslist rule cover 99.5% so I can cover most of the users browsers.

I am using vite and I tried to use @vite/plugin-legacy (https://www.npmjs.com/package/@vitejs/plugin-legacy) to make the transpilation/polyfills to make my bundle compatible with older browsers.

Here is my config:

# vite.config.ts
    legacy({
      targets: ['cover 99.5%'],
      modernPolyfills: true,
      polyfills: true,
    }),

But when I ctrl+f the build code it still show me reference of many features that is incompatible for older browsers.
E.g I see the use of Date.now() but it’s not compatible with IE8.

What I’m missing ?
Am I dreaming and vite is not able to transpile my code like that so easily ?

How to disable scroll wheel zoom in ApexCharts?

I’ve got a line chart in my app using ApexCharts:

import ApexCharts from "apexcharts";

var options = {
  chart: {
    type: "line",
  },
  series: [
    {
      name: "sales",
      data: [30, 40, 35, 50, 49, 60, 70, 91, 125],
    },
  ],
  xaxis: {
    categories: [1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999],
  },
};

var chart = new ApexCharts(document.querySelector("#chart"), options);

chart.render();

When I hover the chart and scroll using the mouse wheel, the chart zooms in/out. How do I disable this behavior?

Example

Using different fonts in Incisor?

I am building a javascript game with Incisor. I have a particular font that I would like to use. What is the process for doing this with Incisor?

I have a .ttf file but I don’t know what to do with it. What is my next step?

How to disable [dynamic] when debugging nodeJS on Visual Studio?

Whenever i set a breakpoint on a javascript file it opens an annoying window which is a copy from the original file, its written [dynamic] and its not editable:

enter image description here

How do i disable this thing?

Im debugging a nodejs project not web.

I already tried unchecking the option enable javascript debug for asp.net (chrome, edge, and ie). but it continues openning that window.

Visual Studio 2022

Chrome Extension: Handling tabId === -1 in webRequest.onBeforeRequest Listener for Fetch Requests

I’m developing a Chrome extension that listens for requests to a particular url and sends a message to the tab that initiated the request. Here’s the relevant part of my background.ts:

chrome.webRequest.onBeforeRequest.addListener(
  (request) => {
    logger.infoDev('Received request', request);

    if (request.tabId === -1) {
      // we are hitting here with requests that are being intercepted by service workers
      return;
    }

    chrome.tabs.get(request.tabId, (tab) => {
      chrome.tabs.sendMessage<InnerMessage>(request.tabId, {
        type: MessageType.Loaded,
        payload: request,
        location: getLocation(tab.url),
      });
    });
  },
  {
    urls: ['https://some-request-url.com/*'],
  },
);

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  switch (message.type) {
    case 'UpdateBadgeCount':
      if (!sender.tab || sender.tab.id === undefined) {
        console.error('Unexpected source of UpdateBadgeCount message');
        return;
      }
      updateBadgeCount(sender.tab.id, message.payload.count); // just updates the count that shows on the extension
      sendResponse();
      break;
    default:
      console.error('Unexpected message type in background script');
  }
});

function getLocation(url: string | undefined) {
  return url ? url.replace(/https?://(?:www.)?/, '') : '';
}

I’m encountering a problem where request.tabId becomes -1 for some requests to our url. Specifically, on certain websites, it looks like they have some sort of service worker intercepting all requests.

My Questions:

  • How can I reliably associate requests with tabId === -1 to the correct tab in the onBeforeRequest listener?
  • Is there a way to handle these fetch requests (with tabId === -1) so that the extension can correctly update the page visit count or badge count?
  • Are there best practices for dealing with requests initiated by service workers or via the Fetch API that result in tabId === -1?

I attempted to handle the tabId === -1 case by using chrome.tabs.query with the initiator URL to find the tab:

if (request.tabId === -1) {
  if (request.initiator) {
    chrome.tabs.query({ url: request.initiator + '/*' }, (tabs) => {
      if (tabs.length > 0) {
        const tab = tabs[0];
        chrome.tabs.sendMessage(tab.id, {
          type: 'RequestDetected',
          payload: request,
          location: getLocation(tab.url),
        });
      } else {
        console.warn(`Could not find tab for initiator ${request.initiator}`);
      }
    });
  } else {
    console.warn(`No tabId or initiator for request ${request.requestId}`);
  }
} else {
  // Original code handling valid tabId
}

When multiple tabs have the same initiator URL (e.g., several tabs open to the same site), this method incorrectly updates the badge count or performs actions on the wrong tabs. It doesn’t reliably associate the request with the correct tab, leading to unintended behavior.

Ignoring requests with tabId === -1 is not ideal because we would miss handling legitimate requests that are important for the extension’s functionality.

Skeleton loader not showing when useFetch status is pending

I’m trying to implement an image gallery with a skeleton loader that should display while the images are loading. However, for some reason, the loader is not showing up even with throttling on. I understand that I should use the onload event to check if the images are loaded, but I want to verify that the skeleton loader works while the data is being fetched. If I set the condition to v-if="status !== 'pending'", I can see the skeleton. I tried adding a delay await new Promise((r) => setTimeout(r, 1000)); before imgList.value = data.value.data;, but I still couldn’t see the loader. Also, tried using <Suspense> to use a skeleton as a fallback, but it didn’t work.

Reproduction: https://stackblitz.com/edit/nuxt-starter-63w6mv?file=app%2Fpages%2Fgallery.vue

Template:

<div class="w-32 h-32 bg-white" v-if="status === 'pending'" />
<img
  class="w-full cursor-pointer rounded-lg object-cover shadow-2xl"
  crossorigin="anonymous"
  :src="item.url"
  v-else
/>

Script:

const imgList = ref<Image[]>([]);

const { apiBase } = useRuntimeConfig().public;
const { data, status, error } = await useFetch<{ data: Image[] }>(
  `${apiBase}/get-images`,
  { lazy: true }
);
watchEffect(() => {
  if (status.value === 'success') {
    if (data.value) {
      // await new Promise((r) => setTimeout(r, 1000));
      imgList.value = data.value.data;
    }
    console.log(data.value.data);
  } else if (status.value === 'error') {
    console.error('Error loading images: ', error.value);
  }
});

I’m looking for a possible solution.

Resize Height IMG on Wheelzoom.js

whats up.
I’m just trying to make an zoomable image on a modal! And I’m using wheelzoom.js

It’s almost perfect, but I need to resize the image HEIGTH that is auto, by deafault, when the orientation of the img is HORIZONTAL. And resize the width when its vertical!

The zoom must work with pinch move, too..

Here’s my project on a freehost

Someone could help me?

My demo.html:



<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <title>Wheelzoom</title>
    <style>
        body {
            margin: 0;
            padding: 0;
        }

        .containerzoom {
            border: 1px dashed;
            /* Borda visual para identificar o contêiner */
            height: 98dvh;
            /* Usando unidade 'dvh' para melhor responsividade em dispositivos móveis */
            max-width: 100vw;
            /* Garante que o contêiner não ultrapasse a largura da viewport */
            display: flex;
            justify-content: center;
            /* Centraliza a imagem horizontalmente */
            align-items: center;
            /* Centraliza a imagem verticalmente */
            position: relative;
            /* Necessário para posicionar elementos dentro */
            overflow: hidden;
            /* Garante que o conteúdo que ultrapassa seja cortado */
            top: 10px;
            /* Desloca o contêiner para baixo */
        }

        .containerzoom img {
            border: 2px solid;
            /* Borda para a imagem se necessário */
            max-width: 100%;
            /* Limita a largura máxima da imagem */
            max-height: 100%;
            /* Limita a altura máxima da imagem */
            width: auto;
            /* Mantém a proporção correta */
            height: auto;
            /* Mantém a proporção correta */
            object-fit: contain;
            /* Ajusta a imagem dentro da div, mantendo a proporção */
            transition: transform 0.3s ease;

            /* Indica que a imagem pode ser ampliada */
        }

        /* .containerzoom img:active {
            cursor: move;
        } */

        .zoom-button {
            position: absolute;
            top: 40px;
            background: rgba(255, 255, 255, 0.7);
            border: 1px solid #ccc;
            border-radius: 5px;
            padding: 10px;
            cursor: pointer;
            font-size: 16px;
            margin-left: auto;
        }

        .zoom-in {
            left: 10px;
        }

        .zoom-out {
            left: 90px;
        }
    </style>
</head>

<body>
    <div class="containerzoom">
        <img class='zoom zoomedimage'
            src='https://img.freepik.com/free-photo/panoramic-shot-erg-chebbi-dunes-sahara-desert-merzouga-morocco_181624-16129.jpg?t=st=1727474703~exp=1727478303~hmac=e729edeeaed62fafb9627aa20e68dd4d79a4fdc2c7daeda09c619101c99e9e63&w=1380'
            alt='Daisy!' />
        <!-- <img class='zoom zoomedimage' src='http://localhost/apis/gallery-box/img/image%20(112).jpeg' alt='Daisy!' /> -->

    </div>

    <button class="zoom-button zoom-in">Zoom In</button>
    <button class="zoom-button zoom-out">Zoom Out</button>



    <script src="wheelzoom.js"></script>
    <script>
        const img = document.querySelector('img.zoom');
        wheelzoom(img);

        const zoomInButton = document.querySelector('.zoom-in');
        const zoomOutButton = document.querySelector('.zoom-out');

        // Função para atualizar os estilos dos botões
        function updateZoomButtons() {
            const currentBgSize = img.style.backgroundSize.split(' ')[0] || '100%'; // Pega a largura atual ou padrão
            const width = parseFloat(currentBgSize); // Converte para número

            // Tamanho padrão
            const defaultSize = img.clientWidth;

            // Atualiza a opacidade e o cursor do botão de zoom out
            if (width <= defaultSize) {
                zoomOutButton.style.opacity = 0.5;
                zoomOutButton.style.cursor = 'default';
                zoomOutButton.disabled = true; // Desabilita o botão
            } else {
                zoomOutButton.style.opacity = 1;
                zoomOutButton.style.cursor = 'pointer';
                zoomOutButton.disabled = false; // Habilita o botão
            }

            // Usa o valor de width atual para verificar se o zoom máximo foi atingido
            if (width >= defaultSize * 2.4) { // Defina o fator de zoom máximo desejado
                console.log(`Desabilitando o botão Zoom In: width = ${width}, defaultSize = ${defaultSize}`);
                zoomInButton.style.opacity = 0.5;
                zoomInButton.style.cursor = 'default'; // Cursor padrão
                zoomInButton.disabled = true; // Desabilita o botão
            } else {
                zoomInButton.style.opacity = 1;
                zoomInButton.style.cursor = 'pointer'; // Cursor pointer
                zoomInButton.disabled = false; // Habilita o botão
            }

            // Log do tamanho atual da imagem
            console.log(`Tamanho atual da imagem: ${width}px`);
        }

        zoomInButton.addEventListener('click', () => {
            const event = new WheelEvent('wheel', { deltaY: -50, bubbles: true, cancelable: true });
            img.dispatchEvent(event);
            updateZoomButtons();
        });

        zoomOutButton.addEventListener('click', () => {
            const currentBgSize = img.style.backgroundSize.split(' ')[0] || '100%';
            const width = parseFloat(currentBgSize);

            if (width > img.clientWidth) {
                const event = new WheelEvent('wheel', { deltaY: 50, bubbles: true, cancelable: true });
                img.dispatchEvent(event);
                updateZoomButtons();
            }
        });

        updateZoomButtons(); // Chama inicialmente para configurar os botões
    </script>
</body>

</html>

AND my Wheelzoom.js:

window.wheelzoom = (function () {
    var defaults = {
        zoom: 0.20,
        maxZoom: 5,
        initialZoom: 1,
        initialX: 0.5,
        initialY: 0.5,
    };

    var main = function (img, options) {
        if (!img || !img.nodeName || img.nodeName !== 'IMG') { return; }

        var settings = {};
        var width;
        var height;
        var bgWidth;
        var bgHeight;
        var bgPosX;
        var bgPosY;
        var previousEvent;
        var transparentSpaceFiller;

        function setSrcToBackground(img) {
            img.style.backgroundRepeat = 'no-repeat';
            img.style.backgroundImage = 'url("' + img.src + '")';
            transparentSpaceFiller = 'data:image/svg+xml;base64,' + window.btoa('<svg xmlns="http://www.w3.org/2000/svg" width="' + img.naturalWidth + '" height="' + img.naturalHeight + '"></svg>');
            img.src = transparentSpaceFiller;
        }

        function updateBgStyle() {
            if (bgPosX > 0) {
                bgPosX = 0;
            } else if (bgPosX < width - bgWidth) {
                bgPosX = width - bgWidth;
            }

            if (bgPosY > 0) {
                bgPosY = 0;
            } else if (bgPosY < height - bgHeight) {
                bgPosY = height - bgHeight;
            }

            img.style.backgroundSize = bgWidth + 'px ' + bgHeight + 'px';
            img.style.backgroundPosition = bgPosX + 'px ' + bgPosY + 'px';
        }

        function reset() {
            bgWidth = width;
            bgHeight = height;
            bgPosX = bgPosY = 0;
            updateBgStyle();
        }

        function onwheel(e) {
            var deltaY = e.deltaY ? e.deltaY : -e.wheelDelta;
            e.preventDefault();

            var rect = img.getBoundingClientRect();
            var offsetX = e.pageX - rect.left - window.pageXOffset;
            var offsetY = e.pageY - rect.top - window.pageYOffset;

            var bgCursorX = offsetX - bgPosX;
            var bgCursorY = offsetY - bgPosY;

            var bgRatioX = bgCursorX / bgWidth;
            var bgRatioY = bgCursorY / bgHeight;

            if (deltaY < 0) {
                bgWidth += bgWidth * settings.zoom;
                bgHeight += bgHeight * settings.zoom;
                img.style.cursor = 'move';
            } else {
                bgWidth -= bgWidth * settings.zoom;
                bgHeight -= bgHeight * settings.zoom;
                img.style.cursor = 'default';
            }

            if (settings.maxZoom) {
                bgWidth = Math.min(width * settings.maxZoom, bgWidth);
                bgHeight = Math.min(height * settings.maxZoom, bgHeight);
            }

            bgPosX = offsetX - (bgWidth * bgRatioX);
            bgPosY = offsetY - (bgHeight * bgRatioY);

            if (bgWidth <= width || bgHeight <= height) {
                reset();
            } else {
                updateBgStyle();
            }
        }




        function drag(e) {
            e.preventDefault();
            bgPosX += (e.pageX - previousEvent.pageX);
            bgPosY += (e.pageY - previousEvent.pageY);
            previousEvent = e;
            updateBgStyle();
        }

        function removeDrag() {
            document.removeEventListener('mouseup', removeDrag);
            document.removeEventListener('mousemove', drag);
        }

        function draggable(e) {
            e.preventDefault();
            previousEvent = e;
            document.addEventListener('mousemove', drag);
            document.addEventListener('mouseup', removeDrag);
        }

        function load() {
            var initial = Math.max(settings.initialZoom, 1);
            if (img.src === transparentSpaceFiller) return;

            var computedStyle = window.getComputedStyle(img, null);
            width = parseInt(computedStyle.width, 10);
            height = parseInt(computedStyle.height, 10);
            bgWidth = width * initial;
            bgHeight = height * initial;
            bgPosX = -(bgWidth - width) * settings.initialX;
            bgPosY = -(bgHeight - height) * settings.initialY;

            setSrcToBackground(img);

            img.style.backgroundSize = bgWidth + 'px ' + bgHeight + 'px';
            img.style.backgroundPosition = bgPosX + 'px ' + bgPosY + 'px';
            img.addEventListener('wheelzoom.reset', reset);
            img.addEventListener('wheel', onwheel, { passive: false });
            img.addEventListener('mousedown', draggable);
        }

        function touchStart(e) {
            e.preventDefault();
            previousEvent = e.touches[0];
            document.addEventListener('touchmove', touchMove);
            document.addEventListener('touchend', touchEnd);
        }

        function touchMove(e) {
            e.preventDefault();
            bgPosX += (e.touches[0].pageX - previousEvent.pageX);
            bgPosY += (e.touches[0].pageY - previousEvent.pageY);
            previousEvent = e.touches[0];
            updateBgStyle();
        }

        function touchEnd() {
            document.removeEventListener('touchmove', touchMove);
            document.removeEventListener('touchend', touchEnd);
        }

        var destroy = function (originalProperties) {
            img.removeEventListener('wheelzoom.destroy', destroy);
            img.removeEventListener('wheelzoom.reset', reset);
            img.removeEventListener('load', load);
            img.removeEventListener('mouseup', removeDrag);
            img.removeEventListener('mousemove', drag);
            img.removeEventListener('mousedown', draggable);
            img.removeEventListener('wheel', onwheel);
            img.removeEventListener('touchstart', touchStart);
            img.removeEventListener('touchmove', touchMove);
            img.removeEventListener('touchend', touchEnd);

            img.style.backgroundImage = originalProperties.backgroundImage;
            img.style.backgroundRepeat = originalProperties.backgroundRepeat;
            img.src = originalProperties.src;
        }.bind(null, {
            backgroundImage: img.style.backgroundImage,
            backgroundRepeat: img.style.backgroundRepeat,
            src: img.src
        });

        img.addEventListener('wheelzoom.destroy', destroy);

        options = options || {};
        Object.keys(defaults).forEach(function (key) {
            settings[key] = options[key] !== undefined ? options[key] : defaults[key];
        });

        if (img.complete) {
            load();
        }

        img.addEventListener('load', load);
        img.addEventListener('touchstart', touchStart, { passive: false });
    };

    if (typeof window.btoa !== 'function') {
        return function (elements) {
            return elements;
        };
    } else {
        return function (elements, options) {
            if (elements && elements.length) {
                Array.prototype.forEach.call(elements, function (node) {
                    main(node, options);
                });
            } else if (elements && elements.nodeName) {
                main(elements, options);
            }
            return elements;
        };
    }
}());

what is a good roadmap for begginers? [closed]

I started programming some months ago, and im really lost on what to learn, i’m learning C on university and im really liking it, but i was thinking on going to front-end first, i studied html and css and now im learning js, probably after that im gonna start learnig react or php, what do you guys think?
i think i have a good basis in html, and ive done learned flexbox and grid layout in css, i was going to javascript because i already have this knowledge in html and css, plus i have a good idea of UX/UI, so i think its a good way to go, learning javascript and react, but i’m asking for opnions.

handsontable unfreeze a column and return to original position

I’m trying to create a handsontable table where when I freeze the column it goes to the 0th column position, but when you right click to unfreeze I’d like it to go back to its original location.

I’ve tried using a custom callback unfreezeColumn that takes on the original order of the columns so that if I freeze the column in position index 3 it will go to 0 when frozen and back to 3 when unfrozen, but this custom indexing function is not working

Codepen here: https://codepen.io/MayaRGans/pen/mdNJJwm

<div id="grid" class="handsontable"></div>
$(function () {
  var data = [
    ['Year', 'Maserati', 'Mazda', 'Mercedes', 'Mini', 'Mitsubishi'],
    ['2009', 0, 2941, 4303, 354, 5814],
    ['2010', 5, 2905, 2867, 412, 5284],
    ['2011', 4, 2517, 4822, 552, 6127],
    ['2012', 2, 2422, 5399, 776, 4151]
  ];

  const container = document.getElementById('grid');
  let isUpdatingOrder = false; // Flag to prevent recursion
  const originalOrder = [...Array(data[0].length).keys()]; // Track the original column order
  const hiddenColumnsList = [];
  const expandedCells = {};

  // Initialize Handsontable
  const hot = new Handsontable(container, {
    data: data,
    columns: originalOrder.map((index) => ({
      title: data[0][index],
      minWidth: 150,
      width: 160
    })),
    filters: true,
    dropdownMenu: ['filter_by_value', 'filter_action_bar'],
    height: 900,
    autoWrapRow: true,
    autoWrapCol: true,
    contextMenu: {
      items: {
        "freeze_column": {},
        "unfreeze_column": {
          name: 'Unfreeze column',
          callback: function(key, selection) {
            const colIndex = selection[0].start.col;
            console.log('Unfreezing column index:', colIndex);
            unfreezeColumn(colIndex);
          }
        },
        "hidden_columns_hide": {},
        "hidden_columns_show": {}
      }
    },
    manualColumnFreeze: true,
    readOnly: true,
    editor: false,
    width: '100%',
    colHeaders: true,
    manualColumnResize: true,
    autoColumnSize: true,
    wordWrap: true,
    className: 'jnj-table',
    licenseKey: 'non-commercial-and-evaluation',
    hiddenColumns: {
      columns: hiddenColumnsList,
      indicators: true
    }
  });

  // Function to unfreeze the column
  function unfreezeColumn(colIndex) {
    hot.getPlugin('manualColumnFreeze').unfreezeColumn(colIndex);
    updateColumnOrder();
  }

  // Function to update the column order
  function updateColumnOrder() {
    if (isUpdatingOrder) return; // Prevent recursion
    isUpdatingOrder = true; // Set the flag

    const currentOrder = hot.getSettings().manualColumnMove || [];
    
    // Restore the columns to the original order only if they're not in the original state
    if (!arraysEqual(currentOrder, originalOrder)) {
      hot.updateSettings({
        manualColumnMove: originalOrder
      });
    }

    hot.render();
    isUpdatingOrder = false; // Reset the flag
  }

  // Helper function to compare two arrays
  function arraysEqual(arr1, arr2) {
    if (arr1.length !== arr2.length) return false;
    return arr1.every((value, index) => value === arr2[index]);
  }

});

Recharts – Custom X axis tick – wrong transform on mobile screen

I am trying to have custom labels for my x axis ticks. It seems to work fine on web browsers, but I can’t get it to position correctly on mobile when I rotate the icon.

This is my label code:

const CustomXAxisTick = ({ x, y, payload, data }: any) => {
        const degrees = 90 // this is dynamic later
        return (
            <g transform={`translate(${x},${y})`}>
                <foreignObject x={-6} y={14} dy={20} width={20} height={20}>
                    <FaArrowUp className="w-3 h-3" style={{ transform: `rotate(${degrees}deg)` }} />
                </foreignObject>
            </g>
        )
    }

On web:

enter image description here

However on mobile (see that the icon moved to the top left)

enter image description here

Any suggestions on how to fix that or why this is happening?

How to find/colorize different between two Meshes of the STEP file uploaded with STEPLoader in Three.js

I have two STEP files, After.stp and Before.stp, of the same object. In the Before.stp file, some surfaces have shifted or deviated compared to After.stp. I need to identify and colorize the different areas between these two STEP files to visualize the changes.

I’ve tried loading the STEP files using Three.js STEPLoader and extracted the meshes, including indexes, brep_faces, and attributes. However, I’m unsure how to compare the two meshes and highlight the differences between them.

Could anyone provide a sample example or guidance on how to achieve this? Any help would be greatly appreciated.

Viem: use simulateContract to get values return from a smart contract write function

In the viem docs, it mentions that writeContract only returns the transaction hash and to use simulateContract to get the values returned from a writeContract call.
https://viem.sh/docs/contract/writeContract.html#return-value

However, the only thing I get returned from the simulateContract call is the request that I pass into the writeContract function after it’s verified, but I don’t see anything resembling the return values in this request and there is nothing else returned.

So how do you get the values returned from a write function when using viem? Is it not possible? Also, won’t the simulation results sometimes differ from the result that would actually be returned from a write based on what happens during that block?