ResponsiveStream doesn't take any event handlers nor ref
In that case you can either send feature request in their github page and use pure js.
const Component = () => {
const containerRef = useRef(null)
const onChartMouseMove = ({target, screenX, screenY}) => {
const rect = target.getBoundingClientRect(); // perhaps you'd like to get relative position of mouse from the element
console.log(rect.left - screenX, rect.top - screenY);
}
useEffect(() => {
const element = containerRef && containerRef.current;
if(element) {
const svg = element.querySelector("svg");
svg.addEventListener("mousemove", onChartMouseMove)
return () => {
svg.removeEventListener("mousemove", onChartMouseMove);
}
}
}, [containerRef])
return (
<div ref={containerRef}>
<ResponsiveStream data={series} keys={keys}/>
</div>);
};
--Edit
Unfortunately nivo
doesnt have umd bundle so I prepared a sample component rendering an xml with logic above.
Getting the color is more difficult as you have to convert svg to image then put Image on canvas via CanvasRenderingContext2D and call getImageData
Now with ImageData you have to compute index where the element is located. MouseEvent.offsetX
, MouseEvent.offsetY
can help you with that.
source
const { useState, useEffect, useRef } = React;
const getValues = () => Array(400).fill(0).map((pr, index) => ({
id: index,
row: index % 20,
column: Math.floor(index / 20),
value: index * 16000
}))
const getImageDataFromSvg = (svg) => new Promise((resolve, reject) => {
const canvas = document.createElement("canvas");
const svgXml = (new XMLSerializer()).serializeToString(svg);
const image = new Image();
image.src = "data:image/svg+xml;base64," + btoa(svgXml);
image.onload = function() {
const width = image.naturalWidth;
const height = image.naturalHeight;
canvas.width = width;
canvas.height = width;
const context = canvas.getContext('2d');
context.drawImage(image, 0, 0);
resolve(context.getImageData(0, 0, width, height));
}
})
const ResponsiveStream = () => {
const [colors, setColors] = useState(getValues());
const fill = (value) => {
return '#' + ("000000" + value.toString(16)).substr(-6);
}
return <svg width="200" height="200">
{colors.map(pr => <rect fill={fill(pr.value)} x={pr.row * 10} y={pr.column * 10} width={10} height={10} key={pr.id}></rect>)}
</svg>
}
const App = () => {
const containerRef = useRef(null)
const onChartMouseMove = ({target, offsetX, offsetY}, imageData) => {
let index = (offsetY * imageData.width + offsetX) * 4;
const [red, green, blue, alpha] = imageData.data.slice(index, index + 4);
const hex = '#' + red.toString(16)
+ green.toString(16)
+ blue.toString(16)
console.log(hex);
}
useEffect(() => {
let isUnmounted = false;
let func = null;
const element = containerRef && containerRef.current;
if(element) {
const svg = element.querySelector("svg");
getImageDataFromSvg(svg)
.then(imageData => {
if(isUnmounted) {
return;
}
func = (event) => onChartMouseMove(event, imageData)
svg.addEventListener("mousemove", func)
})
return () => {
isUnmounted = true;
svg.removeEventListener("mousemove", func);
}
}
}, [containerRef])
return <div>
<div ref={containerRef}>
<ResponsiveStream/>
</div>
</div>
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script src="https://unpkg.com/@material-ui/core@latest/umd/material-ui.development.js"></script>
<script src="https://unpkg.com/material-ui-lab-umd@4.0.0-alpha.32/material-ui-lab.development.js"></script>
<div id="root"></div>
--Edit
You have to wrap code in setTimeout
if rendering takes some time.
useEffect(() => {
let isUnmounted = false;
let func = null;
let svg = null
const element = chartRef && chartRef.current;
if (element) {
setTimeout(() => {
svg = element.querySelector("svg");
getImageDataFromSvg(svg).then(imageData => {
if (isUnmounted) {
return;
}
func = event => onChartMouseMove(event, imageData);
svg.addEventListener("mousemove", func);
});
}, 0)
return () => {
isUnmounted = true;
if(svg) {
svg.removeEventListener("mousemove", func);
}
};
}
}, [chartRef]);