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();
}
});
}
};
Bash alternative (shell set to UTF8):
Input:
in.json
$ file -I in.json
in.json: text/plain; charset=utf-8
{"it-it":"Città"}
Bash command I need the JS alternative for:
$ iconv -f utf8 -t latin1 in.json > out.json
out.json
$ file -I in.json
out.json: text/plain; charset=iso-8859-1
{"it-it":"Citt?"}
What Javascript sees in browser for in.json when read as base64 from an input type="file" (despite content-type and script encoding set to utf8):
{"it-it":"Città "}
What Javascript sees in browser for out.json:
{"it-it":"Città"}
Question - how can I make in the most native Javascript way to make most modern browsers convert this utf8 string
({"it-it":"Città "} as latin1 and {"it-it":"Città"} as utf8)
to a latin1 string?
I prefer a native solution, or worst case JQuery, please try not to solve it with an npm + node dependency hell.
P.s.: I only need to support the most modern browsers, this is for an admin-only page.
Below I've created an array with iso-8859-1version of CittÃ, and then used TextDecoder to decode it,.
So if you can get the binary version of the JSON, this should be able to convert for you.
//CittÃ
var latinSource = new Uint8Array([67, 105, 116, 116, 195]);
var tc = new TextDecoder("iso-8859-1");
console.log(tc.decode(latinSource));
For me, 'new TextDecoder("iso-8859-1")' not working...
1.
var latinSource = new Uint8Array([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]);
var tc = new TextDecoder("iso-8859-1");
console.log(tc.decode(latinSource)); //return windows-1252 string
I see, the result, it's not a latin1 string, because this contains character '€'.
2.
//windows-1252
console.log('new TextDecoder("iso-8859-1")', new TextDecoder("iso-8859-1"));
// ---->
//new TextDecoder("iso-8859-1") {
// "encoding": "windows-1252",
// "fatal": false,
// "ignoreBOM": false,
// "decode": function decode() { [native code] }
//}
Working way to encode-decode latin-1:
//Decode Latin1-string (iso-8859-1 encoded string) -> into Uint8Array
function Latin1ToUint8Array(iso_8859_1){
var uInt8Arr = new Uint8Array(iso_8859_1.length);
for(var i=0; i<iso_8859_1.length; i++){
uInt8Arr[i] = iso_8859_1.charCodeAt(i);
}
return uInt8Arr;
}
//encode Uint8Array -> into iso-8859-1 encoded string (latin1-string)
function Uint8ToLatin1Str(Uint8Arr){
var iso_8859_1_string = '';
for(var i=0; i<Uint8Arr.length; i++){iso_8859_1_string+= String.fromCharCode(Uint8Arr[i]);}
return iso_8859_1_string;
}
var latinSource = new Uint8Array([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]);
console.log( Uint8ToLatin1Str(latinSource) ); //valid latin1-string (iso-8859-1)
Finally, Windows-1252 conversions:
function Windows1252EncodeDecode(
cp1252 //string (to encode into bytes), or Uint8Array (to decode into string)
){
var replaceCharCodesForLatin1 = {
//_______________________________________________________________________
//|"windows-1252"| iso-8859-1 | //Unicode |
//|'character' | charcode, | //charcode(commented), |
//|______________|______________________|_______________________________|
'€' : 128, //8364,
'‚' : 130, //8218,
'ƒ' : 131, //402,
'„' : 132, //8222,
'…' : 133, //8230,
'†' : 134, //8224,
'‡' : 135, //8225,
'ˆ' : 136, //710,
'‰' : 137, //8240,
'Š' : 138, //352,
'‹' : 139, //8249,
'Œ' : 140, //338,
'Ž' : 142, //381,
'‘' : 145, //8216,
'’' : 146, //8217,
'“' : 147, //8220,
'”' : 148, //8221,
'•' : 149, //8226,
'–' : 150, //8211,
'—' : 151, //8212,
'˜' : 152, //732,
'™' : 153, //8482,
'š' : 154, //353,
'›' : 155, //8250,
'œ' : 156, //339,
'ž' : 158, //382,
'Ÿ' : 159, //376
};
if(typeof cp1252 === 'string'){ //if that was been string to encode to bytes
var resultUint8 = new Uint8Array(cp1252.length);
for(var i = 0; i<cp1252.length; i++){
var charCode = cp1252[i].charCodeAt(0);
resultUint8[i] = ((charCode>256) ? replaceCharCodesForLatin1[cp1252[i]] : charCode);
}
return resultUint8; //return Uint8Array
}else if(cp1252 instanceof Uint8Array){ //else if that was been Uint8Array to decode to string
var resultString = "";
for(var i = 0; i<cp1252.length; i++){
var charCode = (Object.keys(replaceCharCodesForLatin1).find(key => replaceCharCodesForLatin1[key] === cp1252[i]));
charCode = (typeof charCode === 'undefined') ? String.fromCharCode(cp1252[i]) : charCode;
resultString += charCode;
}
return resultString; //return Uint8Array
}
}
var latinSource = new Uint8Array([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]);
var windows1252 = new TextDecoder("iso-8859-1").decode(latinSource); //windows-1252 string on output
console.log('new TextDecoder("iso-8859-1").decode(latinSource)', (new TextDecoder("iso-8859-1").decode(latinSource)))
var bytesBack = Windows1252EncodeDecode(windows1252);
console.log('bytesBack', bytesBack.toString());
var Windows1252StringBack = Windows1252EncodeDecode(bytesBack)
console.log('string back', Windows1252StringBack);
console.log('Compare with TextDecoder', (Windows1252StringBack === windows1252 ));
Modification of latin-1 functions, from 3:
function isLatin1String(str){return (str.match(/[^\u0000-\u00FF]/) === null);} //check is string "iso-8859-1"-encoded or not (true/false)
//Decode Latin1 or utf-8 string -> into Uint8Array
function StringToUint8Array(str){
if(!isLatin1String(str)){
return new TextEncoder("utf-8").encode(str); //encode to bytes as utf-8
}
//else, as ASCII-compatible latin1-string
var uInt8Arr = new Uint8Array(str.length);
for(var i=0; i<str.length; i++){
uInt8Arr[i] = str.charCodeAt(i);
}
return uInt8Arr;
}
//encode Uint8Array -> to latin1-string
function Uint8ToStr(Uint8Arr){
var iso_8859_1_string = '';
for(var i=0; i<Uint8Arr.length; i++){iso_8859_1_string+= String.fromCharCode(Uint8Arr[i]);}
return iso_8859_1_string;
}
function latin1ToUtf8(latin1str){
return new TextDecoder("utf-8").decode(StringToUint8Array(latin1str));
}
console.log('StringToUint8Array("CittÃ")', StringToUint8Array("CittÃ")); //Latin1
console.log('StringToUint8Array("Città€")', StringToUint8Array("Città€")); //utf-8
console.log('Uint8ToStr(StringToUint8Array("CittÃ"))', Uint8ToStr(StringToUint8Array("CittÃ"))); //latin1
console.log('Uint8ToStr(StringToUint8Array("Città"))', Uint8ToStr(StringToUint8Array("Città€"))); //utf-8
console.log('latin1ToUtf8(Uint8ToStr(StringToUint8Array("Città€")))', latin1ToUtf8(Uint8ToStr(StringToUint8Array("Città€")))); //utf-8
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.
How do i create from the following code ?
var x = [12, 155, 177];
var y = [120, 175, 255];
var z = [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];
var value = [];
for (var i = 0; i < x.length; i++) {
for (var index = x[i]; index < y[i]; index++) {
value.push(z[index]);
}
}
console.log(value);
this code generate a one dimensional array from 12 to 12 , 155 to 175 and 177 to 255
RESULT : [13 ,.....,120 , 155 ,.......,175 , 177 ,.........,255]
what i want to do is create another array in this array to get
[[13....120] , [155,.....,175] , [175,.....,255]] ;
jsfiddle : http://jsfiddle.net/minagabriel/SK2vJ/
THANKS
Try this
var x = [12, 155, 177];
var y = [120, 175, 255];
var z = [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];
var value = [];
for (var i = 0; i < x.length; i++) {
var temp = []
for (var index = x[i]; index < y[i]; index++) {
temp.push(z[index]);
}
value.push(temp);
}
console.log(value);
I'm not quite following exactly what you want to do, but here's some info which should help.
JavaScript doesn't have multi-dimensional arrays. (In fact, JavaScript arrays aren't really arrays at all.) But you can have an array which has arrays as element values. So:
var i, j, a, sub;
// Create the main array
a = [];
// This loop creates the outermost level
for (i = 0; i < 10; ++i) {
// Here we create the array to store in a[i]:
sub = [];
// This loop builds it up
for (j = 0; j < 20; ++j) {
sub[j] = "I'm the element at a[" + i + "][" + j + "]"; // Just a sample value
}
// Remember this sub-array
a[i] = sub;
}
console.log("a[1][12] = " + a[1][12]); // "I'm the element at a[1][12]"
Key notes on the above:
You have to create each of the subordinate arrays in the loop
You don't have to pre-allocate or anything like that, you can extend an array just by assigning to an element. (push also works. It's a teeny bit slower, but that usually doesn't matter.)
Something like this should work. I also used a for loop to generate the z array instead of writing it out manually.
var x = [12, 155, 177], y = [120, 175, 255], z = [], value = [];
// generate z, 1 to 300
for(var i = 1; i<=300; i++) {
z.push(i);
}
for(var i = 0, len = x.length; i < len; i++) {
var arr = [];
for(var j = 0; j < y[i]; j++) {
arr.push(z[j]);
}
value.push(arr);
}
The javascript function charCodeAt() will convert a character to the UNICODE numeric.
If, instead, I want to find the windows-1252 numeric code of a character, how can I do that?
Thanks,
Are you looking for Windows1251 to Unicode:
var winEncToUni = [
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,
8364, 129, 8218, 402, 8222, 8230, 8224, 8225,
710, 8240, 352, 8249, 338, 141, 381, 143,
144, 8216, 8217, 8220, 8221, 8226, 8211, 8212,
732, 8482, 353, 8250, 339, 157, 382, 376,
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
];
use for example as String.fromCharCode(winEncToUni[65]) (returns A)
or perhaps Unicode to Windows1251?
function toWindows1252(string, replacement)
{
var ret = new Array(string.length);
var i, ch;
replacement = typeof replacement === "string" && replacement.length > 0 ? replacement.charCodeAt(0) : 0;
for (i = 0; i < string.length; i++)
{
ch = string.charCodeAt(i);
if (ch <= 0x7F || (ch >= 0xA0 && ch <= 0xFF))
{
ret[i] = ch;
}
else
{
ret[i] = toWindows1252.table[string[i]];
if (typeof ret[i] === "undefined")
{
ret[i] = replacement;
}
}
}
return ret;
}
toWindows1252.table = {
'\x81': 129, '\x8d': 141, '\x8f': 143, '\x90': 144,
'\x9d': 157, '\u0152': 140, '\u0153': 156, '\u0160': 138,
'\u0161': 154, '\u0178': 159, '\u017d': 142, '\u017e': 158,
'\u0192': 131, '\u02c6': 136, '\u02dc': 152, '\u2013': 150,
'\u2014': 151, '\u2018': 145, '\u2019': 146, '\u201a': 130,
'\u201c': 147, '\u201d': 148, '\u201e': 132, '\u2020': 134,
'\u2021': 135, '\u2022': 149, '\u2026': 133, '\u2030': 137,
'\u2039': 139, '\u203a': 155, '\u20ac': 128, '\u2122': 153
};
document.write(toWindows1252('Hello World àèéìòù'));
I have shortened the table quite much: the first half of the codes (0x00-0x7F) are equal in all the codepages (and in Unicode), and the sequence 0xA0-0xFF are equal in Unicode and Windows-1252.