I have an image contains some solar pannels, i have to track each card in each pannel, for that i use react-img-mapper to highlight over these cards, i numbered each cards from "1, 2, 3 ..., 600" from an api i get an object like this :
// simulate the data
const dumpData = {
startAt: 12,
endAt: 25,
};
startAt and endAt means the cards that should be highlighted, the problem in react-img-mapper is that the areas does not stay highlighted unless you click on it , so what i am trying to do is to create a canvas element and do some logic to determine it's position based on areas coords , to highlight over the specified areas,
here's my full example in Home.tsx:
function Home() {
const [isOpen, setIsOpen] = useState(false);
const [text, setText] = useState("");
const [zoom, setZoom] = useState(0.2);
const [mapData, setMapData] = useState<MapAreaWithName[]>(data);
const [showButtons, setShowButtons] = useState(false);
const canvasRef = useRef<HTMLCanvasElement>(null);
const containerRef = useRef<HTMLDivElement | null>(null);
// this makes image area maps responsive
useEffect(() => {
// @ts-ignore
import("image-map-resizer").then((module) => module.default());
}, []);
// my data
const dumpData = {
startAt: 12,
endAt: 25,
};
// show a Modal when click on area
const clicked = (area: any, i: number, e: any): void => {
setIsOpen(true);
for (const item of mapData) {
if (area?.name === item.name) {
setText('This a pannel num ${area?.name}' );
}
}
};
// my example to set canvas posistion but does not work properly .
useEffect(() => {
// i update my array of areas based my data
const arr = mapData.slice(dumpData.startAt, dumpData.endAt);
// setMapData(arr);
console.log(arr);
const ctx = canvasRef.current?.getContext("2d");
if (!ctx) return;
ctx.fillStyle = "#f00";
ctx.beginPath();
ctx.moveTo(arr[1].coords[2], arr[1].coords[3]);
ctx.lineTo(100, 50);
ctx.lineTo(50, 100);
ctx.lineTo(0, 90);
ctx.closePath();
ctx.fill();
}, []);
// * State handlers
const zoomIn = useCallback(() => {
setZoom((p) => p + 0.1);
}, []);
const zoomOut = useCallback(() => {
setZoom((p) => p - 0.1);
}, []);
const handleShowButtons = useCallback(() => {
setShowButtons((p) => !p);
}, []);
return (
<Fragment>
<div
style={{
zoom,
}}
className="">
<ImageMapper
src={URL}
natural
// rerenderProps={[]}
map={{ name: "my-map", areas: mapData }}
onClick={clicked}
/>
{/* TODO: draw canvas over elements based on dumpData */}
<canvas
ref={canvasRef}
className="bg-slate-500 top-[0] left-0 absolute w-full"></canvas>
</div>
<Modal isOpen={isOpen} setIsOpen={setIsOpen} render={() => <>{text}</>} />
<div className="fixed flex flex-col items-center gap-3 z-40 bottom-10 right-10">
{showButtons && (
<>
<button
type="button"
onClick={zoomIn}
className="text-gray-800 bg-gray-100 hover:bg-gray-200 focus:ring-4 focus:outline-none focus:ring-gray-300 font-medium rounded-lg text-sm p-2.5 text-center inline-flex items-center mr-2">
<PlusIcon className="h-6" />
<span className="sr-only">Icon description</span>
</button>
<button
type="button"
onClick={zoomOut}
className="text-gray-800 bg-gray-100 hover:bg-gray-200 focus:ring-4 focus:outline-none focus:ring-gray-300 font-medium rounded-full text-sm p-2.5 text-center inline-flex items-center mr-2">
<MinusIcon className="h-6" />
<span className="sr-only">Icon description</span>
</button>
</>
)}
<button
onClick={handleShowButtons}
className="bg-gray-100 rounded-xl mt-2 px-3 py-3">
<img className="h-5" src="/images/Vector.svg" alt="" />
</button>
</div>
</Fragment>
);
}
export default Home;
here's the app: https://gep-scada-2.vercel.app/ in the home page if the image did not appear just hit refresh
thanks in advance .