How to plot one circle after another with some delay? - javascript

This is probably a really simple question but I can't seem to figure out how to plot one circle after another (sequentially, with some delay) using d3.js. The circles would then stay on the screen. I'm reading in data from a JSON file and it looks like this:
[{"r":1.2672526041666667,"cx":0,"cy":672.9303022519051,"fill":"rgb(252, 243, 228)"},{"r":1.2672526041666667,"cx":1,"cy":672.9303022519051,"fill":"rgb(252, 243, 228)"},{"r":1.2672526041666667,"cx":2,"cy":672.9303022519051,"fill":"rgb(252, 243, 228)"},{"r":1.2672526041666667,"cx":3,"cy":672.9303022519051,"fill":"rgb(252, 243, 228)"}.....]
and so forth. Json file located here: https://berkeley.box.com/s/4egj1ugr3jm2yp1htoyk8qmtv8avvosb
I've tried so many things!
I've tried using transition/duration but that doesn't seem to be working... I've tried a forEach loop to no avail... I've tried an .each loop as well. I've also tried both methods shown here: How do I loop through or enumerate a JavaScript object?
but I can't get either working. I've also tried looking at this solution:
How to draw circles at different times with D3js?
But I can't seem to plot anything after about 7 hours of trying different things. Here's my code...
<head>
<meta charset="utf-8" />
<title>Laughter Visualizer</title>
<style>
html, body, #svg {
background-color: #FFFFFF;
}
</style>
</head>
<body>
<audio id="audioElement" src="laugh_8.mp3" type="audio/mp3"></audio>
<div>
<button onclick="plotPoints(0, 0)">Draw Points ►</button>
</div>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
function plotPoints(p1, counter) {
d3.json("test2.json").then(function(data){
var svgHeight = window.innerHeight - 100;
var svgWidth = window.innerWidth - 10;
var svg = d3.select('body').append('svg')
.attr('width', svgWidth)
.attr('height', svgHeight);
svg.selectAll("circle")
.data(data)
.enter()
.append('circle')
.attr('r', function(d) { return d.r; })
.attr('cx', function(d) { return d.cx; })
.attr('cy', function(d) { return d.cy; })
.attr('fill', function(d) { return d.fill; });
})
}
</script>
</body>
</html>

Given your comment...
I'm looking for the circles to stay...
...the idiomatic D3 solution is using a simple transition, using the indices to set the delay. For instance, plotting one circle every 100 milliseconds:
.delay(function(_, i) {
return i * 100;
})
Regarding the transition itself, you could do it in several different ways, for instance increasing the radiuses. My solution here is just plotting everything and transition the opacity from 0 to 1.
I also created some scales, so your data values don't need to correspond to SVG coordinates:
const xDomain = d3.extent(data, function(d) {
return d.cx
});
const yDomain = d3.extent(data, function(d) {
return d.cy
});
const xScale = d3.scaleLinear()
.range([0, width])
.domain(xDomain);
const yScale = d3.scaleLinear()
.range([0, height])
.domain(yDomain);
Here is a demo using your data:
const data = [{
"r": 1.2672526041666667,
"cx": 0,
"cy": 672.9303022519051,
"fill": "rgb(252, 243, 228)"
}, {
"r": 1.2672526041666667,
"cx": 1,
"cy": 672.9303022519051,
"fill": "rgb(252, 243, 228)"
}, {
"r": 1.2672526041666667,
"cx": 2,
"cy": 672.9303022519051,
"fill": "rgb(252, 243, 228)"
}, {
"r": 1.2672526041666667,
"cx": 3,
"cy": 672.9303022519051,
"fill": "rgb(252, 243, 228)"
}, {
"r": 3.9895833333333335,
"cx": 4,
"cy": 661.4035574412531,
"fill": "rgb(247, 231, 205)"
}, {
"r": 3.9895833333333335,
"cx": 5,
"cy": 661.4035574412531,
"fill": "rgb(247, 231, 205)"
}, {
"r": 3.9895833333333335,
"cx": 6,
"cy": 661.4035574412531,
"fill": "rgb(247, 231, 205)"
}, {
"r": 5.073893229166667,
"cx": 7,
"cy": 660.5638673253352,
"fill": "rgb(244, 226, 195)"
}, {
"r": 5.073893229166667,
"cx": 8,
"cy": 660.5638673253352,
"fill": "rgb(244, 226, 195)"
}, {
"r": 5.6962890625,
"cx": 9,
"cy": 661.1542183362859,
"fill": "rgb(243, 223, 190)"
}, {
"r": 5.6962890625,
"cx": 10,
"cy": 661.1542183362859,
"fill": "rgb(243, 223, 190)"
}, {
"r": 5.6962890625,
"cx": 11,
"cy": 661.1542183362859,
"fill": "rgb(243, 223, 190)"
}, {
"r": 5.6962890625,
"cx": 12,
"cy": 661.1542183362859,
"fill": "rgb(243, 223, 190)"
}, {
"r": 6.125651041666667,
"cx": 13,
"cy": 661.8292769334325,
"fill": "rgb(242, 221, 186)"
}, {
"r": 6.125651041666667,
"cx": 14,
"cy": 661.8292769334325,
"fill": "rgb(242, 221, 186)"
}, {
"r": 6.422526041666667,
"cx": 15,
"cy": 661.5401588106098,
"fill": "rgb(241, 219, 184)"
}, {
"r": 6.422526041666667,
"cx": 16,
"cy": 661.5401588106098,
"fill": "rgb(241, 219, 184)"
}, {
"r": 6.422526041666667,
"cx": 17,
"cy": 661.5401588106098,
"fill": "rgb(241, 219, 184)"
}, {
"r": 6.422526041666667,
"cx": 18,
"cy": 661.5401588106098,
"fill": "rgb(241, 219, 184)"
}, {
"r": 6.770182291666667,
"cx": 19,
"cy": 658.8530307401353,
"fill": "rgb(241, 218, 181)"
}, {
"r": 6.770182291666667,
"cx": 20,
"cy": 658.8530307401353,
"fill": "rgb(241, 218, 181)"
}, {
"r": 6.770182291666667,
"cx": 21,
"cy": 658.8530307401353,
"fill": "rgb(241, 218, 181)"
}, {
"r": 7.0205078125,
"cx": 22,
"cy": 656.2237523376763,
"fill": "rgb(240, 217, 179)"
}, {
"r": 7.0205078125,
"cx": 23,
"cy": 656.2237523376763,
"fill": "rgb(240, 217, 179)"
}, {
"r": 7.0205078125,
"cx": 24,
"cy": 656.2237523376763,
"fill": "rgb(240, 217, 179)"
}, {
"r": 7.144205729166667,
"cx": 25,
"cy": 654.865008125636,
"fill": "rgb(240, 216, 178)"
}, {
"r": 7.144205729166667,
"cx": 26,
"cy": 654.865008125636,
"fill": "rgb(240, 216, 178)"
}, {
"r": 7.144205729166667,
"cx": 27,
"cy": 654.865008125636,
"fill": "rgb(240, 216, 178)"
}, {
"r": 7.349934895833333,
"cx": 28,
"cy": 653.0513751716197,
"fill": "rgb(239, 215, 176)"
}, {
"r": 7.349934895833333,
"cx": 29,
"cy": 653.0513751716197,
"fill": "rgb(239, 215, 176)"
}, {
"r": 7.7802734375,
"cx": 30,
"cy": 648.4655453746704,
"fill": "rgb(238, 213, 172)"
}, {
"r": 7.7802734375,
"cx": 31,
"cy": 648.4655453746704,
"fill": "rgb(238, 213, 172)"
}, {
"r": 7.7802734375,
"cx": 32,
"cy": 648.4655453746704,
"fill": "rgb(238, 213, 172)"
}, {
"r": 7.7802734375,
"cx": 33,
"cy": 648.4655453746704,
"fill": "rgb(238, 213, 172)"
}, {
"r": 8.924153645833334,
"cx": 34,
"cy": 646.4654507872818,
"fill": "rgb(236, 208, 162)"
}, {
"r": 8.924153645833334,
"cx": 35,
"cy": 646.4654507872818,
"fill": "rgb(236, 208, 162)"
}, {
"r": 8.924153645833334,
"cx": 36,
"cy": 646.4654507872818,
"fill": "rgb(236, 208, 162)"
}, {
"r": 8.924153645833334,
"cx": 37,
"cy": 646.4654507872818,
"fill": "rgb(236, 208, 162)"
}, {
"r": 10.550130208333334,
"cx": 38,
"cy": 642.0891082999074,
"fill": "rgb(233, 200, 148)"
}, {
"r": 10.550130208333334,
"cx": 39,
"cy": 642.0891082999074,
"fill": "rgb(233, 200, 148)"
}, {
"r": 10.550130208333334,
"cx": 40,
"cy": 642.0891082999074,
"fill": "rgb(233, 200, 148)"
}, {
"r": 11.846028645833334,
"cx": 41,
"cy": 638.9493098110339,
"fill": "rgb(230, 194, 137)"
}, {
"r": 11.846028645833334,
"cx": 42,
"cy": 638.9493098110339,
"fill": "rgb(230, 194, 137)"
}, {
"r": 13.046875,
"cx": 43,
"cy": 635.5438456420493,
"fill": "rgb(227, 189, 127)"
}, {
"r": 13.046875,
"cx": 44,
"cy": 635.5438456420493,
"fill": "rgb(227, 189, 127)"
}, {
"r": 13.046875,
"cx": 45,
"cy": 635.5438456420493,
"fill": "rgb(227, 189, 127)"
}, {
"r": 14.2236328125,
"cx": 46,
"cy": 631.6291795399932,
"fill": "rgb(225, 183, 117)"
}, {
"r": 14.2236328125,
"cx": 47,
"cy": 631.6291795399932,
"fill": "rgb(225, 183, 117)"
}, {
"r": 14.2236328125,
"cx": 48,
"cy": 631.6291795399932,
"fill": "rgb(225, 183, 117)"
}, {
"r": 15.346028645833334,
"cx": 49,
"cy": 626.1064208896337,
"fill": "rgb(222, 178, 107)"
}, {
"r": 15.346028645833334,
"cx": 50,
"cy": 626.1064208896337,
"fill": "rgb(222, 178, 107)"
}, {
"r": 15.346028645833334,
"cx": 51,
"cy": 626.1064208896337,
"fill": "rgb(222, 178, 107)"
}, {
"r": 16.297526041666668,
"cx": 52,
"cy": 620.3574348526613,
"fill": "rgb(220, 174, 99)"
}, {
"r": 16.297526041666668,
"cx": 53,
"cy": 620.3574348526613,
"fill": "rgb(220, 174, 99)"
}, {
"r": 16.297526041666668,
"cx": 54,
"cy": 620.3574348526613,
"fill": "rgb(220, 174, 99)"
}, {
"r": 16.778645833333332,
"cx": 55,
"cy": 617.0644627244038,
"fill": "rgb(219, 172, 95)"
}, {
"r": 16.778645833333332,
"cx": 56,
"cy": 617.0644627244038,
"fill": "rgb(219, 172, 95)"
}, {
"r": 16.778645833333332,
"cx": 57,
"cy": 617.0644627244038,
"fill": "rgb(219, 172, 95)"
}, {
"r": 16.83203125,
"cx": 58,
"cy": 614.5978314122896,
"fill": "rgb(219, 171, 94)"
}, {
"r": 16.83203125,
"cx": 59,
"cy": 614.5978314122896,
"fill": "rgb(219, 171, 94)"
}, {
"r": 16.83203125,
"cx": 60,
"cy": 614.5978314122896,
"fill": "rgb(219, 171, 94)"
}, {
"r": 17.060221354166668,
"cx": 61,
"cy": 609.8278349138509,
"fill": "rgb(219, 170, 92)"
}, {
"r": 17.060221354166668,
"cx": 62,
"cy": 609.8278349138509,
"fill": "rgb(219, 170, 92)"
}, {
"r": 17.060221354166668,
"cx": 63,
"cy": 609.8278349138509,
"fill": "rgb(219, 170, 92)"
}, {
"r": 17.060221354166668,
"cx": 64,
"cy": 609.8278349138509,
"fill": "rgb(219, 170, 92)"
}, {
"r": 17.533854166666668,
"cx": 65,
"cy": 602.747264716075,
"fill": "rgb(218, 168, 88)"
}, {
"r": 17.533854166666668,
"cx": 66,
"cy": 602.747264716075,
"fill": "rgb(218, 168, 88)"
}, {
"r": 17.533854166666668,
"cx": 67,
"cy": 602.747264716075,
"fill": "rgb(218, 168, 88)"
}, {
"r": 18.1669921875,
"cx": 68,
"cy": 596.8306485811727,
"fill": "rgb(216, 165, 83)"
}, {
"r": 18.1669921875,
"cx": 69,
"cy": 596.8306485811727,
"fill": "rgb(216, 165, 83)"
}, {
"r": 18.333984375,
"cx": 70,
"cy": 594.4961471538654,
"fill": "rgb(216, 165, 81)"
}, {
"r": 18.333984375,
"cx": 71,
"cy": 594.4961471538654,
"fill": "rgb(216, 165, 81)"
}, {
"r": 18.333984375,
"cx": 72,
"cy": 594.4961471538654,
"fill": "rgb(216, 165, 81)"
}, {
"r": 18.333984375,
"cx": 73,
"cy": 594.4961471538654,
"fill": "rgb(216, 165, 81)"
}, {
"r": 18.0771484375,
"cx": 74,
"cy": 594.6126027167029,
"fill": "rgb(217, 166, 83)"
}, {
"r": 18.0771484375,
"cx": 75,
"cy": 594.6126027167029,
"fill": "rgb(217, 166, 83)"
}, {
"r": 18.0771484375,
"cx": 76,
"cy": 594.6126027167029,
"fill": "rgb(217, 166, 83)"
}, {
"r": 17.9443359375,
"cx": 77,
"cy": 594.2603597883598,
"fill": "rgb(217, 166, 85)"
}, {
"r": 17.9443359375,
"cx": 78,
"cy": 594.2603597883598,
"fill": "rgb(217, 166, 85)"
}];
const width = 400,
height = 200;
const svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
const xDomain = d3.extent(data, function(d) {
return d.cx
});
const yDomain = d3.extent(data, function(d) {
return d.cy
});
const xScale = d3.scaleLinear()
.range([25, width -25])
.domain(xDomain);
const yScale = d3.scaleLinear()
.range([25, height - 25])
.domain(yDomain);
const circles = svg.selectAll(null)
.data(data)
.enter()
.append("circle")
.style("opacity", 0)
.attr("cx", function(d) {
return xScale(d.cx)
})
.attr("cy", function(d) {
return yScale(d.cy)
})
.attr("r", function(d) {
return d.r
})
.style("fill", function(d) {
return d.fill
})
.transition()
.delay(function(_, i) {
return i * 100;
})
.style("opacity", 1);
<script src="https://d3js.org/d3.v5.min.js"></script>

Here is a simple D3-based solution:
const svg = d3.select('svg')
const circleData = [
{id: 1, x: 100, y: 300, c: '#f00', r: 50, d: 500},
{id: 2, x: 250, y: 100, c: '#ff0', r: 90, d: 1000},
{id: 3, x: 300, y: 350, c: '#08f', r: 70, d: 1500},
]
svg.selectAll('circle')
.data(circleData, data => data.id)
.enter()
.append('circle')
.attr('cx', data => data.x)
.attr('cy', data => data.y)
.attr('r', data => data.r)
.style('fill', data => data.c)
.style('visibility', 'hidden')
.transition()
.delay(data => data.d)
.style('visibility', 'visible')
See the demo in a fiddle: https://jsfiddle.net/mrovinsky/pbgac6jw/

The problem is that you're handing over the complete data out of the json object to the selectAll() function of d3 to be drawn at once. Instead inside the callback function for d3.json("test2.json") assign the returned data to a global variable. Afterwards initiate a interval where you call svg.append('circle') - thus telling d3 to draw a circle after another.
<head>
<meta charset="utf-8" />
<title>Laughter Visualizer</title>
<style>
html, body, #svg {
background-color: #FFFFFF;
}
</style>
</head>
<body>
<audio id="audioElement" src="laugh_8.mp3" type="audio/mp3"></audio>
<div>
<button onclick="plotPoints(0, 0)">Draw Points ►</button>
</div>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
var svg;
var circleData;
var index=0;
var interval;
function update()
{
svg.append('circle')
.attr('r', circleData[index].r)
.attr('cx', circleData[index].cx)
.attr('cy', circleData[index].cy)
.attr('fill', circleData[index].fill);
if(index+1<circleData.length)
{
index++;
}
}
function plotPoints(p1, counter) {
d3.json("test2.json").then(function(data){
circleData=data;
var svgHeight = window.innerHeight - 100;
var svgWidth = window.innerWidth - 10;
svg = d3.select('body').append('svg')
.attr('width', svgWidth)
.attr('height', svgHeight);
interval=setInterval(update,100);
})
}
</script>
</body>
</html>

Related

Attempted import error: 'SupportedPackages' is not exported from '#tensorflow-models/facemesh' (imported as 'facemesh')

I am implementing Real-Time AI Face Landmark Detection
and I am getting this error if anyone has a fix then please help me my code snippet is below in reactjs and also i installed all dependencies too and imported in correct way but still this 'SupportedPackages' is not exported from '#tensorflow-models/facemesh' (imported as 'facemesh') import error is coming
App.js
import React, { useRef, useEffect } from "react";
import "./App.css";
import * as tf from "#tensorflow/tfjs";
import * as facemesh from "#tensorflow-models/face-landmarks-detection";
import Webcam from "react-webcam";
import { drawMesh } from "./utilities";
//setup references
function App() {
const webcamRef = useRef(null);
const canvasRef = useRef(null);
// Load posenet
const runFacemesh = async () => {
// OLD MODEL
// const net = await facemesh.load({
// inputResolution: { width: 640, height: 480 },
// scale: 0.8,
// });
// NEW MODEL
const net = await facemesh.load(facemesh.SupportedPackages.mediapipeFacemesh);
setInterval(() => {
detect(net);
}, 10);
};
const detect = async (net) => {
if (
typeof webcamRef.current !== "undefined" &&
webcamRef.current !== null &&
webcamRef.current.video.readyState === 4
) {
// Get Video Properties
const video = webcamRef.current.video;
const videoWidth = webcamRef.current.video.videoWidth;
const videoHeight = webcamRef.current.video.videoHeight;
// Set video width
webcamRef.current.video.width = videoWidth;
webcamRef.current.video.height = videoHeight;
// Set canvas width
canvasRef.current.width = videoWidth;
canvasRef.current.height = videoHeight;
// Make Detections
// OLD MODEL
// const face = await net.estimateFaces(video);
// NEW MODEL
const face = await net.estimateFaces({input:video});
console.log(face);
// Get canvas context
const ctx = canvasRef.current.getContext("2d");
requestAnimationFrame(()=>{drawMesh(face, ctx)});
}
};
useEffect(()=>{runFacemesh()}, []);
return (
<div className="App">
<header className="App-header">
<Webcam
ref={webcamRef}
style={{
position: "absolute",
marginLeft: "auto",
marginRight: "auto",
left: 0,
right: 0,
textAlign: "center",
zindex: 9,
width: 640,
height: 480,
}}
/>
<canvas
ref={canvasRef}
style={{
position: "absolute",
marginLeft: "auto",
marginRight: "auto",
left: 0,
right: 0,
textAlign: "center",
zindex: 9,
width: 640,
height: 480,
}}
/>
</header>
</div>
);
}
export default App;
all dependencies install stuff is done
and also below error
I got the same issue, and the problem was with the npm package version of #tensorflow-models/face-landmarks-detection & #tensorflow/tfjs
I had to modify the original code.
import { useRef, useEffect } from "react";
import * as facemesh from "#tensorflow-models/face-landmarks-detection";
import Webcam from "react-webcam";
import { drawMesh } from "./utilities";
import "./App.css";
function App() {
const webcamRef = useRef(null);
const canvasRef = useRef(null);
const runFaceMesh = async () => {
const model = facemesh.SupportedModels.MediaPipeFaceMesh;
const detectorConfig = {
runtime: "tfjs",
solutionPath: "https://cdn.jsdelivr.net/npm/#mediapipe/face_mesh",
};
const detector = await facemesh.createDetector(model, detectorConfig);
setInterval(() => {
detect(detector);
}, 10);
};
const detect = async (detector) => {
if (
typeof webcamRef.current !== "undefined" &&
webcamRef.current !== null &&
webcamRef.current.video.readyState === 4
) {
const video = webcamRef.current.video;
const videoWidth = webcamRef.current.video.videoWidth;
const videoHeight = webcamRef.current.video.videoHeight;
webcamRef.current.video.width = videoWidth;
webcamRef.current.video.height = videoHeight;
canvasRef.current.width = videoWidth;
canvasRef.current.height = videoHeight;
const face = await detector.estimateFaces(video);
const ctx = canvasRef.current.getContext("2d");
requestAnimationFrame(() => {
drawMesh(face, ctx);
});
}
};
useEffect(() => {
runFaceMesh();
}, []);
return (
<div className="App">
<header className="App-header">
<Webcam
ref={webcamRef}
style={{
position: "absolute",
marginLeft: "auto",
marginRight: "auto",
left: 0,
right: 0,
textAlign: "center",
zIndex: 9,
width: 640,
height: 480,
}}
/>
<canvas
ref={canvasRef}
style={{
position: "absolute",
marginLeft: "auto",
marginRight: "auto",
left: 0,
right: 0,
textAlign: "center",
zIndex: 9,
width: 640,
height: 480,
}}
/>
</header>
</div>
);
}
export default App;
// utilities.js
export const TRIANGULATION = [
127, 34, 139, 11, 0, 37, 232, 231, 120, 72, 37, 39, 128, 121, 47, 232, 121,
128, 104, 69, 67, 175, 171, 148, 157, 154, 155, 118, 50, 101, 73, 39, 40, 9,
151, 108, 48, 115, 131, 194, 204, 211, 74, 40, 185, 80, 42, 183, 40, 92, 186,
230, 229, 118, 202, 212, 214, 83, 18, 17, 76, 61, 146, 160, 29, 30, 56, 157,
173, 106, 204, 194, 135, 214, 192, 203, 165, 98, 21, 71, 68, 51, 45, 4, 144,
24, 23, 77, 146, 91, 205, 50, 187, 201, 200, 18, 91, 106, 182, 90, 91, 181,
85, 84, 17, 206, 203, 36, 148, 171, 140, 92, 40, 39, 193, 189, 244, 159, 158,
28, 247, 246, 161, 236, 3, 196, 54, 68, 104, 193, 168, 8, 117, 228, 31, 189,
193, 55, 98, 97, 99, 126, 47, 100, 166, 79, 218, 155, 154, 26, 209, 49, 131,
135, 136, 150, 47, 126, 217, 223, 52, 53, 45, 51, 134, 211, 170, 140, 67, 69,
108, 43, 106, 91, 230, 119, 120, 226, 130, 247, 63, 53, 52, 238, 20, 242, 46,
70, 156, 78, 62, 96, 46, 53, 63, 143, 34, 227, 173, 155, 133, 123, 117, 111,
44, 125, 19, 236, 134, 51, 216, 206, 205, 154, 153, 22, 39, 37, 167, 200, 201,
208, 36, 142, 100, 57, 212, 202, 20, 60, 99, 28, 158, 157, 35, 226, 113, 160,
159, 27, 204, 202, 210, 113, 225, 46, 43, 202, 204, 62, 76, 77, 137, 123, 116,
41, 38, 72, 203, 129, 142, 64, 98, 240, 49, 102, 64, 41, 73, 74, 212, 216,
207, 42, 74, 184, 169, 170, 211, 170, 149, 176, 105, 66, 69, 122, 6, 168, 123,
147, 187, 96, 77, 90, 65, 55, 107, 89, 90, 180, 101, 100, 120, 63, 105, 104,
93, 137, 227, 15, 86, 85, 129, 102, 49, 14, 87, 86, 55, 8, 9, 100, 47, 121,
145, 23, 22, 88, 89, 179, 6, 122, 196, 88, 95, 96, 138, 172, 136, 215, 58,
172, 115, 48, 219, 42, 80, 81, 195, 3, 51, 43, 146, 61, 171, 175, 199, 81, 82,
38, 53, 46, 225, 144, 163, 110, 246, 33, 7, 52, 65, 66, 229, 228, 117, 34,
127, 234, 107, 108, 69, 109, 108, 151, 48, 64, 235, 62, 78, 191, 129, 209,
126, 111, 35, 143, 163, 161, 246, 117, 123, 50, 222, 65, 52, 19, 125, 141,
221, 55, 65, 3, 195, 197, 25, 7, 33, 220, 237, 44, 70, 71, 139, 122, 193, 245,
247, 130, 33, 71, 21, 162, 153, 158, 159, 170, 169, 150, 188, 174, 196, 216,
186, 92, 144, 160, 161, 2, 97, 167, 141, 125, 241, 164, 167, 37, 72, 38, 12,
145, 159, 160, 38, 82, 13, 63, 68, 71, 226, 35, 111, 158, 153, 154, 101, 50,
205, 206, 92, 165, 209, 198, 217, 165, 167, 97, 220, 115, 218, 133, 112, 243,
239, 238, 241, 214, 135, 169, 190, 173, 133, 171, 208, 32, 125, 44, 237, 86,
87, 178, 85, 86, 179, 84, 85, 180, 83, 84, 181, 201, 83, 182, 137, 93, 132,
76, 62, 183, 61, 76, 184, 57, 61, 185, 212, 57, 186, 214, 207, 187, 34, 143,
156, 79, 239, 237, 123, 137, 177, 44, 1, 4, 201, 194, 32, 64, 102, 129, 213,
215, 138, 59, 166, 219, 242, 99, 97, 2, 94, 141, 75, 59, 235, 24, 110, 228,
25, 130, 226, 23, 24, 229, 22, 23, 230, 26, 22, 231, 112, 26, 232, 189, 190,
243, 221, 56, 190, 28, 56, 221, 27, 28, 222, 29, 27, 223, 30, 29, 224, 247,
30, 225, 238, 79, 20, 166, 59, 75, 60, 75, 240, 147, 177, 215, 20, 79, 166,
187, 147, 213, 112, 233, 244, 233, 128, 245, 128, 114, 188, 114, 217, 174,
131, 115, 220, 217, 198, 236, 198, 131, 134, 177, 132, 58, 143, 35, 124, 110,
163, 7, 228, 110, 25, 356, 389, 368, 11, 302, 267, 452, 350, 349, 302, 303,
269, 357, 343, 277, 452, 453, 357, 333, 332, 297, 175, 152, 377, 384, 398,
382, 347, 348, 330, 303, 304, 270, 9, 336, 337, 278, 279, 360, 418, 262, 431,
304, 408, 409, 310, 415, 407, 270, 409, 410, 450, 348, 347, 422, 430, 434,
313, 314, 17, 306, 307, 375, 387, 388, 260, 286, 414, 398, 335, 406, 418, 364,
367, 416, 423, 358, 327, 251, 284, 298, 281, 5, 4, 373, 374, 253, 307, 320,
321, 425, 427, 411, 421, 313, 18, 321, 405, 406, 320, 404, 405, 315, 16, 17,
426, 425, 266, 377, 400, 369, 322, 391, 269, 417, 465, 464, 386, 257, 258,
466, 260, 388, 456, 399, 419, 284, 332, 333, 417, 285, 8, 346, 340, 261, 413,
441, 285, 327, 460, 328, 355, 371, 329, 392, 439, 438, 382, 341, 256, 429,
420, 360, 364, 394, 379, 277, 343, 437, 443, 444, 283, 275, 440, 363, 431,
262, 369, 297, 338, 337, 273, 375, 321, 450, 451, 349, 446, 342, 467, 293,
334, 282, 458, 461, 462, 276, 353, 383, 308, 324, 325, 276, 300, 293, 372,
345, 447, 382, 398, 362, 352, 345, 340, 274, 1, 19, 456, 248, 281, 436, 427,
425, 381, 256, 252, 269, 391, 393, 200, 199, 428, 266, 330, 329, 287, 273,
422, 250, 462, 328, 258, 286, 384, 265, 353, 342, 387, 259, 257, 424, 431,
430, 342, 353, 276, 273, 335, 424, 292, 325, 307, 366, 447, 345, 271, 303,
302, 423, 266, 371, 294, 455, 460, 279, 278, 294, 271, 272, 304, 432, 434,
427, 272, 407, 408, 394, 430, 431, 395, 369, 400, 334, 333, 299, 351, 417,
168, 352, 280, 411, 325, 319, 320, 295, 296, 336, 319, 403, 404, 330, 348,
349, 293, 298, 333, 323, 454, 447, 15, 16, 315, 358, 429, 279, 14, 15, 316,
285, 336, 9, 329, 349, 350, 374, 380, 252, 318, 402, 403, 6, 197, 419, 318,
319, 325, 367, 364, 365, 435, 367, 397, 344, 438, 439, 272, 271, 311, 195, 5,
281, 273, 287, 291, 396, 428, 199, 311, 271, 268, 283, 444, 445, 373, 254,
339, 263, 466, 249, 282, 334, 296, 449, 347, 346, 264, 447, 454, 336, 296,
299, 338, 10, 151, 278, 439, 455, 292, 407, 415, 358, 371, 355, 340, 345, 372,
390, 249, 466, 346, 347, 280, 442, 443, 282, 19, 94, 370, 441, 442, 295, 248,
419, 197, 263, 255, 359, 440, 275, 274, 300, 383, 368, 351, 412, 465, 263,
467, 466, 301, 368, 389, 380, 374, 386, 395, 378, 379, 412, 351, 419, 436,
426, 322, 373, 390, 388, 2, 164, 393, 370, 462, 461, 164, 0, 267, 302, 11, 12,
374, 373, 387, 268, 12, 13, 293, 300, 301, 446, 261, 340, 385, 384, 381, 330,
266, 425, 426, 423, 391, 429, 355, 437, 391, 327, 326, 440, 457, 438, 341,
382, 362, 459, 457, 461, 434, 430, 394, 414, 463, 362, 396, 369, 262, 354,
461, 457, 316, 403, 402, 315, 404, 403, 314, 405, 404, 313, 406, 405, 421,
418, 406, 366, 401, 361, 306, 408, 407, 291, 409, 408, 287, 410, 409, 432,
436, 410, 434, 416, 411, 264, 368, 383, 309, 438, 457, 352, 376, 401, 274,
275, 4, 421, 428, 262, 294, 327, 358, 433, 416, 367, 289, 455, 439, 462, 370,
326, 2, 326, 370, 305, 460, 455, 254, 449, 448, 255, 261, 446, 253, 450, 449,
252, 451, 450, 256, 452, 451, 341, 453, 452, 413, 464, 463, 441, 413, 414,
258, 442, 441, 257, 443, 442, 259, 444, 443, 260, 445, 444, 467, 342, 445,
459, 458, 250, 289, 392, 290, 290, 328, 460, 376, 433, 435, 250, 290, 392,
411, 416, 433, 341, 463, 464, 453, 464, 465, 357, 465, 412, 343, 412, 399,
360, 363, 440, 437, 399, 456, 420, 456, 363, 401, 435, 288, 372, 383, 353,
339, 255, 249, 448, 261, 255, 133, 243, 190, 133, 155, 112, 33, 246, 247, 33,
130, 25, 398, 384, 286, 362, 398, 414, 362, 463, 341, 263, 359, 467, 263, 249,
255, 466, 467, 260, 75, 60, 166, 238, 239, 79, 162, 127, 139, 72, 11, 37, 121,
232, 120, 73, 72, 39, 114, 128, 47, 233, 232, 128, 103, 104, 67, 152, 175,
148, 173, 157, 155, 119, 118, 101, 74, 73, 40, 107, 9, 108, 49, 48, 131, 32,
194, 211, 184, 74, 185, 191, 80, 183, 185, 40, 186, 119, 230, 118, 210, 202,
214, 84, 83, 17, 77, 76, 146, 161, 160, 30, 190, 56, 173, 182, 106, 194, 138,
135, 192, 129, 203, 98, 54, 21, 68, 5, 51, 4, 145, 144, 23, 90, 77, 91, 207,
205, 187, 83, 201, 18, 181, 91, 182, 180, 90, 181, 16, 85, 17, 205, 206, 36,
176, 148, 140, 165, 92, 39, 245, 193, 244, 27, 159, 28, 30, 247, 161, 174,
236, 196, 103, 54, 104, 55, 193, 8, 111, 117, 31, 221, 189, 55, 240, 98, 99,
142, 126, 100, 219, 166, 218, 112, 155, 26, 198, 209, 131, 169, 135, 150, 114,
47, 217, 224, 223, 53, 220, 45, 134, 32, 211, 140, 109, 67, 108, 146, 43, 91,
231, 230, 120, 113, 226, 247, 105, 63, 52, 241, 238, 242, 124, 46, 156, 95,
78, 96, 70, 46, 63, 116, 143, 227, 116, 123, 111, 1, 44, 19, 3, 236, 51, 207,
216, 205, 26, 154, 22, 165, 39, 167, 199, 200, 208, 101, 36, 100, 43, 57, 202,
242, 20, 99, 56, 28, 157, 124, 35, 113, 29, 160, 27, 211, 204, 210, 124, 113,
46, 106, 43, 204, 96, 62, 77, 227, 137, 116, 73, 41, 72, 36, 203, 142, 235,
64, 240, 48, 49, 64, 42, 41, 74, 214, 212, 207, 183, 42, 184, 210, 169, 211,
140, 170, 176, 104, 105, 69, 193, 122, 168, 50, 123, 187, 89, 96, 90, 66, 65,
107, 179, 89, 180, 119, 101, 120, 68, 63, 104, 234, 93, 227, 16, 15, 85, 209,
129, 49, 15, 14, 86, 107, 55, 9, 120, 100, 121, 153, 145, 22, 178, 88, 179,
197, 6, 196, 89, 88, 96, 135, 138, 136, 138, 215, 172, 218, 115, 219, 41, 42,
81, 5, 195, 51, 57, 43, 61, 208, 171, 199, 41, 81, 38, 224, 53, 225, 24, 144,
110, 105, 52, 66, 118, 229, 117, 227, 34, 234, 66, 107, 69, 10, 109, 151, 219,
48, 235, 183, 62, 191, 142, 129, 126, 116, 111, 143, 7, 163, 246, 118, 117,
50, 223, 222, 52, 94, 19, 141, 222, 221, 65, 196, 3, 197, 45, 220, 44, 156,
70, 139, 188, 122, 245, 139, 71, 162, 145, 153, 159, 149, 170, 150, 122, 188,
196, 206, 216, 92, 163, 144, 161, 164, 2, 167, 242, 141, 241, 0, 164, 37, 11,
72, 12, 144, 145, 160, 12, 38, 13, 70, 63, 71, 31, 226, 111, 157, 158, 154,
36, 101, 205, 203, 206, 165, 126, 209, 217, 98, 165, 97, 237, 220, 218, 237,
239, 241, 210, 214, 169, 140, 171, 32, 241, 125, 237, 179, 86, 178, 180, 85,
179, 181, 84, 180, 182, 83, 181, 194, 201, 182, 177, 137, 132, 184, 76, 183,
185, 61, 184, 186, 57, 185, 216, 212, 186, 192, 214, 187, 139, 34, 156, 218,
79, 237, 147, 123, 177, 45, 44, 4, 208, 201, 32, 98, 64, 129, 192, 213, 138,
235, 59, 219, 141, 242, 97, 97, 2, 141, 240, 75, 235, 229, 24, 228, 31, 25,
226, 230, 23, 229, 231, 22, 230, 232, 26, 231, 233, 112, 232, 244, 189, 243,
189, 221, 190, 222, 28, 221, 223, 27, 222, 224, 29, 223, 225, 30, 224, 113,
247, 225, 99, 60, 240, 213, 147, 215, 60, 20, 166, 192, 187, 213, 243, 112,
244, 244, 233, 245, 245, 128, 188, 188, 114, 174, 134, 131, 220, 174, 217,
236, 236, 198, 134, 215, 177, 58, 156, 143, 124, 25, 110, 7, 31, 228, 25, 264,
356, 368, 0, 11, 267, 451, 452, 349, 267, 302, 269, 350, 357, 277, 350, 452,
357, 299, 333, 297, 396, 175, 377, 381, 384, 382, 280, 347, 330, 269, 303,
270, 151, 9, 337, 344, 278, 360, 424, 418, 431, 270, 304, 409, 272, 310, 407,
322, 270, 410, 449, 450, 347, 432, 422, 434, 18, 313, 17, 291, 306, 375, 259,
387, 260, 424, 335, 418, 434, 364, 416, 391, 423, 327, 301, 251, 298, 275,
281, 4, 254, 373, 253, 375, 307, 321, 280, 425, 411, 200, 421, 18, 335, 321,
406, 321, 320, 405, 314, 315, 17, 423, 426, 266, 396, 377, 369, 270, 322, 269,
413, 417, 464, 385, 386, 258, 248, 456, 419, 298, 284, 333, 168, 417, 8, 448,
346, 261, 417, 413, 285, 326, 327, 328, 277, 355, 329, 309, 392, 438, 381,
382, 256, 279, 429, 360, 365, 364, 379, 355, 277, 437, 282, 443, 283, 281,
275, 363, 395, 431, 369, 299, 297, 337, 335, 273, 321, 348, 450, 349, 359,
446, 467, 283, 293, 282, 250, 458, 462, 300, 276, 383, 292, 308, 325, 283,
276, 293, 264, 372, 447, 346, 352, 340, 354, 274, 19, 363, 456, 281, 426, 436,
425, 380, 381, 252, 267, 269, 393, 421, 200, 428, 371, 266, 329, 432, 287,
422, 290, 250, 328, 385, 258, 384, 446, 265, 342, 386, 387, 257, 422, 424,
430, 445, 342, 276, 422, 273, 424, 306, 292, 307, 352, 366, 345, 268, 271,
302, 358, 423, 371, 327, 294, 460, 331, 279, 294, 303, 271, 304, 436, 432,
427, 304, 272, 408, 395, 394, 431, 378, 395, 400, 296, 334, 299, 6, 351, 168,
376, 352, 411, 307, 325, 320, 285, 295, 336, 320, 319, 404, 329, 330, 349,
334, 293, 333, 366, 323, 447, 316, 15, 315, 331, 358, 279, 317, 14, 316, 8,
285, 9, 277, 329, 350, 253, 374, 252, 319, 318, 403, 351, 6, 419, 324, 318,
325, 397, 367, 365, 288, 435, 397, 278, 344, 439, 310, 272, 311, 248, 195,
281, 375, 273, 291, 175, 396, 199, 312, 311, 268, 276, 283, 445, 390, 373,
339, 295, 282, 296, 448, 449, 346, 356, 264, 454, 337, 336, 299, 337, 338,
151, 294, 278, 455, 308, 292, 415, 429, 358, 355, 265, 340, 372, 388, 390,
466, 352, 346, 280, 295, 442, 282, 354, 19, 370, 285, 441, 295, 195, 248, 197,
457, 440, 274, 301, 300, 368, 417, 351, 465, 251, 301, 389, 385, 380, 386,
394, 395, 379, 399, 412, 419, 410, 436, 322, 387, 373, 388, 326, 2, 393, 354,
370, 461, 393, 164, 267, 268, 302, 12, 386, 374, 387, 312, 268, 13, 298, 293,
301, 265, 446, 340, 380, 385, 381, 280, 330, 425, 322, 426, 391, 420, 429,
437, 393, 391, 326, 344, 440, 438, 458, 459, 461, 364, 434, 394, 428, 396,
262, 274, 354, 457, 317, 316, 402, 316, 315, 403, 315, 314, 404, 314, 313,
405, 313, 421, 406, 323, 366, 361, 292, 306, 407, 306, 291, 408, 291, 287,
409, 287, 432, 410, 427, 434, 411, 372, 264, 383, 459, 309, 457, 366, 352,
401, 1, 274, 4, 418, 421, 262, 331, 294, 358, 435, 433, 367, 392, 289, 439,
328, 462, 326, 94, 2, 370, 289, 305, 455, 339, 254, 448, 359, 255, 446, 254,
253, 449, 253, 252, 450, 252, 256, 451, 256, 341, 452, 414, 413, 463, 286,
441, 414, 286, 258, 441, 258, 257, 442, 257, 259, 443, 259, 260, 444, 260,
467, 445, 309, 459, 250, 305, 289, 290, 305, 290, 460, 401, 376, 435, 309,
250, 392, 376, 411, 433, 453, 341, 464, 357, 453, 465, 343, 357, 412, 437,
343, 399, 344, 360, 440, 420, 437, 456, 360, 420, 363, 361, 401, 288, 265,
372, 353, 390, 339, 249, 339, 448, 255,
];
const drawPath = (ctx, points, closePath) => {
const region = new Path2D();
region.moveTo(points[0].x, points[0].y);
for (let i = 1; i < points.length; i++) {
const point = points[i];
region.lineTo(point.x, point.y);
}
if (closePath) {
region.closePath();
}
ctx.strokeStyle = "grey";
ctx.stroke(region);
};
export const drawMesh = (predictions, ctx) => {
if (predictions.length > 0) {
predictions.forEach((prediction) => {
const keyPoints = prediction.keypoints;
for (let i = 0; i < TRIANGULATION.length / 3; i++) {
const points = [
TRIANGULATION[i * 3],
TRIANGULATION[i * 3 + 1],
TRIANGULATION[i * 3 + 2],
].map((index) => keyPoints[index]);
drawPath(ctx, points, true);
}
for (let i = 0; i < keyPoints.length; i++) {
const x = keyPoints[i].x;
const y = keyPoints[i].y;
ctx.beginPath();
ctx.arc(x, y, 1, 0, 3 * Math.PI);
ctx.fillStyle = "aqua";
ctx.fill();
}
});
}
};

Zoom is very slow in ChartJS Zoom Plugin

I'm trying to build a webpage with some graphs. In order to get it, I'm using ChartJS. Sometimes can happen there are too many data to see in just one canvas, so I need to use the ChartJS zoom plugin. I install and use it well, unless I have a big problem:
Setting the mode as 'x', the zoom applied on canvas is really really slow (even if I put 100000 as speed value). I want to make it faster. How can I solve it? This is my code:
new Chart(document.getElementById('like-growth-lt'), {
type: 'line',
data: {
labels: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515],
datasets: [{
data: [64, 44, 71, 71, 24, 32, 54, 56, 36, 37, 50, 38, 48, 33, 46, 88, 43, 45, 48, 36, 44, 38, 64, 63, 89, 40, 50, 85, 79, 69, 64, 70, 66, 70, 40, 178, 57, 25, 38, 105, 79, 58, 89, 102, 94, 87, 91, 93, 100, 72, 78, 65, 68, 123, 79, 107, 91, 66, 89, 90, 45, 127, 138, 79, 58, 81, 92, 97, 52, 97, 43, 64, 81, 62, 69, 74, 75, 54, 93, 43, 101, 83, 49, 106, 77, 86, 105, 91, 73, 129, 99, 64, 104, 92, 105, 141, 96, 100, 84, 101, 75, 100, 76, 112, 171, 94, 78, 97, 87, 100, 198, 112, 98, 95, 127, 107, 74, 122, 137, 45, 147, 147, 169, 125, 147, 129, 118, 164, 90, 135, 132, 135, 135, 239, 197, 165, 261, 150, 164, 238, 271, 196, 307, 246, 137, 112, 142, 265, 295, 173, 172, 116, 127, 141, 142, 134, 196, 298, 305, 273, 121, 99, 108, 138, 191, 310, 375, 360, 427, 271, 191, 168, 123, 323, 70, 126, 138, 222, 170, 160, 185, 236, 160, 290, 192, 196, 386, 166, 186, 236, 232, 425, 181, 142, 103, 126, 176, 292, 200, 186, 179, 277, 305, 610, 140, 200, 283, 218, 384, 183, 165, 156, 195, 215, 210, 157, 337, 208, 799, 130, 242, 80, 337, 181, 261, 307, 264, 371, 639, 379, 253, 384, 141, 391, 212, 1371, 321, 149, 345, 345, 159, 337, 313, 1131, 204, 339, 396, 208, 285, 99, 440, 410, 187, 138, 109, 241, 318, 225, 415, 350, 231, 267, 432, 195, 228, 418, 360, 334, 204, 706, 270, 70, 328, 219, 319, 594, 168, 229, 632, 281, 259, 391, 150, 628, 273, 339, 432, 237, 667, 319, 302, 88, 167, 334, 274, 121, 303, 636, 233, 1399, 465, 404, 211, 209, 537, 361, 192, 189, 474, 1694, 659, 297, 495, 883, 417, 427, 298, 438, 251, 381, 422, 442, 225, 418, 177, 476, 292, 619, 147, 293, 375, 228, 326, 539, 306, 416, 317, 239, 1095, 605, 219, 392, 320, 296, 216, 355, 563, 291, 792, 298, 319, 252, 526, 225, 225, 399, 387, 255, 311, 199, 364, 542, 405, 260, 175, 173, 582, 231, 201, 196, 222, 909, 265, 191, 243, 346, 349, 163, 263, 151, 217, 261, 172, 191, 387, 314, 379, 172, 157, 446, 120, 131, 494, 445, 294, 414, 485, 407, 415, 214, 242, 159, 168, 145, 256, 123, 350, 999, 296, 171, 790, 1051, 620, 330, 231, 1742, 194, 547, 360, 136, 503, 555, 646, 580, 609, 566, 256, 181, 189, 562, 176, 622, 758, 692, 358, 202, 1877, 1157, 668, 311, 1037, 736, 1477, 616, 677, 605, 224, 838, 306, 704, 503, 448, 1198, 778, 171, 921, 1071, 1099, 837, 329, 2337, 395, 1063, 297, 1415, 1195, 745, 341, 931, 1178, 336, 1016, 234, 632, 573, 495, 944, 993, 1066, 1980, 619, 556, 238, 818, 1003, 532, 1427, 373, 249, 304, 790, 2962, 985, 252, 1545, 276, 1219, 1112, 1109, 1367, 792, 1116, 1055, 648, 740, 435, 1528, 805, 565, 1183, 1105, 1498, 1453, 381, 651, 2073],
label: '',
borderColor: 'rgb(22, 133, 204)',
backgroundColor: 'rgba(22, 133, 204, 0.3)',
},
]
},
options: {
pan: {
enabled: true,
mode: "x",
speed: 10000000000000000
},
zoom: {
enabled: true,
drag: false,
mode: "x",
speed: 10000000000000000
},
responsive: true
}
});
.panel{
position: relative;
padding-bottom: 20px;
width: 100%;
}
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.9.3"></script>
<script src="https://cdn.jsdelivr.net/npm/hammerjs#2.0.8"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-zoom#0.7.7"></script>
<div class="panel" id="panel-lt">
<canvas id="like-growth-lt" ></canvas>
</div>
You need to set your scales.xAxes.type to numeric and then set the speed to 0.1. Speed is from 0 to 1, so setting it to 1000000 is useless.

How to implement motion video highchart on Reactjs

I am able to make bubble chart using highchart library. But is there any way we can implement motion to it.
Example link is below
http://jsfiddle.net/gh/get/library/pure/larsac07/Motion-Highcharts-Plugin/tree/master/demos/map-australia-bubbles-demo/
My problem is motions.js and bubble.js are external files. Here in react we are using render method to render highchart.
Below state options will be having motion object and series like below
motion: {
enabled: true,
axisLabel: 'year',
loop: false,
series: 0, // The series which holds points to update
updateInterval: 100,
magnet: {
round: 'round', // ceil / floor / round
step: 0.1
},
labels: [20181031, 20181101, 20181102, 20181103, 20181104, 20181105, 20181106, 20181107, 20181108, 20181109, 20181110, 20181111, 20181112, 20181113]
},
series: [{
name: 'Things',
colorByPoint: true,
id: 'deep',
marker: {
fillColor: {
radialGradient: { cx: 0.4, cy: 0.3, r: 0.7 },
stops: [
[0, 'rgba(255,255,255,0.5)']
]
}
},
data: [{ "color": "rgba(67, 67, 72, 0.5)", "fillColor": "rgba(67, 67, 72, 0.5)", "x": 38.42, "y": 0, "z": 6, "name": "California" }, { "color": "rgba(67, 67, 72, 0.5)", "fillColor": "rgba(67, 67, 72, 0.5)", "x": 38.17, "y": 0, "z": 6, "name": "California" }, { "color": "rgba(67, 67, 72, 0.5)", "fillColor": "rgba(67, 67, 72, 0.5)", "x": 38.75, "y": 0, "z": 6, "name": "California" }, { "color": "rgba(67, 67, 72, 0.5)", "fillColor": "rgba(67, 67, 72, 0.5)", "x": 37.92, "y": 0, "z": 6, "name": "California" }, { "color": "rgba(67, 67, 72, 0.5)", "fillColor": "rgba(67, 67, 72, 0.5)", "x": 37.08, "y": 0, "z": 6, "name": "California" }, { "color": "rgba(67, 67, 72, 0.5)", "fillColor": "rgba(67, 67, 72, 0.5)", "x": 37.75, "y": 0, "z": 6, "name": "California" }, { "color": "rgba(67, 67, 72, 0.5)", "fillColor": "rgba(67, 67, 72, 0.5)", "x": 37.83, "y": 0, "z": 6, "name": "California" }, { "color": "rgba(67, 67, 72, 0.5)", "fillColor": "rgba(67, 67, 72, 0.5)", "x": 37.5, "y": 0, "z": 6, "name": "California" }, { "color": "rgba(67, 67, 72, 0.5)", "fillColor": "rgba(67, 67, 72, 0.5)", "x": 38.08, "y": 0, "z": 6, "name": "California" }, { "color": "rgba(67, 67, 72, 0.5)", "fillColor": "rgba(67, 67, 72, 0.5)", "x": 36.92, "y": 0, "z": 6, "name": "California" }, { "color": "rgba(67, 67, 72, 0.5)", "fillColor": "rgba(67, 67, 72, 0.5)", "x": 13, "y": 0, "z": 6, "name": "California" }, { "color": "rgba(67, 67, 72, 0.5)", "fillColor": "rgba(67, 67, 72, 0.5)", "x": 36, "y": 0, "z": 6, "name": "California" }, { "color": "rgba(67, 67, 72, 0.5)", "fillColor": "rgba(67, 67, 72, 0.5)", "x": 13, "y": 0, "z": 6, "name": "California" }, { "color": "rgba(67, 67, 72, 0.5)", "fillColor": "rgba(67, 67, 72, 0.5)", "x": 13, "y": 0, "z": 6, "name": "California" }]
}]
return (
<div>
<Highcharts
config={this.state.options}
/>
</div>
);
I recommend you to use highcharts-react-official wrapper: https://www.npmjs.com/package/highcharts-react-official
By using this wrapper, you can in easy way add additional plugins or modules. Below I created a live example with Motion-Highcharts-Plugin.
Live demo: https://codesandbox.io/s/6j359qpr6r

Scale a Polygon of an image

I want to be able to scale a polygon of an image on hover.
To be precise, its a world-map, and I want to scale the country bigger, when you hover over it, and then make it smaller again, when not hovering any more.
I know, that there is the transform: scale(2) for CSS for example, and it works fine with normal images or also with world map. But actually I don't want to scale the hole map, but a polygon of the map (or at least, if a polygon is not possible, then a square (so only a little part of the map).
Is there any way to do this? Doesn't have to be CSS only, can also be JS/jQuery.
The hover part is not part of the question, thats simple jQuery, but the question is how to scale only a specific part of an image.
Thanks for any help!
It's been a noisy night here. So I've thrown together something to play with. It's an incomplete implementation - I just grab the part of the image hovered and throw it into a picture along-side the original.
It's up to you to
(0) show the image larger than full size
(1) position it in front of the original, using absolute positioning and z-index
(2) handle mouseout on the hovered area.
The answer I linked to in the comments demonstrates positioning, z-ordering and passing pointer events to the underlying map elements.
You'll need to decide just how/where you wish the enlarged version to appear. Perhaps you'd want it 150%, with the center-point atop the center-point of the map element.
As the comments indicate, you'd normally use an existing image, rather than creating one from scratch, as I've done here.
First, the complete source in a single piece - just copy it all and past into a new html file.
<!DOCTYPE html>
<html>
<head>
<script>
"use strict";
function byId(e){return document.getElementById(e);}
function newEl(tag){return document.createElement(tag);}
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(e)
{
createImageFromMapAreasForUseAtStackoverflow();
attachHoverHandlers();
}
// this function is only used for the purpose of answering this question.
// Ordinarily, you would set the src of #img1 to be that of your image. - since cross-origin contamination prevents
// access to the image data if the image comes from a different server, I've just opted to create the image from scratch.
//
// the original image may be found here: https://upload.wikimedia.org/wikipedia/commons/thumb/1/16/Australia_location_map_recolored.png/500px-Australia_location_map_recolored.png
function createImageFromMapAreasForUseAtStackoverflow()
{
var imgWidth = 500, imgHeight = 360;
var can = newEl('canvas');
can.width = imgWidth;
can.height = imgHeight;
var ctx = can.getContext('2d');
ctx.fillStyle = '#ecf5f6';
ctx.fillRect(0,0,imgWidth,imgHeight);
var areas = document.querySelectorAll('area');
var i, n = areas.length;
var colours = ['#f4f100', '#b2d025', '#f67c60', '#8fbce1', '#f4f236', '#fca164', '#bc9eee', 'black'];
for (i=0; i<n; i++)
{
var areaType = areas[i].getAttribute('shape');
if ((areaType == 'polygon') || (areaType == 'poly'))
drawMapPoly(areas[i].getAttribute('coords'), colours[i]);
}
byId('img1').src = can.toDataURL();
function drawMapPoly(coordStr, colour)
{
ctx.beginPath();
var ptArray = coordStrToPointArray(coordStr);
var i, n=ptArray.length;
ctx.moveTo(ptArray[0].x, ptArray[0].y);
for (i=0;i<n;i++)
ctx.lineTo(ptArray[i].x,ptArray[i].y);
ctx.closePath();
ctx.fillStyle=colour;
ctx.fill();
}
}
function attachHoverHandlers()
{
//
// Attach event-listeners to each of the areas in the image-map to handle mouseover
//
var areas = document.querySelectorAll('area');
var i, n = areas.length;
for (i=0; i<n; i++)
{
areas[i].addEventListener('mouseover', onAreaHovered, false);
}
}
function onAreaHovered(e)
{
var hoveredElement = this;
var coordStr = this.getAttribute('coords');
var areaType = this.getAttribute('shape');
switch (areaType)
{
case 'polygon':
case 'poly':
showPolyCoords(coordStr);
break;
default:
alert("You need to add a handler for areas of type '" + areaType + "'");
}
}
function coordStrToPointArray(coordStr)
{
var mCoords = coordStr.split(',');
var i, n = mCoords.length;
var coordArray = [];
coordArray.push( new p2d(mCoords[0], mCoords[1]) );
for (i=2; i<n; i+=2)
{
coordArray.push( new p2d(mCoords[i], mCoords[i+1]) );
}
coordArray.push( new p2d(mCoords[0], mCoords[1]) );
return coordArray;
}
// takes a string that contains coords eg - "227,307,261,309, 339,354, 328,371, 240,331"
// draws a line from each co-ord pair to the next - assumes starting point needs to be repeated as ending point.
function showPolyCoords(coOrdStr)
{
var coordArray = coordStrToPointArray(coOrdStr);
var sortedArray = coordArray.slice();
sortedArray.sort(sortX);
var minX = sortedArray[0].x;
var maxX = sortedArray[sortedArray.length-1].x;
sortedArray.sort(sortY);
var minY = sortedArray[0].y;
var maxY = sortedArray[sortedArray.length-1].y;
var topLeft = new p2d(minX, minY);
var botRight = new p2d(maxX, maxY);
testFuncWithClipping(topLeft, botRight, 'img1', coordArray);
}
function p2d(x, y)
{
this.x = Number(x);
this.y = Number(y);
return this;
}
// unneccesary - just makes displaying the point easier.
// Having this prototype available means that (in chrome at least)
// the code: "console.log( pt2d );" or "alert( pt2d );" will result in "<xCoord, yCoord>" being printed/alerted
p2d.prototype.toString = function()
{
return "<"+this.x+", "+this.y+">";
}
// comparison functions used when sorting the point list to obtain the min/max values of both X and Y
function sortX(a, b){return a.x - b.x;}
function sortY(a, b){return a.y - b.y;}
function testFuncWithClipping(topLeft, botRight, srcImgId, pointArray)
{
var width = botRight.x - topLeft.x;
var height = botRight.y - topLeft.y;
var can = newEl('canvas');
can.width = width;
can.height = height;
var ctx = can.getContext('2d');
var img = byId(srcImgId);
ctx.beginPath();
ctx.moveTo( pointArray[0].x - topLeft.x, pointArray[0].y-topLeft.y );
var i, n = pointArray.length;
for (i=0; i<n; i++)
{
ctx.lineTo( pointArray[i].x - topLeft.x, pointArray[i].y-topLeft.y );
}
ctx.clip();
ctx.drawImage(img, topLeft.x, topLeft.y, width, height, 0,0, width,height);
byId('img2').src = can.toDataURL();
}
</script>
<style>
body
{
background-color: gray;
}
#canvas2
{
pointer-events: none; /* make the canvas transparent to the mouse - needed since canvas is position infront of image */
position: absolute; /* you'll need to use this trick to allow the area to know when the mouse leaves it, so you can hide/destroy the */
} /* enlarged version of the hovered area */
</style>
</head>
<body>
<!--
Usually, you would use this element.
For the purpose of making a working demo, I've used the next element and have created the picture using the map data and
the funtion createImageFromMapAreasForUseAtStackoverflow
As mentioned above, the original image is:
https://upload.wikimedia.org/wikipedia/commons/thumb/1/16/Australia_location_map_recolored.png/500px-Australia_location_map_recolored.png
which was saved as ausMap.png in the img folder of my localhost.
<img id='img1' usemap='#imgMap1' src='img/ausMap.png' />
-->
<img id='img1' usemap='#imgMap1'/>
<map name='imgMap1' id='imgMap1'>
<area shape="polygon" coords="359, 324, 373, 332, 392, 327, 393, 346, 375, 356, 364, 343" title="Tasmania">
<area shape="polygon" coords="325, 258, 335, 258, 339, 265, 346, 265, 347, 271, 357, 279, 360, 279, 361, 276, 368, 278, 380, 279, 388, 277, 390, 288, 406, 293, 405, 296, 391, 297, 377, 308, 376, 310, 372, 308, 356, 303, 350, 307, 338, 303, 332, 301, 325, 300" title="Victoria">
<area shape="polygon" coords="325, 207, 397, 206, 403, 201, 417, 203, 420, 209, 425, 205, 427, 200, 440, 197, 440, 204, 436, 222, 432, 235, 432, 241, 424, 245, 419, 255, 415, 267, 408, 277, 408, 293, 391, 286, 389, 278, 381, 279, 373, 279, 364, 276, 361, 278, 348, 271, 346, 265, 340, 266, 338, 261, 333, 258, 325, 258" title="New South Wales">
<area shape="polygon" coords="325, 206, 398, 207, 404, 201, 417, 203, 423, 207, 427, 201, 434, 198, 441, 198, 436, 169, 429, 159, 419, 150, 416, 142, 410, 138, 406, 139, 400, 121, 397, 114, 375, 101, 372, 82, 367, 79, 365, 61, 357, 52, 353, 56, 349, 39, 345, 31, 341, 22, 336, 18, 336, 27, 330, 35, 334, 38, 331, 41, 330, 46, 331, 60, 329, 66, 329, 74, 326, 77, 326, 85, 320, 90, 312, 88, 308, 82, 298, 78, 298, 175, 325, 175" title="Queensland">
<area shape="polygon" coords="297, 175, 297, 79, 273, 60, 286, 34, 281, 30, 276, 33, 268, 33, 254, 29, 250, 25, 247, 22, 243, 22, 244, 26, 249, 31, 246, 33, 237, 33, 235, 33, 234, 31, 236, 28, 236, 23, 231, 25, 228, 24, 225, 27, 230, 29, 233, 33, 229, 37, 223, 41, 227, 45, 222, 46, 218, 54, 221, 62, 214, 63, 213, 175" title="Northern Territory">
<area shape="polygon" coords="214, 234, 214, 61, 211, 60, 205, 65, 205, 59, 197, 50, 194, 54, 190, 52, 187, 56, 180, 56, 179, 62, 174, 64, 174, 75, 163, 74, 167, 81, 164, 85, 160, 77, 150, 82, 149, 90, 153, 93, 148, 97, 143, 108, 127, 114, 122, 113, 121, 115, 111, 120, 103, 118, 94, 125, 90, 130, 85, 132, 80, 138, 78, 136, 80, 131, 73, 138, 75, 144, 75, 148, 72, 150, 72, 160, 75, 170, 78, 176, 75, 179, 69, 172, 76, 187, 76, 193, 82, 200, 82, 205, 84, 210, 84, 218, 91, 234, 92, 241, 93, 250, 90, 253, 86, 253, 86, 261, 92, 262, 99, 269, 112, 269, 125, 263, 132, 256, 145, 254, 164, 257, 168, 248, 172, 248, 186, 241, 192, 242" title="Western Australia">
<area shape="polygon" coords="324, 299, 323, 175, 213, 175, 213, 234, 233, 232, 242, 238, 249, 236, 261, 242, 258, 246, 265, 249, 269, 256, 270, 261, 272, 263, 277, 267, 277, 261, 281, 257, 288, 254, 291, 249, 295, 246, 295, 243, 297, 250, 294, 254, 290, 259, 291, 265, 287, 269, 294, 268, 297, 262, 301, 268, 299, 272, 295, 275, 290, 273, 285, 274, 283, 277, 290, 278, 294, 275, 301, 273, 315, 286, 314, 291" title="South Australia">
<area shape='rect' coords='0,0,100,100' title='unsupported area type'>
</map>
<img id='img2'/>
</body>
</html>
Next, a working demo that you can try right here on the page (use full-screen for the best experience)
"use strict";
function byId(e){return document.getElementById(e);}
function newEl(tag){return document.createElement(tag);}
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(e)
{
createImageFromMapAreasForUseAtStackoverflow();
attachHoverHandlers();
}
// this function is only used for the purpose of answering this question.
// Ordinarily, you would set the src of #img1 to be that of your image. - since cross-origin contamination prevents
// access to the image data if the image comes from a different server, I've just opted to create the image from scratch.
//
// the original image may be found here: https://upload.wikimedia.org/wikipedia/commons/thumb/1/16/Australia_location_map_recolored.png/500px-Australia_location_map_recolored.png
function createImageFromMapAreasForUseAtStackoverflow()
{
var imgWidth = 500, imgHeight = 360;
var can = newEl('canvas');
can.width = imgWidth;
can.height = imgHeight;
var ctx = can.getContext('2d');
ctx.fillStyle = '#ecf5f6';
ctx.fillRect(0,0,imgWidth,imgHeight);
var areas = document.querySelectorAll('area');
var i, n = areas.length;
var colours = ['#f4f100', '#b2d025', '#f67c60', '#8fbce1', '#f4f236', '#fca164', '#bc9eee', 'black'];
for (i=0; i<n; i++)
{
var areaType = areas[i].getAttribute('shape');
if ((areaType == 'polygon') || (areaType == 'poly'))
drawMapPoly(areas[i].getAttribute('coords'), colours[i]);
}
byId('img1').src = can.toDataURL();
function drawMapPoly(coordStr, colour)
{
ctx.beginPath();
var ptArray = coordStrToPointArray(coordStr);
var i, n=ptArray.length;
ctx.moveTo(ptArray[0].x, ptArray[0].y);
for (i=0;i<n;i++)
ctx.lineTo(ptArray[i].x,ptArray[i].y);
ctx.closePath();
ctx.fillStyle=colour;
ctx.fill();
}
}
function attachHoverHandlers()
{
//
// Attach event-listeners to each of the areas in the image-map to handle mouseover
//
var areas = document.querySelectorAll('area');
var i, n = areas.length;
for (i=0; i<n; i++)
{
areas[i].addEventListener('mouseover', onAreaHovered, false);
}
}
function onAreaHovered(e)
{
var hoveredElement = this;
var coordStr = this.getAttribute('coords');
var areaType = this.getAttribute('shape');
switch (areaType)
{
case 'polygon':
case 'poly':
showPolyCoords(coordStr);
break;
default:
alert("You need to add a handler for areas of type '" + areaType + "'");
}
}
function coordStrToPointArray(coordStr)
{
var mCoords = coordStr.split(',');
var i, n = mCoords.length;
var coordArray = [];
coordArray.push( new p2d(mCoords[0], mCoords[1]) );
for (i=2; i<n; i+=2)
{
coordArray.push( new p2d(mCoords[i], mCoords[i+1]) );
}
coordArray.push( new p2d(mCoords[0], mCoords[1]) );
return coordArray;
}
// takes a string that contains coords eg - "227,307,261,309, 339,354, 328,371, 240,331"
// draws a line from each co-ord pair to the next - assumes starting point needs to be repeated as ending point.
function showPolyCoords(coOrdStr)
{
var coordArray = coordStrToPointArray(coOrdStr);
var sortedArray = coordArray.slice();
sortedArray.sort(sortX);
var minX = sortedArray[0].x;
var maxX = sortedArray[sortedArray.length-1].x;
sortedArray.sort(sortY);
var minY = sortedArray[0].y;
var maxY = sortedArray[sortedArray.length-1].y;
var topLeft = new p2d(minX, minY);
var botRight = new p2d(maxX, maxY);
testFuncWithClipping(topLeft, botRight, 'img1', coordArray);
}
function p2d(x, y)
{
this.x = Number(x);
this.y = Number(y);
return this;
}
// unneccesary - just makes displaying the point easier.
// Having this prototype available means that (in chrome at least)
// the code: "console.log( pt2d );" or "alert( pt2d );" will result in "<xCoord, yCoord>" being printed/alerted
p2d.prototype.toString = function()
{
return "<"+this.x+", "+this.y+">";
}
// comparison functions used when sorting the point list to obtain the min/max values of both X and Y
function sortX(a, b){return a.x - b.x;}
function sortY(a, b){return a.y - b.y;}
function testFuncWithClipping(topLeft, botRight, srcImgId, pointArray)
{
var width = botRight.x - topLeft.x;
var height = botRight.y - topLeft.y;
var can = newEl('canvas');
can.width = width;
can.height = height;
var ctx = can.getContext('2d');
var img = byId(srcImgId);
ctx.beginPath();
ctx.moveTo( pointArray[0].x - topLeft.x, pointArray[0].y-topLeft.y );
var i, n = pointArray.length;
for (i=0; i<n; i++)
{
ctx.lineTo( pointArray[i].x - topLeft.x, pointArray[i].y-topLeft.y );
}
// comment the below line to see the effect of drawing a rectangular
// portion of the image without clipping.
ctx.clip();
ctx.drawImage(img, topLeft.x, topLeft.y, width, height, 0,0, width,height);
byId('img2').src = can.toDataURL();
}
body
{
background-color: gray;
}
#canvas2
{
pointer-events: none; /* make the canvas transparent to the mouse - needed since canvas is position infront of image */
position: absolute; /* you'll need to use this trick to allow the area to know when the mouse leaves it, so you can hide/destroy the */
} /* enlarged version of the hovered area */
<!--
Usually, you would use this element.
For the purpose of making a working demo, I've used the next element and have created the picture using the map data and
the funtion createImageFromMapAreasForUseAtStackoverflow
As mentioned above, the original image is:
https://upload.wikimedia.org/wikipedia/commons/thumb/1/16/Australia_location_map_recolored.png/500px-Australia_location_map_recolored.png
which was saved as ausMap.png in the img folder of my localhost.
<img id='img1' usemap='#imgMap1' src='img/ausMap.png' />
-->
<img id='img1' usemap='#imgMap1'/>
<map name='imgMap1' id='imgMap1'>
<area shape="polygon" coords="359, 324, 373, 332, 392, 327, 393, 346, 375, 356, 364, 343" title="Tasmania">
<area shape="polygon" coords="325, 258, 335, 258, 339, 265, 346, 265, 347, 271, 357, 279, 360, 279, 361, 276, 368, 278, 380, 279, 388, 277, 390, 288, 406, 293, 405, 296, 391, 297, 377, 308, 376, 310, 372, 308, 356, 303, 350, 307, 338, 303, 332, 301, 325, 300" title="Victoria">
<area shape="polygon" coords="325, 207, 397, 206, 403, 201, 417, 203, 420, 209, 425, 205, 427, 200, 440, 197, 440, 204, 436, 222, 432, 235, 432, 241, 424, 245, 419, 255, 415, 267, 408, 277, 408, 293, 391, 286, 389, 278, 381, 279, 373, 279, 364, 276, 361, 278, 348, 271, 346, 265, 340, 266, 338, 261, 333, 258, 325, 258" title="New South Wales">
<area shape="polygon" coords="325, 206, 398, 207, 404, 201, 417, 203, 423, 207, 427, 201, 434, 198, 441, 198, 436, 169, 429, 159, 419, 150, 416, 142, 410, 138, 406, 139, 400, 121, 397, 114, 375, 101, 372, 82, 367, 79, 365, 61, 357, 52, 353, 56, 349, 39, 345, 31, 341, 22, 336, 18, 336, 27, 330, 35, 334, 38, 331, 41, 330, 46, 331, 60, 329, 66, 329, 74, 326, 77, 326, 85, 320, 90, 312, 88, 308, 82, 298, 78, 298, 175, 325, 175" title="Queensland">
<area shape="polygon" coords="297, 175, 297, 79, 273, 60, 286, 34, 281, 30, 276, 33, 268, 33, 254, 29, 250, 25, 247, 22, 243, 22, 244, 26, 249, 31, 246, 33, 237, 33, 235, 33, 234, 31, 236, 28, 236, 23, 231, 25, 228, 24, 225, 27, 230, 29, 233, 33, 229, 37, 223, 41, 227, 45, 222, 46, 218, 54, 221, 62, 214, 63, 213, 175" title="Northern Territory">
<area shape="polygon" coords="214, 234, 214, 61, 211, 60, 205, 65, 205, 59, 197, 50, 194, 54, 190, 52, 187, 56, 180, 56, 179, 62, 174, 64, 174, 75, 163, 74, 167, 81, 164, 85, 160, 77, 150, 82, 149, 90, 153, 93, 148, 97, 143, 108, 127, 114, 122, 113, 121, 115, 111, 120, 103, 118, 94, 125, 90, 130, 85, 132, 80, 138, 78, 136, 80, 131, 73, 138, 75, 144, 75, 148, 72, 150, 72, 160, 75, 170, 78, 176, 75, 179, 69, 172, 76, 187, 76, 193, 82, 200, 82, 205, 84, 210, 84, 218, 91, 234, 92, 241, 93, 250, 90, 253, 86, 253, 86, 261, 92, 262, 99, 269, 112, 269, 125, 263, 132, 256, 145, 254, 164, 257, 168, 248, 172, 248, 186, 241, 192, 242" title="Western Australia">
<area shape="polygon" coords="324, 299, 323, 175, 213, 175, 213, 234, 233, 232, 242, 238, 249, 236, 261, 242, 258, 246, 265, 249, 269, 256, 270, 261, 272, 263, 277, 267, 277, 261, 281, 257, 288, 254, 291, 249, 295, 246, 295, 243, 297, 250, 294, 254, 290, 259, 291, 265, 287, 269, 294, 268, 297, 262, 301, 268, 299, 272, 295, 275, 290, 273, 285, 274, 283, 277, 290, 278, 294, 275, 301, 273, 315, 286, 314, 291" title="South Australia">
<area shape='rect' coords='0,0,100,100' title='unsupported area type'>
</map>
<img id='img2'/>
Have fun!
I would honestly make every country its own image and rescale that on hover. Image effects aren't very well supported in JS/jQuery/CSS and if you don't want multiple images then I would start looking for a library to do that for you.
For instance you might want to consider using Pieces
Another possibility would be to use canvas or svg to draw your map and make it interactive using JS.

Efficient way of finding the 5 largest numbers in an array at any given interval

I am trying to find the five largest numbers at set intervals, while also Removing those values from the array. I need to grab the top candidates in their respective range. That range can change and the number that I need to query can also change. Is there an efficient and preferably elegant solution to this? By elegance, I mean an algorithmic (preferably hashed) approach that removes inefficient sorting or actions that do not contribute to performance on sparse and large arrays.
var arr = [101, 88, 267, 175, 154, 39, 74, 217, 31, 105, 235, 31, 14, 49, 226, 195, 134, 207, 222, 281,
262, 112, 133, 115, 0, 53, 128, 103, 88, 145, 238, 13, 204, 199, 100, 247, 292, 157, 141, 286,
72, 160, 85, 61, 57, 54, 263, 50, 125, 179, 243, 281, 39, 76, 151, 79, 1, 238, 200, 249, 35, 82,
204, 174, 293, 216, 84, 209, 170, 236, 3, 247, 25, 162, 25, 57, 49, 215, 8, 167, 180, 268,
204, 257, 134, 151, 191, 81, 77, 106, 85, 128, 52, 136, 46, 185, 229, 116, 145, 253, 258, 222,
269, 225, 101, 175, 265, 77, 32, 8, 72, 54, 111, 264, 292, 161, 91, 215, 139, 245, 73, 127, 297,
73, 258, 183, 232, 55, 199, 175, 31, 24, 21, 155, 231, 95, 40, 223, 222, 86, 115, 210, 134, 229,
211, 54, 294, 153, 52, 165, 168, 125,186, 185, 289, 188, 248, 61, 136, 15, 19, 92, 200, 80, 208,
195, 241, 85, 288, 279, 119, 247, 208, 11, 80, 111, 29, 292, 222, 289, 70, 11, 209, 25, 267, 233,
16, 289, 154, 141, 174, 30, 156, 40, 266, 139, 116, 241, 1, 101, 109, 61, 220, 265, 45, 178, 166,
102, 181, 193, 202, 133, 200, 266, 114, 222, 231, 89, 190, 29, 20, 64, 233, 261,213, 40, 161, 167,
100, 121, 288, 268, 50, 264, 78, 105, 21, 33, 79, 114, 5, 134, 56, 259, 124, 44, 134, 133, 74, 176,
65, 68, 34, 56, 2, 287, 63, 167, 299, 59, 290, 241, 104, 75, 76, 116, 225, 297, 208, 136, 265, 290,
170, 267, 10, 176, 141, 217, 195, 4, 173, 32, 150, 271, 238, 171, 195, 16, 282, 77, 62, 39, 44, 248,
270, 222, 295, 122, 190, 230];
function maxAtIntervals (intervalLength, select, xs) {
const comparator = (a, b, _) => a - b;
const temp = [];
for (var i = 0; i < xs.length; i += intervalLength) {
const interval = xs.slice(i, i + intervalLength);
temp.push(interval.sort(comparator).slice(-select));
}
return temp;
}
console.log(maxAtIntervals(20, 5, arr));
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have read #le_m's comment however finding the k largest / smallest items or the kth largest / smallest item is a complicated task in O(n). It's best implemented in sorting and taking the necessary ones from the beginning of the array.
Accordingly you may do as follows;
function segmentAndTakeMax(ar,sl,mc) { // array , segment length, max count
var tempar = Array.from({length: sl});
return Array.from({length: Math.ceil(ar.length/sl)})
.map((_,i) => tempar.map((_,j) => arr[i*sl+j])
.sort((a,b) => b-a)
.slice(0,Math.min(arr.length-i*sl,mc)));
}
var arr = Array.from(new Array(203), _ => ~~(Math.random()*100));
console.log(arr);
console.log(segmentAndTakeMax(arr,20,5));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Ok as per OP's performance concerns on V8 i have repharsed the code to use .reduce() which is much faster than .map() in V8. Here is the modified code.
function segmentAndTakeMax(arr, n, m) {
var li = arr.length-1; // last index
return arr.reduce((r,e,i,a) => i%n ? (r[r.length-1].push(e), // if i%n != 0 then do these -> push e to last sub array
i == li && (r[r.length-1] = r[r.length-1].sort((a,b) => b-a).slice(0,m)), // short circuit for if i == last index then sort and slice the last sub array
r) // return r
: (i && (r[r.length-1] = r[r.length-1].sort((a,b) => b-a).slice(0,m)), // if i%n == 0 then do these -> short circuit for if i != 0 then sort and slice the last sub array
r.push([e]), // push [e] (a new sub array) to r
r), []); // return r
}
var arr = Array.from(new Array(203), _ => ~~(Math.random()*100));
console.log(arr);
console.log(segmentAndTakeMax(arr,20,5));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories

Resources