Related
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();
}
});
}
};
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.
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
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.
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; }