fetched video data using byte range http request not playing in html5 video element

I have a node server which serves byte range request from browser. The browser sends the request. I get 206 successful byte-range request status code. But the fetched segment is not playing in html5 video element. I am using firefox.

Error : No video with supported format or mime type found


async function fetchRange(url, startByte, endByte) {
    try {
         const response = await fetch(url, {
                             headers: {'Range': `bytes=${startByte}-${endByte}`}
                         });
                 
         const data = await response.blob(); 
         console.log(`Fetched ${data.size} bytes from ${startByte} to ${endByte}.`);
         return data;

    } catch (error) {
        console.error('Error fetching range:', error);
    }
}

// Example usage:
const fileUrl = 'http://localhost:8000/video'; // Replace with your file URL
const start = 0;
const end = 1023; // Requesting the first 1024 bytes (0-1023)

fetchRange(fileUrl, start, end)
.then(data => {
          if (data) {
             // Process the received data (e.g., display it, save it)
             console.log('Received data:', data);

             let f = new File([data],'haah',{ type: "video/mp4" })
             document.getElementById('vid2').src = URL.createObjectURL(f)
          }
});

html:

<video controls width="350" id="vid2" >
     <source src='' type="video/mp4" >
          Sorry, not supported by browser
     </source>
</video>

node server code :

if(req.url === '/video' && req.method === 'GET'){
        console.log('video get')
        //var filePath = 'audiofile2.flac';
        var filePath = "output_ah.mp4"
         var stat = fs.statSync(filePath);
         var total = stat.size;
         console.log(req.headers.range)
         var range = req.headers.range;
         var parts = range.replace(/bytes=/, "").split("-");
         var partialstart = parts[0];
         var partialend = parts[1];
         var start = parseInt(partialstart, 10);
         var end = partialend ? parseInt(partialend, 10) : total-1;
         //console.log(start,end)
         var chunksize = (end-start)+1;
         var file = fs.createReadStream(filePath, {start: start, end: end});
         res.writeHead(206, {
             'Content-Range': 'bytes ' + start + '-' + end + '/' + total,
             // 'Content-Length' : total,
             'Accept-Ranges': 'bytes', 
             'Content-Length': chunksize,
             'Content-Type': 'video/mp4'
             // 'ETag' : '"'+"abcd-efgh"+'"'
         });
         file.pipe(res)
     }

I got this error in React – “Uncaught TypeError: Cannot read properties of undefined (reading ‘match’)” can someone help me please?

While creating a video game search app I ran into a problem, I’m using a separate API and when you click on a searched game card it then should take you to a new page showing games images and a brief info about the game. For some reason I get this this error “Uncaught TypeError: Cannot read properties of undefined (reading ‘match’)” for my GameDetails component (at createParagraphs (GameDetails.jsx:8:33) to be exact. It shows an error near a regex conversion where I try to convert the long text I get from API into 3 paragraph text. I think I wrote the regex correctly.

I searched the internet for answers but I didn’t get one or I just don’t understand it with different examples since I’m still a noob at coding 😀 I’ll leave the code to my GameDetails.jsx component below if you have more questions ask away, I really wanna get to the bottom of this, solving problems is like defeating a hard Souls-like boss, it’s addicting and releaving 😀

import { useEffect, useState } from "react";
import useFetch from "../hooks/useFetch";
import { fetchGameData } from "../api";
import ScreenshotCarousel from "./ScreenshotCarousel";
import Spinner from "./Spinner";

function createParagraphs(inputString) {
  const sentences = inputString.match(/[^.!?]+[.!?]+/g) || [];

  const paragraphs = [];

  for (let i = 0; i < sentences.length; i += 3) {
    const paragraph = sentences
      .slice(i, i + 3)
      .join(" ")
      .trim();
    paragraphs.push(paragraph);
  }

  return paragraphs;
}

export default function GameDetails({ currentGame, goBack }) {
  const [description, setDescription] = useState([]);

  const { data, loading, fetchData, error, reset } = useFetch(() =>
    fetchGameData({ gameSlug: currentGame.slug })
  );

  useEffect(() => {
    (async () => {
      await fetchData();
    })();
  }, []);

  useEffect(() => {
    if (data) {
      const rawDescription = data.description_raw;
      const paragraphs = createParagraphs(rawDescription);

      setDescription(paragraphs);
    }
  }, [data]);

  return (
    <section>
      <button className="main-button flex" onClick={goBack}>
        <img src="./back-arrow.svg" /> <span className="mx-2">Go Back</span>
      </button>

      {loading ? (
        <div className="flex justify-center mt-4">
          <Spinner />
        </div>
      ) : (
        <div className="mt-4">
          <div className="w-full relative">
            <div className="absolute inset-0 bg-gradient-to-b from-black via-transparent to-transparent opacity-80"></div>
            <h1 className="text-gray-200 text-2xl absolute top-5 left-5">
              {currentGame.name}
            </h1>
            <img
              className="w-full h-40 object-cover rounded-md"
              src={currentGame.background_image}
            />
          </div>
          <div className="">
            {data && (
              <div className="text-gray-300">
                {description.map((paragraph, index) => (
                  <p className="mt-2" key={index}>
                    {paragraph}
                  </p>
                ))}
              </div>
            )}

            <div className="w-full flex flex-col items-center p-4 h-96">
              {currentGame.short_screenshots.length !== 0 && (
                <ScreenshotCarousel
                  screenshots={currentGame.short_screenshots.slice(0)} 
                />
              )}
            </div>

            <div className="grid grid-cols-2 py-4">
              <div className="flex flex-col">
                <h2 className="text-gray-300 text-xl">Genres</h2>
                <ul className="flex flex-wrap gap-2 py-2">
                  {currentGame.genres.map((genre) => (
                    <li className="genre-pill" key={genre.name}>
                      {genre.name}
                    </li>
                  ))}
                </ul>
                <h2 className="text-gray-300 text-xl">Platforms</h2>
                <ul className="flex flex-wrap gap-2 py-2">
                  {currentGame.platforms.map((platform) => (
                    <li key={platform.platform.name} className="platform-pill">
                      {platform.platform.name}
                    </li>
                  ))}
                </ul>
              </div>
              <div className="flex justify-center items-center">
                <button
                  className="main-button flex items-center"
                  onClick={() =>
                    window.open(
                      `https://google.com/search?q=where+to+buy+${currentGame.name}`,
                      "_blank"
                    )
                  }
                >
                  <span className="ml-4 mr-2">Purchase</span>
                  <img src="./shopping-cart.svg" className="size-6 mr-4" />
                </button>
              </div>
            </div>
          </div>
        </div>
      )}
    </section>
  );
}

I tried checking for errors in my syntax or my regex writing but I couldn’t find anything. I’ve tried googling for solutions of this problem but nothing came up that was similar to my case :/

How would someone perform filtering, paging, and other OData capabilities on in-memory data in Node.js?

I have a requirement to implement OData endpoints in Node.js. In my scenario, the underlying data will be sourced from API calls rather than a direct database connection, essentially returning large payloads of data to the function in which the OData capabilities would, unfortunately, need to operate off of in-memory data (no database pushdown, unfortunately.)

What would the code look like to accomplish something like this?

swiper.js w/ coverflow causing ‘mouse’ problems?

sceenshot

<html>
    <head>
        <style>
            .swiper-slide {
                width: 75px !important;
                cursor: no-drop;
            }
        </style>
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@12/swiper-bundle.min.css" />
        <script src="https://cdn.jsdelivr.net/npm/swiper@12/swiper-bundle.min.js"></script>
    </head>

    <body>
        <div class="swiper photoContainer swiper-horizontal" style="height: 75px; width: 300px">
            <div class="swiper-wrapper">
                <div class="swiper-slide">
                    <img src="graphics/advFeature.png" />
                </div>
                <div class="swiper-slide">
                    <img src="graphics/advFeature.png" />
                </div>
                <div class="swiper-slide">
                    <img src="graphics/advFeature.png" />
                </div>
                <div class="swiper-slide">
                    <img src="graphics/advFeature.png" />
                </div>
                <div class="swiper-slide">
                    <img src="graphics/advFeature.png" />
                </div>
                <div class="swiper-slide">
                    <img src="graphics/advFeature.png" />
                </div>
            </div>
        </div>

        <script>
            photoSwiper = new Swiper(".photoContainer", {
                direction: "horizontal",
                nested: true,
                slidesPerView: "auto",
                centeredSlides: true,
                effect: "coverflow",
                coverflowEffect: {
                    rotate: 20,
                    slideShadows: true,
                    depth: 250
                    //stretch: 0,
                },
                spaceBetween: 1
            });
        </script>
    </body>
</html>

with the code above, recognition of a slide in css (or for a click event etc) is sporadic. i had working code in an older version where i could hover or click on ANY visible portion of a slide, even partly covered and far to one side, and all recognition of the correct slide worked as expected. now some (most) seem to be ignored, and which ones work change as you swipe the content. even the active slide sometimes won’t be ‘noticed’.
i have tried all kinds of suggestions, like z-indexing, on:click event in the swiper init, slidetoactive etc:false.

note that if i take out coverflow works fine immediately!

in the screenshot, only the third slide, the right half of the fifth, and the sixth one seem to be recognized; cursor changes.

it’s as if there is a disconnect between normal browser/click/touch/mouse registration and the slides now…

How do I use localStorage to save a shopping cart in JavaScript? [duplicate]

I’m building a simple shopping cart website as a beginner project, and I want to use localStorage so that the user’s cart items are not lost when the page is refreshed.

So far, I understand how to add items to the cart in JavaScript, but I don’t know how to save them in localStorage and then load them back when the page reloads.
When I refresh the page, the cart data doesn’t load back properly. It just shows as [object Object] or a string instead of the actual array of items.
I tried writing some code before, but I don’t remember exactly how I did it since it didn’t work and I almost gave up. Now I want to learn the correct way to do it.

What I’m expecting:
• Save the cart (an array of items) into localStorage.
• Retrieve the cart correctly when the page reloads.
• Keep the items in the cart persistent across page refreshes.

How can I properly implement this with JavaScript?
what I’ve tried:

localStorage.setItem('panier', JSON.stringify(table[0].innerHTML));
localStorage.setItem('cout', cout_total.toString());
// Au chargement de la page, restaurer le panier
window.addEventListener('load', () => {
    const panierSauvegarde = JSON.parse(localStorage.getItem('panier'));
    const savedTotal = localStorage.getItem('cout_total');

    
});
function mettreAJourLocalStorage() {
    const lignes = table[0].querySelectorAll('tr');
    const panier = [];

    lignes.forEach(row => {
        const nom = row.querySelector('p')?.textContent;
        const prix = row.querySelector('#prix')?.textContent?.replace(' $', '');
        const unite = row.querySelector('#unite')?.textContent?.split(' x ')[0];
        if (nom && prix && unite) {
            panier.push({
                nom,
                prix: parseInt(prix),
                quantite: parseInt(unite),
            });
        }
    });

    localStorage.setItem('panier', JSON.stringify(panier));
    localStorage.setItem('cout_total', cout_total.toString());
}

Better way to override methods on an instance of a JavaScript class

In our JavaScript web app, we use a custom-made component framework. All of our components are defined as classes using the class syntax.

We can make child classes that inherit the parents, and they can override methods that call the parent method with the super keyword.

However, we very frequently want to create individual instances of a class and override methods on that one instance, without writing up the boilerplate to make a new class that only has one instance.

Here’s an example of how we do it:

class Component {
    constructor(){ }

    myMethod() {
        // Do stuff...
    }
}

class SelectBox extends Component {
    constructor(){ super(); }

    myMethod() {
        super.myMethod();
        // Do more stuff afterwards
    }
}

// This one is normal and doesn't need overrides
let mySelectBox = new SelectBox();

// These next 2 override the same method differently
let mySelectBox1 = new SelectBox();
mySelectBox1.myMethod = function() {
    this.__proto__.myMethod.call(this);
    // Do yet more stuff on this one instance
};

let mySelectBox2 = new SelectBox();
mySelectBox2.myMethod = function() {
    this.__proto__.myMethod.call(this);
    // Do some different stuff on this other instance
};

// Defining a new class for each instance would work, but it's less concise
class MySelectBox3 extends SelectBox {
    constructor() {
        super();
    }

    myMethod() {
        super.myMethod();
        // Do yet more stuff on this one instance
    }
}
let mySelectBox3 = new MySelectBox3();

Recently, our SonarQube instance has started warning us about the __proto__ property being deprecated. I’m aware of Object.getPrototypeOf(), but that appears to do the same thing but with words.

I’ve tried using super in mySelectBox1.myMethod() but apparently that only works inside the class syntax, because I get Uncaught SyntaxError: 'super' keyword unexpected here.

Is there a cleaner way to extend a class by overriding methods on a single instance of that class, without having to rely on the deprecated __proto__ property?

Alternatively, is there a concise way to make a class that has only a single instance without filling up our codebase with a lot of boilerplate?

Is it really safe to work with arrays inside setTimeout/event handlers?

I need to access the same array from main thread and multiple setTimeout/event handlers? May array operation interrupt another array operation when it is called from, setTimeout/event handler function?

In another words, is situation like this possible:

let a = [];

Main "thread" calls: a.push(5)

While a.push(5) is not finished, setTimeout/event handler called

handler calls a.push(4), interrupting it in the middle, while a.push(5) isn't finished
*some bad things and undefined behavior happen*

If it’s unsafe, please tell me how to do it in a safe way.

Apply css just to number and symbols

Apply css just to digits
How to apply CSS only to numbers in paragraph? (without <span>)
How to apply css to only numbers in a text inside/or any <p><p> element?

When we look at the other questions above, there are only numbers and the code I got from there is below, how can I add symbols(color:blue) in addition to numbers?

$('code').html(function(i, v){
    return v.replace(/(d+)/g, '<span class="number">$1</span>');
});
.number {
    color: red;
}
<script src= "https://code.jquery.com/jquery-2.2.4.min.js"></script>

<code>z*4rc9v3@P+D)m2k5y</code>

React19:Un return que no funciona? [closed]

Llevo todo el dia, y no puedo entender que es lo que esta pasando, pero parece que hay un return que me lleva al principio!!!!
He unido todo el codigo en la App

import { use } from "react";
import ErrorBoundary from "./error/ErrorBoundary";


function App() {
  return (
    <>
      <ErrorBoundary>
        {/* <Suspense fallback={<div>Cargando...</div>}> */}
        <DataDisplay />
        {/* </Suspense> */}
      </ErrorBoundary>
    </>
  );
}

function DataDisplay() {
  // Usamos 'use' para "esperar" la promesa de fetchData()

  console.log("iniciando:");
  const data = use(fetchData());
  console.log("data:", data);
  return (
    <div>
      <h1>{data.title}</h1>
      <p>{data.completed ? "Completado" : "Pendiente"}</p>
    </div>
  );
}

const fetchData = async () =>   {
    try {
        const response =  await fetch('https://jsonplaceholder.typicode.com/todos/1',{mode: 'cors' });
        console.log('Response received:', response);
        const data = await response.json();
        console.log('Data fetched successfully', data);
        
        **return data;**
    } catch (error) {
        console.error(error);
        throw error;
    }
     console.log('This will not run');
}
export default App;``` 

y esto es un trozo de los consoles; el return lo ha de ejecutar despues de *'Data fetched successfully'*. Por favor, darme alguna pista!!!!

App.tsx:36 Response received: Response {type: ‘cors’, url: ‘https://jsonplaceholder.typicode.com/todos/1’, redirected: false, status: 200, ok: true, …}
App.tsx:36 Response received: Response {type: ‘cors’, url: ‘https://jsonplaceholder.typicode.com/todos/1’, redirected: false, status: 200, ok: true, …}
App.tsx:38 Data fetched successfully {userId: 1, id: 1, title: ‘delectus aut autem’, completed: false}
App.tsx:38 Data fetched successfully {userId: 1, id: 1, title: ‘delectus aut autem’, completed: false}
App.tsx:22 iniciando:“`

Mixpanel JavaScript SDK cookies missing SameSite attribute – how to add SameSite=Lax?

A pen tester called out that my Mixpanel cookies (mp_*) are missing the SameSite attribute.

Current Setup

I’m using the Mixpanel JavaScript SDK with this configuration:

mixpanel.init(token, {
track_pageview: false,
debug: process.env.NODE_ENV !== “production”,
secure_cookie: true,
cross_subdomain_cookie: false,
cross_site_cookie: false
});

Problem

Despite trying various configuration options, the Mixpanel cookies are still being set without the SameSite attribute. Browser dev tools show:

  • ✅ Secure flag is present (due to secure_cookie: true)
  • ❌ SameSite attribute is missing
  • ❌ HttpOnly flag is missing

What I’ve Tried

  1. Configuration options – I’ve tried cross_site_cookie: false and cross_subdomain_cookie: false but these don’t seem to add SameSite attributes. I found cross_site_cookie on https://classic.yarnpkg.com/en/package/mixpanel-browser from a 2.35.0 (17 Mar 2020) release, but it’s not mentioned anywhere else and doesn’t seem to work.
  2. Custom cookie interceptor – I overrode document.cookie to intercept Mixpanel cookies and add SameSite, but this feels hacky and I’m not sure if it’s reliable.
//interceptor approach
const originalCookieDescriptor = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie');
Object.defineProperty(document, 'cookie', {
  set: function(cookieString) {
    if (cookieString && cookieString.includes('mp_')) {
      if (!/samesites*=/i.test(cookieString)) {
        cookieString += '; SameSite=Lax';
      }
    }
    originalCookieDescriptor.set.call(this, cookieString);
  }
});

Questions

  1. Does Mixpanel JavaScript SDK have native support for SameSite cookie attributes? I can’t find this in their official documentation.
  2. What’s the recommended way to ensure Mixpanel cookies comply with modern browser security requirements?
  3. Is there a reliable way to add SameSite attributes to third-party library cookies like Mixpanel’s?

Environment

  • Mixpanel JavaScript SDK (latest version via CDN)

Plasma UI Causes Blank Screen

Environment

  • React 18
  • Vite 7.1.5
  • Plasma UI (latest via npm)
  • macOS (local dev)
  • Fresh project scaffolded with
npm create vite@latest

What I Expected

I expected Plasma UI’s <Input /> component to render inside a simple form, styled and functional, as long as I wrapped the app with DeviceThemeProvider and used GlobalStyle and a valid theme.

What Actually Happened

As soon as I include <Input /> from @salutejs/plasma-ui, the entire UI goes blank. Nothing is visible in the browser — not even the surrounding JSX like <h1> and <div>. There’s no error in the browser console, no crash logs, and no failed network requests.

What Renders to the DOM

When <Input /> is present:

  • The root <div id="root"> is empty — no children are rendered

  • No HTML elements appear in the DOM inspector

  • No styles or layout are applied

  • Console logs inside the component do not appear

When I remove <Input /> and use a native <input> instead:

  • Everything renders correctly

  • JSX elements appear in the DOM

  • Console logs work

  • Form behaves as expected

Is It a Crash or a Visibility Issue?

It seems like a silent crash during render, not a CSS issue. The DOM is completely empty, and even fallback JSX like <h1> disappears. It’s not just that the input is invisible — the entire component tree fails to render.

Minimal Repro

.jsx code

import { Input } from '@salutejs/plasma-ui';
import { DeviceThemeProvider } from '@salutejs/plasma-ui/components/Device';
import { GlobalStyle } from '@salutejs/plasma-ui';
import { light } from '@salutejs/plasma-tokens/themes';

function App() {
  const [name, setName] = useState('');

  return (
    <DeviceThemeProvider theme={light}>
      <GlobalStyle />
      <Input
        placeholder="Your name"
        value={name}
        onChange={({ value }) => setName(value)}
      />
    </DeviceThemeProvider>
  );
}

What I’ve Tried

  • Wrapped the app in DeviceThemeProvider with light theme from @salutejs/plasma-tokens/themes
  • Added <GlobalStyle /> inside the provider
  • Imported @salutejs/plasma-core in main.jsx
  • Verified that onChange={({ value }) => setName(value)} is used correctly
  • Removed deprecated lightEva theme
  • Removed invalid import @salutejs/plasma-ui/styles (caused Vite build error)
  • Downgraded Plasma UI to 3.0.0 — same result
  • Replaced Plasma <Input /> with native <input> — works fine
  • No console errors, no crash logs, just a blank screen

Is there a way for JSDoc comments to be visible in HTML files?

I’m not sure how to get the code snippet for this question as I don’t know how to specify the filename of the JavaScript file, but here goes.

I have a JavaScript file, “scripts.js” that includes // @ts-check at the top of the file. JSDoc comments are included to indicate parameters for functions, variables and classes. This has been most helpful for development of scripts.js, ensuring that I have proper typing in JavaScript. However, when I use the scripts.js file in an HTML file, those JSDoc type hints are not visible. For example, in Visual Studio Code, the calling of footer(1); does not give me the following problem of:

Argument of type 'number' is not assignable to parameter of type 'string'.

I’ve added // @ts-check to the HTML file and imported footer but still no luck.

Is there any way to get those ts-check type hints show up in the HTML file?

// @ts-check
"use strict";

/**
 * @param {string} [email] - Email address. (optional)
 */
function footer(email = "")
{
    // main function

    {
        let html = "";

        html += `<footer>`;
        html += `<hr>`;
        html += `<address><a href="mailto:${email}">${email}</a></address>`;
        html += `</footer>`;

        document.body.insertAdjacentHTML("beforeend", html);
    }
}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <script src="scripts.js">
        // @ts-check
        import
        {
            footer
        } from "";
    </script>
    <title>JSDoc Test</title>
</head>

<body>

<h1>JSDoc Test</h1>

<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
    Maecenas porttitor congue massa. Fusce posuere, magna sed
    pulvinar ultricies, purus lectus malesuada libero, sit amet
    commodo magna eros quis urna.</p>

<script>
    footer("[email protected]");
    footer(1); // no error here but ts-check should complain because the param is not a string
</script>

</body>
</html>

Holberton checker fails “thumbnailElement is declared and assigned by ID” even though code uses document.getElementById

I’m working through a Holberton School web project.
In behavior.js I need to toggle a thumbnail’s size when it’s clicked.
The task says:

Modify the click event in behavior.js to include an if…else statement.

My HTML contains the image:

<img src="https://via.placeholder.com/800"
     id="smart_thumbnail"
     class="small"
     alt="Thumbnail">

My behavior.js currently looks like this:

    // I first wrote this (step 1):
thumbnailElement.addEventListener("click", function() {
    thumbnailElement.className =
        (thumbnailElement.className === "small") ? "" : "small";
});

// Then I added the required if...else (step 2):
var thumbnailElement = document.getElementById("smart_thumbnail");
thumbnailElement.addEventListener("click", function() {
    if (thumbnailElement.className === "small") {
        thumbnailElement.className = "";
    } else {
        thumbnailElement.className = "small";
    }
});

But when I run the automated checker I keep failing Test #1: “thumbnailElement is declared and assigned by ID.”
Tests #2 and #3 (toggle logic and class switching) pass.

I’ve confirmed:

The HTML ID is smart_thumbnail and matches getElementById.

behavior.js is loaded at the bottom of the HTML before .

Why does the checker still think thumbnailElement is not “declared and assigned by ID”?
Is it because I have two event listeners or because of the order of the code?
What’s the correct way to satisfy this test?

(Holberton project context, but the underlying issue is JavaScript DOM usage and linter/checker expectations.)

How to reset lasso selection across multiple plots to avoid accumulation?

Ah, and is there any hack or workaround on the latest version to reset the selection? Maybe simulating the double click event on an empty area of the plot. This is what I want to achieve:

plot images

I cannot find a way to do it with scattergl

This is what I’m trying, even in the version 2.12.0 with no luck

  await Plotly.relayout(plotDiv, {selections: []});
  await Plotly.restyle(plotDiv, {selectedpoints: [null]}, [lastSelectionSource]);

In this script I am using this instruction to trigger the repainting. But I get the same resulta than with relayout and restyle.

await Plotly.react(plotDiv, traces, layout);

The first time I use the lasso tool to make a selection, the drawn lasso remains visible, and the next selection in other plot doesn’t work properly. It gets added to the selectedIndices instead of replacing the current selection.

After that, if I select points in another plot, the selection works as expected.

However, when I make a new selection in the same plot, the lasso drawing appears again (which is normal behavior), but this causes the next selection in another plot to be aggregated with the previous selectedIndices, instead of overriding them.

I’ve attached a GIF that illustrates this behavior.

Do you know a more reliable way to implement this so that selections always replace the previous ones rather than accumulate?

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Plotly 3.1.0 Grid Plot - ScatterGL</title>
    <script src="https://cdn.plot.ly/plotly-3.1.0.min.js"></script>
    <style>
      body {margin:0; font-family:'Inter', sans-serif; background-color:#f5f5f5; height:100vh;}
      .plot-container {width:100vw; height:100vh; background:white; overflow:hidden;}
    </style>
  </head>
  <body>
    <div id="plotly-plot" class="plot-container"></div>
    <script>
      function generateRandom(count){
          return Array.from({length:count},()=>Math.floor(Math.random()*100)+1);
      }

      const data = {
          x: generateRandom(100),
          y: generateRandom(100),
          x2: generateRandom(100),
          y2: generateRandom(100),
          x3: generateRandom(100),
          y3: generateRandom(100),
          x4: generateRandom(100),
          y4: generateRandom(100)
      };

      let traces = [
          {x:data.x, y:data.y, mode:'markers', type:'scattergl', marker:{size:7,color:'blue',opacity:0.7}, selected:{marker:{size:10,color:'red',opacity:1}}, unselected:{marker:{opacity:0.2}}, xaxis:'x1', yaxis:'y1'},
          {x:data.x2, y:data.y2, mode:'markers', type:'scattergl', marker:{size:7,color:'green',opacity:0.7}, selected:{marker:{size:10,color:'red',opacity:1}}, unselected:{marker:{opacity:0.2}}, xaxis:'x2', yaxis:'y2'},
          {x:data.x3, y:data.y3, mode:'markers', type:'scattergl', marker:{size:7,color:'red',opacity:0.7}, selected:{marker:{size:10,color:'red',opacity:1}}, unselected:{marker:{opacity:0.2}}, xaxis:'x3', yaxis:'y3'},
          {x:data.x4, y:data.y4, mode:'markers', type:'scattergl', marker:{size:7,color:'purple',opacity:0.7}, selected:{marker:{size:10,color:'red',opacity:1}}, unselected:{marker:{opacity:0.2}}, xaxis:'x4', yaxis:'y4'}
      ];

      const plotDiv = document.getElementById('plotly-plot');

      let layout = {
          title:'Plotly 3.1.0 Grid Plot - ScatterGL',
          autosize:true,
          showlegend:false,
          grid:{rows:2, columns:2, pattern:'independent'},
          xaxis1:{title:'X1'}, yaxis1:{title:'Y1'},
          xaxis2:{title:'X2'}, yaxis2:{title:'Y2'},
          xaxis3:{title:'X3'}, yaxis3:{title:'Y3'},
          xaxis4:{title:'X4'}, yaxis4:{title:'Y4'},
          plot_bgcolor:'white',
          paper_bgcolor:'white',
          hovermode:'closest',
          margin:{t:40,b:40,l:30,r:30},
          selectdirection:'any',
          selectionrevision:0,
          dragmode:'select'
      };

      Plotly.newPlot(plotDiv, traces, layout, {displayModeBar:true, responsive:true, scrollZoom:true, displaylogo:false});

      let lastSelectionSource = null;

      plotDiv.on('plotly_selected', async function(eventData){
          if(!eventData || !eventData.points || eventData.points.length===0) return;

          const sourceTrace = eventData.points[0].curveNumber;
          const selectedIndices = Array.from(new Set(eventData.points.map(p=>p.pointIndex)));
          console.log(selectedIndices);

          if(lastSelectionSource !== null && lastSelectionSource !== sourceTrace){
              layout.selectionrevision++;
              traces[lastSelectionSource].selectedpoints = null;
              await Plotly.react(plotDiv, traces, layout);
          }

          traces.forEach(t => t.selectedpoints = selectedIndices);
          layout.selectionrevision++;
          await Plotly.react(plotDiv, traces, layout);

          lastSelectionSource = sourceTrace;
      });
    </script>
  </body>
</html>

Image

I have seen that there are some issues related to selected points in the latest versions of Plotly.js

This SO question is also related. Triggering a double click on an empty area would reset the selection. But I don’t know how to trigger that programmatically