How to calculate the new transform origin when translate is applied

I’ve created a touch event to be able to zoom into an image, saved the x and y values in the touchstart

imageContainer.addEventListener("touchstart", function (event) {
   event.preventDefault();
   if (event.touches.length === 2) {

      let touch1s = [event.touches[0].pageX, event.touches[0].pageY];
      let touch2s = [event.touches[1].pageX, event.touches[1].pageY];

      x = Math.abs(touch1s[0] + touch2s[0]) / 2;
      y = Math.abs(touch1s[1] + touch2s[1]) / 2;

      originalDistance = Math.hypot(event.touches[0].pageX - event.touches[1].pageX,event.touches[0].pageY - event.touches[1].pageY );

      zoomDrag[0].disable();
   }
});

In the touchmove event listener I have added in functionality to be able to zoom in and out on the point of my finger,

imageContainer.addEventListener("touchmove", function (event) {
   event.preventDefault();
   if (event.touches.length === 2) {
      let currentDistance = Math.hypot(event.touches[0].pageX - event.touches[1].pageX,event.touches[0].pageY - event.touches[1].pageY);
 
      if (originalDistance < currentDistance) {
         if (gsap.getProperty(imageContainer, "scale") <= maxScale) {
            zoom_control(imageContainer, x, y, "+=0.4");
         }
      } else if (originalDistance > currentDistance) {
         if (gsap.getProperty(imageContainer, "scale") >= minScale) {
            zoom_control(imageContainer, x, y, "-=0.4");
         } 
      }
   }
});

However when I implement the GSAP Draggable library and perform a drag when I am zoomed in, and try to zoom back in/out, the transform origin isn’t where it should be.

Math isn’t my strong suit so what would the formula be to make the transform origin correct?

Memory Leak When Dynamically Updating Content Using srcdoc in JavaScript

We are experiencing memory leaks in a web application where we dynamically update elements with new HTML content using the srcdoc property. This issue becomes apparent after extended usage, especially when the content within the s changes frequently. The problem is worse with the highest diversity of html content. If the diversity of content is too high, it will consistently max out memory usage.

Our application uses two elements per container, switching between them to ensure a smooth transition. One is updated with new content using srcdoc, and once loaded, we switch its visibility with the currently active . The previously active is then cleared and hidden.

However, over time, this approach seems to cause a memory leak (e.g., Google Chrome, Edge, Opera). The memory usage keeps increasing, even after the unused is cleared. Firefox does not appear to suffer from the memory leak, however, video in the htmls seem to gradually suffer from slower playback.

Questions:

  • What’s the recommended way to dynamically update content without causing memory leaks in modern browsers?
  • Is there a more efficient pattern for managing and cleaning up resources when using srcdoc?

Current Implementation:

Here’s the logic for updating the srcdoc property and handling the onload event:

if (received_data.html) {
    var inactiveIframe = document.getElementById(iframeIds.inactiveIframe);
    
    // Update the srcdoc of the inactive iframe, which triggers content loading
    inactiveIframe.srcdoc = received_data.html;

    // Handle the iframe size if provided
    if (received_data.width && received_data.height) {
        inactiveIframe.style.width = received_data.width + "px";
        inactiveIframe.style.height = received_data.height + "px";
        inactiveIframe.parentNode.style.height = received_data.height + "px";
        inactiveIframe.parentNode.parentNode.style.height = received_data.height + "px";
    }

    // Set up the onload event handler to switch iframes after the new content has loaded
    inactiveIframe.onload = async function() {
        await switchIframe(iframeIds);
        // Optionally, remove the event listener after the switch
        inactiveIframe.onload = null;
    };

    validateResources(received_data.html);
}

The switchIframe function is responsible for swapping the active and inactive iframes:

function switchIframe(iframeIds) {
    // Swap the active and inactive iframe IDs
    let temp = iframeIds.activeIframe;
    iframeIds.activeIframe = iframeIds.inactiveIframe;
    iframeIds.inactiveIframe = temp;

    // Hide the previously active iframe
    const inactiveIframeElement = document.getElementById(iframeIds.inactiveIframe);
    inactiveIframeElement.style.zIndex = '999997';
    inactiveIframeElement.style.opacity = '0';

    // Clear the content of the inactive iframe
    inactiveIframeElement.srcdoc = '';
    let frameDoc = inactiveIframeElement.contentDocument || inactiveIframeElement.contentWindow.document;
    if (frameDoc) {
        frameDoc.documentElement.innerHTML = '';
    }

    // Remove event listeners
    inactiveIframeElement.onload = null;

    // Show the new active iframe
    const activeIframeElement = document.getElementById(iframeIds.activeIframe);
    activeIframeElement.style.zIndex = '999998';
    activeIframeElement.style.opacity = '1';
}

Result: The memory usage maxes out over time.

Alternative Approaches Tried:

We’ve tried different strategies to avoid memory leaks, but none were successful:

  1. Recreate the : Instead of reusing the inactive , we removed it from the DOM and re-added a new with the same ID:
const inactiveIframeElement = document.getElementById(iframeIds.inactiveIframe);
inactiveIframeElement.srcdoc = '';
inactiveIframeElement.parentElement.innerHTML = `
    <iframe id="${iframeIds.inactiveIframe}" class="iframe-class" scrolling="no" srcdoc=""></iframe>`;

Result: The memory usage maxes out over time.

  1. Clearing HTML with innerHTML: Cleared the ’s content using innerHTML, as shown below:
let frameDoc = inactiveIframeElement.contentDocument || inactiveIframeElement.contentWindow.document;
if (frameDoc) {
    frameDoc.documentElement.innerHTML = '';
}

Result: The memory usage maxes out over time.

How to keep slidesPerGroup when swipe back after reachEnd?

I have 7 slides and swiper setting loop: false, slidesPerView: 3, slidesPerGroup: 3,

  1. Swipe 3 cards at a time.
  2. When there are not enough cards left for the next group of 3, it should show the last 3 cards.

when swipe next it works fine:
123 -> 456 -> 567

But when swipe back it acts:
567 -> 456 -> 123

And I want it keep three slidesPerGroup :
567 -> 345 -> 123

Can I do this by Swiper.js?

<div class="container">   
    <div class="swiper-container">
        <div class="swiper-wrapper">
            <div class="swiper-slide">Slide 1</div>
            <div class="swiper-slide">Slide 2</div>
            <div class="swiper-slide">Slide 3</div>
            <div class="swiper-slide">Slide 4</div>
            <div class="swiper-slide">Slide 5</div>
            <div class="swiper-slide">Slide 6</div>
            <div class="swiper-slide">Slide 7</div>
        </div>
        <div class="swiper-button-prev"></div>
        <div class="swiper-button-next"></div>
    </div>
</div>
<script src="https://unpkg.com/swiper/swiper-bundle.min.js"></script>
<script>
  document.addEventListener("DOMContentLoaded", function() {
  new Swiper('.swiper-container', {
        loop: false,
        nextButton: '.swiper-button-next',
        prevButton: '.swiper-button-prev',
        slidesPerView: 3,
        slidesPerGroup: 3,
        spaceBetween: 20,
    });
});
</script>

CodePen

Where does index come from? [duplicate]

Would you be so kind to explain one thing? I’ve got a snippet of code from a w3schools example.

let text = "";
const fruits = ["apple", "orange", "cherry"];
fruits.forEach(myFunction);

document.getElementById("demo").innerHTML = text;
 
function myFunction(item, index) {
  text += index + ": " + item + "<br>"; 
}

Can you tell me please, how it works? Especially, where index parameter comes from, if it it was defined anywhere? I do understand that item parameter goes for each array element, but how counting happens?

You have a large list that is slow to update error after memoizing renderItem function

I’ve tried every solution on StackOverflow, a couple of other webpages and various chatbots. They all give me several solutions, including: wrapping my renderItem function in a memoization, using a pureComponent class instead of a function component and useCallback.

No matter what I use, I’m still getting the same error. It causes the UI to freeze up, so I can’t just ignore it! What’s even more frustrating, is that I wrapped the renderItem function in a memo for another list with a similar renderItem function and data structure, and it worked!

I’ve tried the following code:

const BleSections = (params) => {
    if (!params.device) {
        return [];
    }

    const { sections: deviceSections } = params.device;

    return [
        {
            title: "Address",
            data: [
                { label: "MAC", value: params.device.bleDeviceAddress },
            ],
        },
        {
            title: "Temperature",
            data: [
                { label: "Cloud ID", value: deviceSections?.Temperature?.cloud_id },
                { label: "Local ID", value: deviceSections?.Temperature?.local_id },
            ],
        },
        {
            title: "Humidity",
            data: [
                { label: "Cloud ID", value: deviceSections?.Humidity?.cloud_id },
                { label: "Local ID", value: deviceSections?.Humidity?.local_id },
            ],
        },
        {
            title: "Panic",
            data: [
                { label: "Cloud ID", value: deviceSections?.Panic?.cloud_id },
                { label: "Local ID", value: deviceSections?.Panic?.local_id },
            ],
        },
    ];
};

export default BleSections;
const sections = BleSections({
    device: Object.values(bleDevices).find(device => bleDevice &&
    device.bleDeviceAddress === bleDevice.id)
});
import React, { memo } from "react";
import { View, Text } from "react-native";

import ScanStyle from "../Styles/ScanStyle.js";

import BleTextRender from "./BleTextRender.js";

const BleSectionRender = ({ item: section }) => {
    return (
        <View style={ScanStyle.subSectionContainer}>
            <Text style={ScanStyle.subSectionTitle}>
                {section.title}
            </Text>
            {section.data.map((item, itemIndex) => (
                <View key={itemIndex}>
                    <BleTextRender
                        label={item.label}
                        value={item.value}
                    />
                </View>
            ))}
        </View>
    );
};

export default memo(BleSectionRender);
import React, { memo } from "react";
import { View, Text } from "react-native";

import ScanStyle from "../Styles/ScanStyle";

const BleTextRender = ({ label, value }) => {
    return (
        <View style={ScanStyle.textContainer}>
            <Text style={ScanStyle.textLabel}>
                {label}:
            </Text>
            <Text style={ScanStyle.textValue}>
                {value ? value : "Not set"}
            </Text>
        </View>
    );
};

export default memo(BleTextRender);
<FlatList                        
    data={sections}
    renderItem={BleSectionRender} 
    keyExtractor={(item, index) => index.toString()}                                 
    contentContainerStyle={ScanStyle.content}
/>

Next.js or Browser blocking redirection requests by Payment Provider after 3ds verification

I am implementing the MPGS payment gateway in my Next.js app. I provide the redirection URL to the MPGS API, which in turns provide me an HTML to be injected into this page. This html contains a form and an iframe. When the 3ds is successful the iframe tries to redirect the website to the redirect URL, I get a long list of redirection attempts in the Chrome Network tab but the page never actually redirects. Then I get the error in the iframe that
my-domain.com redirected you too many times. The redirection url is correct inside the Chrome Network tab but I cant figure out if the redirection is being blocked by Next.js or Chrome.

In my next.js client component, I fetch the three3ds HTML and display it as follows

<div
  ref={containerRef}
  dangerouslySetInnerHTML={{ __html: threeDSHtml }}
</div>

And in the useEffect I load the script provided by MPGS in the returned html

useEffect(() => {
    if (threeDSHtml) {
      setTimeout(() => {
        var e = document.getElementById("threedsChallengeRedirectForm")
        if (e) {
          e.submit()
          if (e.parentNode !== null) {
            e.parentNode.removeChild(e)
          }
        }
      }, 500)
    }
  }, [threeDSHtml])

enter image description here

WebdriverIO: can’t access window attribute

I’m having trouble accessing the window attribute in WebdriverIO testing.

In the JavaScript code I create a new instance of OpenLayers:

import Map from 'ol/Map.js';
import View from 'ol/View.js';
import TileLayer from 'ol/layer/Tile.js';
import OSM from 'ol/source/OSM.js';

window.map = new Map({
  view: new View({
    center: [0, 0],
    zoom: 1,
  }),
  layers: [
    new TileLayer({
      source: new OSM(),
    }),
  ],
  target: 'map',
});

I want to use the instance in the WebdriverIO test.

So far I have tried the technique described in this answer, which is the following:

 const result = browser.execute(function() {
    return window['map']
 });

When I include the code above, it doesn’t execute.

What I want is the following:

describe('Mocha Example', () => {
    it('Test view', async () => {
        const view = window.map.getView()

        // do something with view
    })
})

The error we get is the following:

window is not defined

I think I should be able to access the window property directly from the describe -> it function because it’s not a Unit Test but it is End to End testing that uses a web browser to run the tests.

How can I access the map property of window?

How to generate possible results combinations from a multi-page form with multiple choice questions?

I’ve created a multi-page form (5 pages) – each page has radio inputs and only one selection can be made per page (all fields are marked as required). Most answers will be assigned a ‘product’, some answers will be assigned the same product – I need to output the recommended assigned products on the confirmation page. at minimum, one product will be recommended as all questions on the first page have a product assigned, maximum there could be 5 products recommended if the user makes selections where the answer is associated to a product.

Simplified tables for context:

page 1 answers page 1 products
Choice A Product 1
Choice B Product 1
Choice C Product 2
Choice D Product 3
Choice E Product 1
Choice F Product 4
page 2 answers page 2 products
Choice A Product 1
Choice B Product 2
Choice C Product 3
Choice D no product
Choice E no product

and so on…

I sourced some jQuery(?) on another post, and made some edits to interact with the IDs association to my options

<script>

$('input[type=radio]').on("change", buttonChanged);

function buttonChanged() {
  if ($("#7_1").is(':checked') && $("#14_12").is(':checked') && $("#12_12").is(':checked') && $("#10_12").is(':checked') && $("#22_12").is(':checked')) {
    $(".test-display1").show();
  } else if ($("#7_2").is(':checked') && $("#14_13").is(':checked') && $("#12_13").is(':checked') && $("#10_13").is(':checked') && $("#22_13").is(':checked')) {
    $(".test-display2").show();
  }
}

</script>

The above works just fine, and the correct confirmation block displays – however, I’m just guessing there has to be an easier way to calculate/generate all possible combinations rather than writing each possible combo and having a lot of confirmation blocks in the code… I can use jQuery or JavaScript with the form tool I’m using – how to write this a bit easier?

Some of the HTML form code also (build is in progress still):

<form>
**PAGE 1**
<div class="ee_list_item_label">
            <span class="input"><input type="radio" name="7" id="7_1" value="1" required="required"></span>
            <label class="ee_editable ee_answertext" for="7_1"><font>Improved Hair, Skin &amp; Nails</font>
        </label></div>
    </div><div class="option-wrapper">
        <div class="ee_list_item_label">
            <span class="input"><input type="radio" name="7" id="7_2" value="2" required="required"></span>
            <label class="ee_editable ee_answertext" for="7_2"><span>Bones &amp; Joint Support</span>
        </label></div>
    </div><div class="option-wrapper">
        <div class="ee_list_item_label">
            <span class="input"><input type="radio" name="7" id="7_3" value="3" required="required"></span>
            <label class="ee_editable ee_answertext" for="7_3"><span>Healthy Energy</span>
        </label></div>
    </div><div class="option-wrapper">
        <div class="ee_list_item_label">
            <span class="input"><input type="radio" name="7" id="7_4" value="4" required="required"></span>
            <label class="ee_editable ee_answertext" for="7_4"><span>Exercise Support</span>
        </label></div>
    </div><div class="option-wrapper">
        <div class="ee_list_item_label">
            <span class="input"><input type="radio" name="7" id="7_5" value="5" required="required"></span>
            <label class="ee_editable ee_answertext" for="7_5"><span>Anti-Aging Support</span>
        </label></div>
    </div><div class="option-wrapper">
        <div class="ee_list_item_label">
            <span class="input"><input type="radio" name="7" id="7_8" value="8" required="required"></span>
            <label class="ee_editable ee_answertext" for="7_8"><span>General Wellness</span>
        </label></div>

**PAGE 2**
 <div class="ee_list_item_label">
            <span class="input"><input type="radio" name="14" id="14_12" value="12" required="required"></span>
            <label class="ee_editable ee_answertext" for="14_12"><span>30 mins or more intense exercise 5-7 times a week</span>
        </label></div>
    </div><div class="option-wrapper">
        <div class="ee_list_item_label">
            <span class="input"><input type="radio" name="14" id="14_13" value="13" required="required"></span>
            <label class="ee_editable ee_answertext" for="14_13"><span>30 mins or more moderate exercise daily</span>
        </label></div>
    </div><div class="option-wrapper">
        <div class="ee_list_item_label">
            <span class="input"><input type="radio" name="14" id="14_14" value="14" required="required"></span>
            <label class="ee_editable ee_answertext" for="14_14"><span>30 mins exercise 3-4 times a week</span>
        </label></div>
    </div><div class="option-wrapper">
        <div class="ee_list_item_label">
            <span class="input"><input type="radio" name="14" id="14_15" value="15" required="required"></span>
            <label class="ee_editable ee_answertext" for="14_15"><span>Daily walking</span>
        </label></div>
    </div><div class="option-wrapper">
        <div class="ee_list_item_label">
            <span class="input"><input type="radio" name="14" id="14_16" value="16" required="required"></span>
            <label class="ee_editable ee_answertext" for="14_16"><span>Little to no exercise</span>
        </label></div>
</form>

Sending multiple files from axios to nestjs (Multipart: Boundary not found)

I’m attempting to send multiple files in a multipart/form-data. This form will have one required file imagem and on required data which will be a json. I has a optional anexos which is an array of images. I’m gettings an error when attempting to send only an image from axios to my nestjs backed.

From the app side I receive:

{"error": "Bad Request", "message": "Multipart: Boundary not found", "statusCode": 400}

If I remove multipart/form-data, I get an error in nestjs:

[Nest] 29165  - 01/21/2025, 10:34:06 AM   ERROR [ExceptionsHandler] Cannot read properties of undefined (reading 'imagem')
TypeError: Cannot read properties of undefined (reading 'imagem')
    at ReceitasController.create

React Native axios logic:

static async create(file: any, receita: Receita): Promise<Receita> {
    const formData = new FormData()

    formData.append('imagem', {
      type: file.mime,
      name: file.fileName,
      uri:
        Platform.OS === 'android' ? file.uri : file.uri.replace('file://', ''),
    })

    formData.append('data', JSON.stringify(receita))

    return http.post('/receitas', formData, {
      headers: { 'Content-Type': 'multipart/form-data' },
    })
  }

Nest.js:

@Post()
@UseInterceptors(
  FileFieldsInterceptor([
    { name: 'imagem', maxCount: 1 },
    { name: 'anexos', maxCount: 5 },
  ]),
)
async create(
  @UploadedFiles()
  files: { imagem: Express.Multer.File[]; anexos?: Express.Multer.File[] },
  @Body() body: { data: string },
  @CurrentUser() user: TokenPayload,
) {
  const file = files.imagem[0]

  const b = JSON.parse(body.data)

  const rc = createReceitaSchema.parse(b)

  return await this.receitasService.create(
    file,
    rc,
    user.sub,
    files.anexos,
  )
}

The http is:

const http = axios.create({
  baseURL: 'http://192.168.1.45:3333/',
  withCredentials: true,
}) as APIInstaceProps

This works fine on my postman:

enter image description here

Android WebView – Origin Private File System – An attempt was made to break through the security policy of the user agent

We have an Android app using WebView to display part of the user interface. In app telemetry we see that on some user device the following exception is thrown:

SecurityError: Failed to execute ‘getFileHandle’ on
‘FileSystemDirectoryHandle’: An attempt was made to break through the
security policy of the user agent.

Here is the code causing the exception:

const root = await navigator.storage.getDirectory();
const fileHandle = await root.getFileHandle(name, {create: true});

I would expect the exception to be thrown in a browser with strict privacy controls. However, the problem appears in a WebView component. What’s more puzzling the problem appears only on some devices. For example, I’m not able to reproduce the problem on any of our test smartphones.

The OPFS API is being used in a secure context (HTTPS page).

Most often the exception is thrown in WebView version 132, running on Android 14.

What may cause the WebView to limit origin private file system API use?

Oracle APEX dynamically set item value on a datepicker

I am working on an Oracle APEX application where I need to dynamically format a user’s input in a Date Picker item. The desired behavior is:

When the user types 20022025 (for example), the item should automatically reformat it to 20.02.2025 (i.e., DD.MM.YYYY) upon losing focus.
If a date is selected using the date picker, the value should remain unchanged.
The format mask for the Date Picker is already set to DD.MM.YYYY.

What I have tried:

//PL/SQL Dynamic Action
declare
begin
  SELECT TO_CHAR(TO_DATE(:BIRTH_DATE, 'DDMMYYYY'), 'DD.MM.YYYY') 
    INTO :BIRTH_DATE
    FROM DUAL;
end;

//PL/SQL with Conditional Formatting
declare
  v_formatted_date varchar2(10);
begin
  if regexp_like(:BIRTH_DATE, '^d{8}$') then
    v_formatted_date := substr(:BIRTH_DATE, 1, 2) || '.' || 
                        substr(:BIRTH_DATE, 3, 2) || '.' || 
                        substr(:BIRTH_DATE, 5, 4);
  end if;
  :BIRTH_DATE:= v_formatted_date;
end;

//JavaScript Dynamic Action
var pid = $(this.triggeringElement).attr("id");
var value = apex.item(pid).getValue(); 
console.log("value:", value);

if (/^d{8}$/.test(value)) {
  var formattedValue = value.substring(0, 2) + '.' + 
                       value.substring(2, 4) + '.' + 
                       value.substring(4);
  console.log("Formatted value:", formattedValue);
  apex.item(pid).setValue(formattedValue);
}

//Set Value Action with PL/SQL Function Body
declare
begin
  IF REGEXP_LIKE(:BIRTH_DATE, '^d{8}$') THEN
    SELECT TO_CHAR(TO_DATE(:BIRTH_DATE, 'DDMMYYYY'), 'DD.MM.YYYY') 
      INTO :BIRTH_DATE
      FROM DUAL;
  end if;
end;

bug in chromium 132 when iterating over very large objects (1 million keys)

It seems there is a bug in chrome 132 with very large objects (1 million keys).

  • chrome 132.0.6834.84
  • V8 13.2.152.27

Firefox works fine

Here is a minimal repro.

  • For some reason, the first time chrome loads the page, there are only 2 errors.
  • After I refresh, there are 3 errors.
<html>
  <script>
    const count = 1e6; // 1e5 => OK, 1e6 => ERROR

    const big = {};
    for (let i = 0; i < count; i++) {
      big[`key_${i}`] = { a: i, b: i * 2, c: i * 3 };
    }

    console.log('begin');

    try {
      for (let k in big) {
        if (big[k] === undefined) {
          throw new Error();
        }
      }
    } catch (e) {
      console.log(`for (k in big) => ERROR with count = ${count}`);
    }

    try {
      const keys = Object.keys(big);
      for (let k of keys) {
        if (big[k] === undefined) {
          throw new Error();
        }
      }
    } catch (e) {
      console.log(`Object.keys(big) => ERROR with count = ${count}`);
    }

    
    try {
      const keys = Object.getOwnPropertyNames(big);
      for (let k of keys) {
        if (big[k] === undefined) {
          throw new Error();
        }
      }
    } catch (e) {
      console.log(`Object.getOwnPropertyNames(big) => ERROR with count = ${count}`);
    }

    console.log('done');
  </script>
</html>

Is there a way to proxy a streamed answer in AWS Lambda js?

I’m using loopback 4 as backend framework and I deploy my APIs on AWS lambda using Serverless framework (followed this guide: https://medium.com/@hitesh.gupta/running-loopback-v4-on-aws-lambda-56064a97b5c3). I want to make a Bedrock API and stream model response (as a GPT like) but I can’t manage to stream my response as it was stuck in buffering mode.

serverless.yml

functions:
  stream:
    handler: lambda.handler
    timeout: 60
    url:
      cors: true
      invokeMode: RESPONSE_STREAM
  app:
    handler: lambda.handler # reference the file and exported method
    events: # events trigger lambda functions
      - http: # this is an API Gateway HTTP event trigger
          path: /
          method: ANY
          cors: true
      - http: # all routes get proxied to the Express router
          path: /{proxy+}
          method: ANY
          cors: true

lambda.js

const awsServerlessExpress = require('aws-serverless-express');
const AWS = require('aws-sdk');
const application = require('./dist');
const app = new application.StudyApplication({
  rest: {
    openApiSpec: {
      setServersFromRequest: true,
    },
  },
});
const server = awsServerlessExpress.createServer(app.restServer.requestHandler);
exports.handler = async (event, context) => {
  console.log('Event: ', event);

  await app.boot();
  return awsServerlessExpress.proxy(server, event, context, 'PROMISE').promise;
};

my test controller:

import {inject} from '@loopback/core';
import {post, Response, RestBindings} from '@loopback/rest';
import {Readable} from 'stream';
// import {inject} from '@loopback/core';
export class PromptController {
  constructor() {}
  @post('/prompt', {
    responses: {
      '200': {
        description: 'Stream fixed text in chunks',
        content: {
          'text/event-stream': {},
        },
      },
    },
  })
  async streamFixedText(
    @inject(RestBindings.Http.RESPONSE) response: Response,
  ): Promise<void> {
    response.set('Content-Type', 'text/event-stream');
    response.set('Connection', 'keep-alive');
    const chunks = [
      'This is the first chunk of the text.',
      ' Here comes the second chunk.',
      ' And finally, the last chunk.',
    ];

    const readable = new Readable({
      read() {
        let index = 0;

        const intervalId = setInterval(() => {
          if (index < chunks.length) {
            this.push(`data: ${chunks[index]}nn`);
            index++;
          } else {
            this.push(null);
            clearInterval(intervalId);
          }
        }, 1000);
      },
    });

    response.on('close', () => {
      readable.destroy();
    });

    readable.pipe(response);
  }
}

I don’t know if there is a way to make it works.

Thanks a lot for taking the time to read my issue.
ITZouzouille

tried using streamifyResponse lib but it seems that the event object when requesting a lambda url isn’t the same as when we pass through API Gateway.

How to implement illustrator’s ability to identify closed paths with svg

I am making a website that helps making kufi typography art. Kufi is basically based on grids. it varies by the way the grid is constructed.

regular square grid circular grid

before, I used to make these grids using python’s turtle library. but now I will make it 100% frontend which means i need to handle the graphics using SVG and javascript.
the drawing itself isn’t the problem. the problem is that the drawing isn’t based on paths. it’s based on circles, rectangles and lines.
I need to be able to identify each closed region like illustrator’s live paint bucket does.
illustrator’s live paint bucket
so that it basically looks like pixel art apps where you can hover your mouse on any closed region and it detects it and can color it individually.
A sample of the grids written in svg:

<svg width="1000" height="1000"><circle r="300" cx="500" cy="500" fill="none" stroke="black" stroke-width="0.5"></circle><circle r="290" cx="500" cy="500" fill="none" stroke="black" stroke-width="0.5"></circle><circle r="270" cx="500" cy="500" fill="none" stroke="black" stroke-width="0.5"></circle><circle r="260" cx="500" cy="500" fill="none" stroke="black" stroke-width="0.5"></circle><circle r="240" cx="500" cy="500" fill="none" stroke="black" stroke-width="0.5"></circle><circle r="230" cx="500" cy="500" fill="none" stroke="black" stroke-width="0.5"></circle><circle r="210" cx="500" cy="500" fill="none" stroke="black" stroke-width="0.5"></circle><circle r="200" cx="500" cy="500" fill="none" stroke="black" stroke-width="0.5"></circle><circle r="180" cx="500" cy="500" fill="none" stroke="black" stroke-width="0.5"></circle><circle r="170" cx="500" cy="500" fill="none" stroke="black" stroke-width="0.5"></circle><circle r="150" cx="500" cy="500" fill="none" stroke="black" stroke-width="0.5"></circle><circle r="140" cx="500" cy="500" fill="none" stroke="black" stroke-width="0.5"></circle><circle r="120" cx="500" cy="500" fill="none" stroke="black" stroke-width="0.5"></circle><circle r="110" cx="500" cy="500" fill="none" stroke="black" stroke-width="0.5"></circle><circle r="90" cx="500" cy="500" fill="none" stroke="black" stroke-width="0.5"></circle><circle r="80" cx="500" cy="500" fill="none" stroke="black" stroke-width="0.5"></circle><circle r="60" cx="500" cy="500" fill="none" stroke="black" stroke-width="0.5"></circle><circle r="50" cx="500" cy="500" fill="none" stroke="black" stroke-width="0.5"></circle><circle r="30" cx="500" cy="500" fill="none" stroke="black" stroke-width="0.5"></circle><circle r="20" cx="500" cy="500" fill="none" stroke="black" stroke-width="0.5"></circle><rect x="495" y="200" width="10" height="600" transform="rotate(0, 500, 500)" fill="none" stroke="black" stroke-width="0.5"></rect><rect x="495" y="200" width="10" height="600" transform="rotate(18, 500, 500)" fill="none" stroke="black" stroke-width="0.5"></rect><rect x="495" y="200" width="10" height="600" transform="rotate(36, 500, 500)" fill="none" stroke="black" stroke-width="0.5"></rect><rect x="495" y="200" width="10" height="600" transform="rotate(54, 500, 500)" fill="none" stroke="black" stroke-width="0.5"></rect><rect x="495" y="200" width="10" height="600" transform="rotate(72, 500, 500)" fill="none" stroke="black" stroke-width="0.5"></rect><rect x="495" y="200" width="10" height="600" transform="rotate(90, 500, 500)" fill="none" stroke="black" stroke-width="0.5"></rect><rect x="495" y="200" width="10" height="600" transform="rotate(108, 500, 500)" fill="none" stroke="black" stroke-width="0.5"></rect><rect x="495" y="200" width="10" height="600" transform="rotate(126, 500, 500)" fill="none" stroke="black" stroke-width="0.5"></rect><rect x="495" y="200" width="10" height="600" transform="rotate(144, 500, 500)" fill="none" stroke="black" stroke-width="0.5"></rect><rect x="495" y="200" width="10" height="600" transform="rotate(162, 500, 500)" fill="none" stroke="black" stroke-width="0.5"></rect></svg>

I tried to use intersections libraries, but I couldn’t find a way to know which intersection is which. or how to make separate paths of each closed region

The modification of the browser’s mouse cursor style becomes invalid after the browser loses focus

I have a requirement to change the browser’s mouse cursor style dynamically to achieve a mouse animation effect. To simplify the content for discussion, it can be represented by the following code:

const cursorTypes = ["default", "pointer", "text", "move", "help", "progress", "crosshair", "not-allowed", "zoom-in", "zoom-out", "grab", "grabbing"];
let cIndex = 0;

setInterval(() => {
  console.log(cIndex);
  document.body.style.cursor = cursorTypes[cIndex];
  cIndex++;
  if (cIndex >= cursorTypes.length) {
    cIndex = 0;
  }
}, 500);

The problem is that when the browser loses focus, although the setInterval function continues to run normally, the mouse cursor style does not change. However, when the mouse is continuously moved within the browser viewport, the styles that are not rendered will be applied sequentially at the set interval. Once the mouse stops moving, the rendering stops immediately until the browser regains focus. Why is this happening? I suspect this might be related to the browser’s rendering buffer.

I have tried using requestAnimationFrame function for animation updates:

let frameIndex = 0;
let step = (timestamp, elapsed) => {
  if (elapsed > 1000 / frameRate) { 
    document.body.style.cursor = cursorTypes[cIndex]; 
    frameIndex++;
    if (frameIndex >= frameURLs.length) {
      frameIndex = 0;
    }
    elapsed = 0;
  }
  console.log(frameIndex);
  window.requestAnimationFrame((_timestamp) =>
    step(_timestamp, elapsed + _timestamp - timestamp)
  );
};
window.requestAnimationFrame((timestamp) => step(timestamp, 0));

Or using the CSS animation property:

@keyframes cursor-animation-keyframes{
  0% { cursor: default; } 
  6% { cursor: pointer; } 
  ... 
}

.cursor-animation { 
  animation: cursor-animation-keyframes 1866ms step-end infinite; 
}

But the results are the same with no difference.
What should I do to ensure that the mouse cursor style modification still works after the browser loses focus?