首先,讓我們建立一個簡單的 SVG 元件,它接受寬度和高度作為 props。這將是我們圖表的起點。
import React from "react"; const LineGraph = ({ height, width }) => { return <svg height={height} width={width}></svg>; }; export default LineGraph;
現在,讓我們加入水平穿過圖表的 X 軸。我們將使用
const drawXAxis = () => { const middleY = height / 2; return ( <line x1={0} y1={middleY} x2={width} y2={middleY} stroke={lineColor} /> ); };
我們將使用另一個
const drawYAxis = () => { const middleX = width / 2; return ( <line x1={middleX} y1={0} x2={middleX} y2={height} stroke={lineColor} /> ); };
折線圖的關鍵部分是連接不同點的線。讓我們繪製一些範例座標並使用 SVG 連接它們。
const drawPath = () => { const pathData = coordinates .map((coordinate, index) => index === 0 ? `M ${coordinate.x} ${coordinate.y}` : `L ${coordinate.x} ${coordinate.y}` ) .join(" "); return <path d={pathData} stroke={pathColor} fill="none" />; };
我們可以用顏色填滿線下方的區域來增強圖形。這可以使用附加元件來完成。考慮 prop isFillArea 來顯示/隱藏該區域。
const drawPath = () => { const pathData = coordinates .map((coordinate, index) => index === 0 ? `M ${coordinate.x} ${coordinate.y}` : `L ${coordinate.x} ${coordinate.y}` ) .join(" "); const middleY = height / 2; const svgPath = showFillArea ? `${pathData} L ${width} ${middleY} L 0 ${middleY} Z` : pathData; const fillColor = showFillArea ? areaColor : "none"; return ( <path d={svgPath} fill={fillColor} stroke={pathColor} opacity="0.5" /> ); };
讓我們加入一個跟隨遊標在圖形路徑上移動的圓圈。
我們需要 SVG 元件的參考來存取 SVG 元素的邊界框。也是我們的追蹤圓的參考,它將用於追蹤圖表上的遊標。
const svgRef = useRef(); const circleRef = useRef(); // ... const drawTrackingCircle = () => { return ( <circle ref={circleRef} r={6} fill="red" style={{ display: "none" }} // Initially hidden /> ); }; // ... <svg ref={svgRef} width={width} height={height}> // ... </svg>
然後,我們需要在 SVG 元素中新增一個事件監聽器。這將監聽我們在圖表上的所有遊標移動。
useEffect(() => { const svgElement = svgRef.current; svgElement.addEventListener("mousemove", handleMouseMove); // clean up return () => svgElement.removeEventListener("mousemove", handleMouseMove); }, []);
接下來,我們需要一個方法來找到遊標位置和路徑之間的交點座標。
const getIntersectionPoint = (cursorX) => { // Find the segment (p1, p2) where cursorX lies between two consecutive coordinates. const segment = coordinates.find((p1, i) => { // Get the next point const p2 = coordinates[i + 1]; // Check if cursorX falls between the two coordinates horizontally. return ( p2 && ((p1.x <= cursorX && p2.x >= cursorX) || (p1.x >= cursorX && p2.x <= cursorX)) ); }); // Return null if no valid segment is found. if (!segment) return null; // Destructure the two coordinates in the segment. const [p1, p2] = [segment, coordinates[coordinates.indexOf(segment) + 1]]; // Calculate 't' to determine the relative position between p1 and p2. const t = (cursorX - p1.x) / (p2.x - p1.x); // Interpolate the Y-coordinate using 't'. const y = p1.y + t * (p2.y - p1.y); return { x: cursorX, y }; };
遊標移動追蹤方法。它使用 getIntersectionPoint 方法來尋找目前交叉點座標。
const handleMouseMove = (event) => { // Get SVG position const svgRect = svgRef.current.getBoundingClientRect(); // Calculate cursor's X within the SVG const cursorX = event.clientX - svgRect.left; // Find the intersection point const intersectionPoint = getIntersectionPoint(cursorX); if (intersectionPoint) { // Move the intersection circle to the calculated point circleRef.current.setAttribute("cx", intersectionPoint.x); circleRef.current.setAttribute("cy", intersectionPoint.y); circleRef.current.style.display = "block"; } };
最後,這就是我們的圖形組件的結構
return ( <svg ref={svgRef} height={height} width={width}> {drawPath()} {drawXAxis()} {drawYAxis()} {drawTrackingCircle()} {drawDataPointCircles()} </svg> );
這就是我們使用圖表組件的方式
<LineGraph width={300} height={400} coordinates={samplePoints} lineColor="#000" pathColor="#00008B" areaColor="#ADD8E6" dataPointColor="#008000" showFillArea showDataPointCircle />
LineGraph 示範的 Codesandbox 連結
Isaac Smith 在 Unsplash 上的部落格照片
感謝您的閱讀❤
以上是在 ReactJS 中建立您自己的互動式線圖的詳細內容。更多資訊請關注PHP中文網其他相關文章!