Core::Graphics: Canvas2D: Canvas API to read pixel data doesn't work
Categories
(Core :: Graphics: Canvas2D, defect, P3)
Tracking
()
People
(Reporter: reza.bakhshi1381r, Unassigned, NeedInfo)
References
()
Details
(Keywords: webcompat:needs-diagnosis, webcompat:site-report)
User Story
platform:windows,mac,linux,android impact:feature-broken configuration:general affects:all branch:release diagnosis-team:dom
Attachments
(2 files)
User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36
Steps to reproduce:
https://fazayesh.spaceomid.com
This is the website that I develope myself, I'm using React-leaflet to display png images of NDVI value in a tooltip by mousemove event handler from ImageOverlay. I use Canvas API for getting pixel RGB data and a Map to give the color and return related NDVI value, the feature works correct in Chrome and Edge as I checked.
you can see an example code in stack overflow: https://stackoverflow.com/questions/77631436/how-to-read-pixel-values-of-an-imageoverlay-in-react-leaflet-by-mousemove-event
Actual results:
When I move the mouse over the image, it should open a tooltip and show a different value for each RGB pixel, but it only shows the default Map object string value.
Expected results:
It should read each pixel value and extract RGB and then give it to the Map object of predefined colors and return value to be displayed in a tooltip. please check the stack overflow link which I put in first text area.
React.js component:
import { useRef, useState } from "react"
import { ImageOverlay, SVGOverlay, Tooltip } from "react-leaflet"
import { useSelector } from "react-redux"
import { ndmiMap, ndviMap } from "./utils/statics"
export default function ImageEvents() {
const activeField = useSelector(store => store.userFarms.activeField)
const socketData = useSelector(store => store.socketCluster)
const selectedDay = useSelector(store => store.userFarms.selectedDay)
const imageRef = useRef()
const [tooltip, setTooltip] = useState(1)
function rgbToHex(rgb) {
const hex = rgb.replace(/[^\d,]/g, "").split(",")
const r = parseInt(hex[0], 10).toString(16).padStart(2, "0")
const g = parseInt(hex[1], 10).toString(16).padStart(2, "0")
const b = parseInt(hex[2], 10).toString(16).padStart(2, "0")
return `#${r}${g}${b}`
}
const onHover = event => {
const canvas = document.createElement("canvas")
canvas.style.display = "none"
const ctx = canvas.getContext("2d")
const image = imageRef.current._image
const width = image.width
const height = image.height
const x = event.originalEvent.offsetX
const y = event.originalEvent.offsetY
image.crossOrigin = "Anonymous" // Set the crossOrigin attribute of the image
canvas.width = width
canvas.height = height
ctx.drawImage(image, 0, 0, width, height)
const pixelData = ctx.getImageData(x, y, 1, 1).data
const hexColor = rgbToHex(`rgb(${pixelData[0]}, ${pixelData[1]}, ${pixelData[2]})`)
socketData.imageIndicator === "ndvi"
? setTooltip(ndviValue => ndviMap.get(hexColor) ?? ndviValue)
: setTooltip(ndmiValue => ndmiMap.get(hexColor) ?? ndmiValue)
}
const debounce = (func, delay) => {
let timeoutId
return (...args) => {
clearTimeout(timeoutId)
timeoutId = setTimeout(() => {
func(...args)
}, delay)
}
}
const debouncedOnHover = debounce(onHover, 10) // Adjust the debounce delay as needed
return (
<>
{socketData.data &&
activeField &&
activeField.farm_id &&
selectedDay &&
socketData.data[activeField.farm_id] &&
socketData.data[activeField.farm_id][selectedDay] &&
socketData.data[activeField.farm_id][selectedDay].base64_encode ? (
<ImageOverlay
url={socketData.data[activeField.farm_id][selectedDay].base64_encode}
crossOrigin={"anonymous"}
bounds={activeField.bbox}
key={activeField.bbox[0][0]}
ref={imageRef}
id={"image-ndvi"}
opacity={socketData.imageIndicator === "nolayer" ? 0 : 1}
interactive={true}
eventHandlers={{
mousemove: debouncedOnHover,
click: onHover,
}}
>
{(tooltip !== undefined || tooltip !== 0) && <Tooltip sticky>{tooltip}</Tooltip>}
</ImageOverlay>
) : activeField.bbox && socketData.imageIndicator !== "nolayer" ? (
<SVGOverlay
attributes={{
width: "40",
height: "40",
viewBox: "-30 -30 100 100",
}}
bounds={activeField.bbox}
>
<defs>
<linearGradient x1="8.042%" y1="0%" x2="65.682%" y2="23.865%" id="a">
<stop stopColor="#D6AD60" stopOpacity="0" offset="0%" />
<stop stopColor="#D6AD60" stopOpacity=".631" offset="63.146%" />
<stop stopColor="#D6AD60" offset="100%" />
</linearGradient>
</defs>
<g fill="none" fillRule="evenodd">
<g transform="translate(1 1)">
<path d="M36 18c0-9.94-8.06-18-18-18" id="Oval-2" stroke="url(#a)" strokeWidth="2">
<animateTransform
attributeName="transform"
type="rotate"
from="0 18 18"
to="360 18 18"
dur="0.9s"
repeatCount="indefinite"
/>
</path>
<circle fill="#D6AD60" cx="36" cy="18" r="1">
<animateTransform
attributeName="transform"
type="rotate"
from="0 18 18"
to="360 18 18"
dur="0.9s"
repeatCount="indefinite"
/>
</circle>
</g>
</g>
</SVGOverlay>
) : null}
</>
)
}
Map variable values:
export const ndviMap = new Map([
["#ffffff", "ابر"],
["#000000", "وارد محدوده رنگی شوید"],
["#ff0303", "0.01, بدون پوشش"],
["#ff0b05", "0.02, بدون پوشش"],
["#ff1308", "0.03, بدون پوشش"],
["#ff1b0b", "0.04, بدون پوشش"],
["#ff230d", "0.05, بدون پوشش"],
["#ff2b10", "0.06, بدون پوشش"],
["#ff3313", "0.07, بدون پوشش"],
["#ff3413", "0.07, بدون پوشش"],
["#ff3a15", "0.08, بدون پوشش"],
["#fe4a1a", "0.08, بدون پوشش"],
["#ff3212", "0.08, بدون پوشش"],
["#ff4318", "0.09, بدون پوشش"],
["#ff4b1b", "0.1, بدون پوشش"], // 0.1
["#ff531e", "0.11, بدون پوشش"],
["#fd5c20", "0.12, بدون پوشش"],
["#fc6722", "0.11, بدون پوشش"],
["#fc6522", "0.13, بدون پوشش"],
["#fb6e24", "0.14, بدون پوشش"],
["#f97726", "0.15, بدون پوشش"],
["#f88128", "0.16, بدون پوشش"],
["#f78a2a", "0.17, بدون پوشش"],
["#f5932c", "0.18, بدون پوشش"],
["#f49c2e", "0.19, بدون پوشش"],
["#f3a530", "0.2, تراکم پایین"], // 0.2
["#f0aa2f", "0.21, تراکم پایین"],
["#f2af33", "0.21, تراکم پایین"],
["#efb331", "0.21, تراکم پایین"],
["#eeb530", "0.22, تراکم پایین"],
["#eabc2e", "0.23, تراکم پایین"],
["#ebb92f", "0.23, تراکم پایین"],
["#e6c32b", "0.24, تراکم پایین"],
["#e9bd2d", "0.24, تراکم پایین"],
["#e2c929", "0.25, تراکم پایین"],
["#e2c829", "0.25, تراکم پایین"],
["#ded027", "0.26, تراکم پایین"],
["#e1ca29", "0.26, تراکم پایین"],
["#dfce28", "0.27, تراکم پایین"],
["#dad724", "0.27, تراکم پایین"],
["#d6dd22", "0.28, تراکم پایین"],
["#d2e41f", "0.29, تراکم پایین"],
["#ceeb1d", "0.3, تراکم متوسط"], // 0.3
["#cbf21b", "0.31, تراکم متوسط"],
["#c3ef1a", "0.32, تراکم متوسط"],
["#bced1a", "0.33, تراکم متوسط"],
["#b5eb19", "0.34, تراکم متوسط"],
["#ade819", "0.35, تراکم متوسط"],
["#a6e618", "0.36, تراکم متوسط"],
["#9fe418", "0.37, تراکم متوسط"],
["#97e117", "0.38, تراکم متوسط"],
["#90df17", "0.39, تراکم متوسط"],
["#89dd16", "0.4, تراکم متوسط"], // 0.4
["#82db16", "0.41, تراکم متوسط"],
["#7ad715", "0.42, تراکم متوسط"],
["#72d415", "0.43, تراکم متوسط"],
["#6ad114", "0.44, تراکم متوسط"],
["#63cd14", "0.45, تراکم متوسط"],
["#5bca13", "0.46, تراکم متوسط"],
["#53c713", "0.47, تراکم متوسط"],
["#4cc312", "0.48, تراکم متوسط"],
["#44c012", "0.49, تراکم متوسط"],
["#3cbd11", "0.5, تراکم بالا"], // 0.5
["#35ba11", "0.51, تراکم بالا"],
["#32b310", "0.52, تراکم بالا"],
["#2fad0f", "0.53, تراکم بالا"],
["#2ca70d", "0.54, تراکم بالا"],
["#29a10d", "0.55, تراکم بالا"],
["#279b0c", "0.56, تراکم بالا"],
["#24950b", "0.57, تراکم بالا"],
["#218f0a", "0.58, تراکم بالا"],
["#1e8909", "0.59, تراکم بالا"],
["#1b8308", "0.6, تراکم بالا"], // 0.6
["#45a10b", "0.61, تراکم بالا"],
["#409d0a", "0.62, تراکم بالا"],
["#3c990a", "0.63, تراکم بالا"],
["#379609", "0.64, تراکم بالا"],
["#339209", "0.65, تراکم بالا"],
["#2f8f09", "0.66, تراکم بالا"],
["#2a8b08", "0.67, تراکم بالا"],
["#268708", "0.68, تراکم بالا"],
["#218407", "0.69, تراکم بالا"],
["#1d8007", "0.7, تراکم بالا"], // 0.7
["#197d07", "0.71, تراکم بالا"],
["#177806", "0.72, تراکم بالا"],
["#157305", "0.73, تراکم بالا"],
["#136e04", "0.74, تراکم بالا"],
["#116904", "0.75, تراکم بالا"],
["#0f6503", "0.76, تراکم بالا"],
["#0d6002", "0.77, تراکم بالا"],
["#0b5b02", "0.78, تراکم بالا"],
["#095601", "0.79, تراکم بالا"],
["#075100", "0.8, تراکم بالا"], // 0.8
["#064d00", "0.81, تراکم بالا"],
["#054b00", "0.82, تراکم بالا"],
["#054a00", "0.83, تراکم بالا"],
["#054800", "0.84, تراکم بالا"],
["#054700", "0.85, تراکم بالا"],
["#054600", "0.86, تراکم بالا"],
["#054400", "0.87, تراکم بالا"],
["#054300", "0.88, تراکم بالا"],
["#054100", "0.89, تراکم بالا"],
["#054000", "0.9, تراکم بالا"], // 0.9
["#053f00", "0.91, تراکم بالا"],
["#053d00", "0.92, تراکم بالا"],
["#053c00", "0.93, تراکم بالا"],
["#053a00", "0.94, تراکم بالا"],
["#053900", "0.95, تراکم بالا"],
["#053800", "0.96, تراکم بالا"],
["#053600", "0.97, تراکم بالا"],
["#053500", "0.98, تراکم بالا"],
["#053300", "0.99, تراکم بالا"],
["#053200", "1.0, تراکم بالا"], // 1.0
])
export const ndmiMap = new Map([
["#ffffff", "ابر"],
["#b29f99", "0.00"],
["#b3a09b", "0.01"],
["#b4a19d", "0.02"],
["#b5a29f", "0.03"],
["#b6a4a1", "0.04"],
["#b8a5a3", "0.05"],
["#b9a6a5", "0.06"],
["#baa8a7", "0.07"],
["#bba9a9", "0.08"],
["#bcaaab", "0.09"],
["#beacad", "0.10"],
["#bfadae", "0.11"],
["#c1aeb0", "0.12"],
["#c2afb1", "0.13"],
["#c4b0b3", "0.14"],
["#c5b2b4", "0.15"],
["#c7b3b6", "0.16"],
["#c8b4b7", "0.17"],
["#cab5b9", "0.18"],
["#cbb6ba", "0.19"],
["#cdb8bc", "0.20"],
["#ceb8bd", "0.21"],
["#cfb9bf", "0.22"],
["#d0bac1", "0.23"],
["#d1bbc3", "0.24"],
["#d3bcc5", "0.25"],
["#d4bdc6", "0.26"],
["#d5bec8", "0.27"],
["#d6bfca", "0.28"],
["#d7c0cc", "0.29"],
["#d9c1ce", "0.30"],
["#d6bfcf", "0.31"],
["#d3bdd0", "0.32"],
["#d0bbd1", "0.33"],
["#cdb9d2", "0.34"],
["#cab7d3", "0.35"],
["#c7b5d4", "0.36"],
["#c4b3d5", "0.37"],
["#c1b1d6", "0.38"],
["#beafd7", "0.39"],
["#bcaed9", "0.40"],
["#b8abd9", "0.41"],
["#b4a9d9", "0.42"],
["#b1a7d9", "0.43"],
["#ada5d9", "0.44"],
["#aaa3d9", "0.45"],
["#a6a0d9", "0.46"],
["#a29ed9", "0.47"],
["#9f9cd9", "0.48"],
["#9b9ad9", "0.49"],
["#9898d9", "0.51"],
["#9495d9", "0.52"],
["#9192d9", "0.53"],
["#8d8fd9", "0.54"],
["#8a8cd9", "0.55"],
["#8789d9", "0.56"],
["#8386d9", "0.57"],
["#8083d9", "0.58"],
["#7c80d9", "0.59"],
["#797dd9", "0.60"],
["#767ada", "0.61"],
["#7277da", "0.62"],
["#6f75da", "0.63"],
["#6c72da", "0.64"],
["#6870db", "0.65"],
["#656edb", "0.66"],
["#626bdb", "0.67"],
["#5e69dc", "0.68"],
["#5b66dc", "0.69"],
["#5864dc", "0.70"],
["#5562dd", "0.71"],
["#515fdd", "0.72"],
["#4e5cdd", "0.73"],
["#4a5ade", "0.74"],
["#4757de", "0.75"],
["#4455df", "0.76"],
["#4052df", "0.77"],
["#3d4fdf", "0.78"],
["#394de0", "0.79"],
["#364ae0", "0.80"],
["#3348e1", "0.81"],
["#2f45e0", "0.82"],
["#2c42e0", "0.83"],
["#293fe0", "0.84"],
["#263de0", "0.85"],
["#233ae0", "0.86"],
["#2037e0", "0.87"],
["#1d35e0", "0.88"],
["#1a32e0", "0.89"],
["#172fe0", "0.90"],
["#142de0", "0.91"],
["#142be0", "0.92"],
["#142ae0", "0.93"],
["#1429e0", "0.94"],
["#1428e0", "0.95"],
["#1427e0", "0.96"],
["#1426e0", "0.97"],
["#1425e0", "0.98"],
["#1424e0", "0.99"],
["#1423e0", "1"],
])
Comment 3•18 days ago
|
||
The Bugbug bot thinks this bug should belong to the 'Core::Graphics: Canvas2D' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.
Updated•13 days ago
|
Comment 5•13 days ago
|
||
Is it possible to get a standalone test case that shows the problem?
(In reply to Jeff Muizelaar [:jrmuizel] from comment #5)
Is it possible to get a standalone test case that shows the problem?
Here is a standalone test case to view the error on FireFox, You can fork the repo and run it on your desktop.
Github rep: Link
Comment 7•8 days ago
|
||
I can reproduce it with that test case. It looks like problem might be that offsetX and offsetY are always 0
There are two warnings in the console, which indicate:
- MouseEvent.mozPressure is deprecated. Use PointerEvent.pressure instead. (Util.js:15:3)
- MouseEvent.mozInputSource is deprecated. Use PointerEvent.pointerType instead. (Util.js:15:3)
Comment 9•6 days ago
|
||
Tom, is this related to the TikTok captcha thing?
Comment 10•6 days ago
|
||
https://bugzilla.mozilla.org/show_bug.cgi?id=505521 is a candidate bug here.
Updated•2 days ago
|
Description
•