8 changed files with 1829 additions and 101 deletions
-
54src/pages/measure/components/MeasureAction.tsx
-
109src/pages/measure/components/graph/MarkLayer.tsx
-
126src/pages/measure/components/graph/RealtimeLayer.tsx
-
59src/pages/measure/components/graph/StandardLayer.tsx
-
33src/services/socket.ts
-
20src/services/wsTypes.ts
-
26src/utils/index.ts
-
1503src/utils/measure.json
@ -1,31 +1,88 @@ |
|||
import { useCallback, useEffect, useRef } from "react"; |
|||
import { calculatePointOnCircle, findSymmetricPoint } from "../../../../utils"; |
|||
|
|||
const marks = [ |
|||
{ x: 9.949007022412, y: 0.1650166186941, degree: -80 }, |
|||
{ x: 25.35, y: 2.184814802617, degree: -60 }, |
|||
{ x: -9.949007022412, y: 0.1650166186941, degree: -100 }, |
|||
{ x: -25.35, y: 2.184814802617, degree: -120 }, |
|||
]; |
|||
|
|||
export default function MarkLayer(props: { |
|||
width: number; |
|||
height: number; |
|||
leftPadding: number; |
|||
rightPadding: number; |
|||
topPadding: number; |
|||
bottomPadding: number; |
|||
width: number; |
|||
height: number; |
|||
leftPadding: number; |
|||
rightPadding: number; |
|||
topPadding: number; |
|||
bottomPadding: number; |
|||
columns: number; |
|||
rows: number; |
|||
}) { |
|||
const canvasRef = useRef<HTMLCanvasElement | null>(null); |
|||
const draw = useCallback((ctx: CanvasRenderingContext2D) => { |
|||
// 使用context对象进行绘图
|
|||
ctx.fillStyle = "skyblue"; // 设置填充颜色
|
|||
ctx.fillRect(50, 50, 150, 100); // 绘制一个矩形
|
|||
}, []); |
|||
useEffect(() => { |
|||
const canvas = canvasRef.current; |
|||
if (!canvas) return; |
|||
|
|||
const context = canvas.getContext("2d"); |
|||
if (!context) return; |
|||
draw(context); |
|||
}, [draw]); |
|||
|
|||
return ( |
|||
<div> |
|||
<canvas ref={canvasRef} width={props.width} height={props.height}></canvas> |
|||
</div> |
|||
); |
|||
const xStartPx = props.leftPadding; |
|||
const xEndPx = props.width - props.rightPadding; |
|||
const xStepPx = (props.width - props.leftPadding - props.rightPadding) / props.columns; |
|||
const yStartPx = props.topPadding; |
|||
// const yEndPx = props.height - props.bottomPadding;
|
|||
const yStepPx = (props.height - props.topPadding - props.bottomPadding) / props.rows; |
|||
|
|||
const unitPx = xStepPx / 10; |
|||
const canvasRef = useRef<HTMLCanvasElement | null>(null); |
|||
|
|||
const calcPoints = useCallback( |
|||
(arr: typeof marks) => { |
|||
return arr.map(p => { |
|||
const p1 = calculatePointOnCircle(p.x * unitPx, p.y * unitPx, xStepPx / 2, p.degree); |
|||
const p2 = findSymmetricPoint(p1.x, p1.y, p.x * unitPx, p.y * unitPx); |
|||
// 角度文本,向外偏移
|
|||
const p3 = calculatePointOnCircle(p.x * unitPx, p.y * unitPx, xStepPx / 2 + 10, p.degree); |
|||
return [p1, p2, p3]; |
|||
}); |
|||
}, |
|||
[unitPx, xStepPx] |
|||
); |
|||
|
|||
const draw = useCallback( |
|||
(ctx: CanvasRenderingContext2D) => { |
|||
// 偏移原点
|
|||
const xOffset = (xEndPx - xStartPx) / 2; |
|||
const yOffset = yStepPx * 2; |
|||
ctx.translate(xStartPx + xOffset, yStartPx + yOffset); |
|||
|
|||
ctx.fillStyle = "#333333"; |
|||
ctx.textAlign = "center"; |
|||
ctx.font = "normal 14px system"; |
|||
|
|||
const lines = calcPoints(marks); |
|||
for (let idx = 0; idx < lines.length; idx++) { |
|||
const line = lines[idx]; |
|||
ctx.moveTo(line[0].x, line[0].y); |
|||
ctx.lineTo(line[1].x, line[1].y); |
|||
|
|||
ctx.save(); |
|||
ctx.translate(line[2].x, line[2].y); |
|||
ctx.rotate(((marks[idx].degree + 90) * Math.PI) / 180); |
|||
ctx.fillText(`${-marks[idx].degree}°`, 0, 0); |
|||
ctx.restore(); |
|||
} |
|||
ctx.stroke(); |
|||
// ctx.fillStyle = "skyblue"; // 设置填充颜色
|
|||
// ctx.fillRect(50, 50, 150, 100); // 绘制一个矩形
|
|||
}, |
|||
[calcPoints, xEndPx, xStartPx, yStartPx, yStepPx] |
|||
); |
|||
|
|||
useEffect(() => { |
|||
const canvas = canvasRef.current; |
|||
if (!canvas) return; |
|||
|
|||
const context = canvas.getContext("2d"); |
|||
if (!context) return; |
|||
draw(context); |
|||
}, [draw]); |
|||
|
|||
return ( |
|||
<div> |
|||
<canvas ref={canvasRef} width={props.width} height={props.height}></canvas> |
|||
</div> |
|||
); |
|||
} |
@ -1,31 +1,103 @@ |
|||
import { useCallback, useEffect, useRef } from "react"; |
|||
import { useCallback, useEffect, useRef, useState } from "react"; |
|||
import points from "../../../../utils/measure.json"; |
|||
import { createWebSocket, sharedWsUrl } from "../../../../services/socket"; |
|||
const wsClient = createWebSocket(sharedWsUrl); |
|||
console.log(sharedWsUrl); |
|||
|
|||
const pointArr: { x: number; y: number }[] = []; |
|||
|
|||
export default function RealtimeLayer(props: { |
|||
width: number; |
|||
height: number; |
|||
leftPadding: number; |
|||
rightPadding: number; |
|||
topPadding: number; |
|||
bottomPadding: number; |
|||
width: number; |
|||
height: number; |
|||
leftPadding: number; |
|||
rightPadding: number; |
|||
topPadding: number; |
|||
bottomPadding: number; |
|||
columns: number; |
|||
rows: number; |
|||
}) { |
|||
const canvasRef = useRef<HTMLCanvasElement | null>(null); |
|||
const draw = useCallback((ctx: CanvasRenderingContext2D) => { |
|||
// 使用context对象进行绘图
|
|||
ctx.fillStyle = "skyblue"; // 设置填充颜色
|
|||
ctx.fillRect(50, 50, 150, 100); // 绘制一个矩形
|
|||
}, []); |
|||
useEffect(() => { |
|||
const canvas = canvasRef.current; |
|||
if (!canvas) return; |
|||
|
|||
const context = canvas.getContext("2d"); |
|||
if (!context) return; |
|||
draw(context); |
|||
}, [draw]); |
|||
|
|||
return ( |
|||
<div> |
|||
<canvas ref={canvasRef} width={props.width} height={props.height}></canvas> |
|||
</div> |
|||
); |
|||
const xStartPx = props.leftPadding; |
|||
const xEndPx = props.width - props.rightPadding; |
|||
const xStepPx = (props.width - props.leftPadding - props.rightPadding) / props.columns; |
|||
const yStartPx = props.topPadding; |
|||
// const yEndPx = props.height - props.bottomPadding;
|
|||
const yStepPx = (props.height - props.topPadding - props.bottomPadding) / props.rows; |
|||
|
|||
const unitPx = xStepPx / 10; |
|||
const pointsPx = points.map(p => ({ x: p.x * unitPx, y: p.y * unitPx + 4 })); // 特意偏移
|
|||
|
|||
const canvasRef = useRef<HTMLCanvasElement | null>(null); |
|||
|
|||
const [rtPoints, setRtPoints] = useState<{ x: number; y: number }[]>([]); |
|||
|
|||
// const draw = useCallback(
|
|||
// (ctx: CanvasRenderingContext2D) => {
|
|||
// for (let idx = 0; idx < pointsPx.length; idx++) {
|
|||
// if (idx === 0) {
|
|||
// ctx.moveTo(pointsPx[idx].x, pointsPx[idx].y);
|
|||
// } else {
|
|||
// ctx.lineTo(pointsPx[idx].x, pointsPx[idx].y);
|
|||
// }
|
|||
// }
|
|||
// ctx.stroke();
|
|||
// },
|
|||
// [pointsPx, xEndPx, xStartPx, yStartPx, yStepPx]
|
|||
// );
|
|||
|
|||
useEffect(() => { |
|||
const subscription = wsClient.dataOb.subscribe(data => { |
|||
if (data.path === "/measurement-task/get-task-state") { |
|||
const canvas = canvasRef.current; |
|||
if (!canvas) return; |
|||
|
|||
const ctx = canvas.getContext("2d"); |
|||
if (!ctx) return; |
|||
|
|||
if (data.data.event === "START_RECORD_SIG") { |
|||
// setRtPoints([]);
|
|||
pointArr.length = 0; |
|||
ctx.resetTransform(); |
|||
ctx.clearRect(0, 0, canvas.width, canvas.height); |
|||
setTimeout(() => { |
|||
ctx.strokeStyle = "blue"; |
|||
const xOffset = (xEndPx - xStartPx) / 2; |
|||
const yOffset = yStepPx * 2; |
|||
ctx.translate(xStartPx + xOffset, yStartPx + yOffset); |
|||
ctx.beginPath(); |
|||
}, 0); |
|||
} else if (data.data.event === "END_RECORD_SIG") { |
|||
//
|
|||
} |
|||
} else if (data.path === "/measurement-task/profile-record-ctrl-sig") { |
|||
// console.log(data.data);
|
|||
// setRtPoints(rtPoints.concat([data.data]));
|
|||
pointArr.push(data.data); |
|||
|
|||
const canvas = canvasRef.current; |
|||
if (!canvas) return; |
|||
|
|||
const ctx = canvas.getContext("2d"); |
|||
if (!ctx) return; |
|||
|
|||
const pointsPx = pointArr.map(p => ({ x: p.x * unitPx, y: p.y * unitPx })); |
|||
|
|||
for (let idx = 0; idx < pointsPx.length; idx++) { |
|||
if (idx === 0) { |
|||
ctx.moveTo(pointsPx[idx].x, pointsPx[idx].y); |
|||
} else { |
|||
ctx.lineTo(pointsPx[idx].x, pointsPx[idx].y); |
|||
} |
|||
} |
|||
ctx.stroke(); |
|||
} |
|||
}); |
|||
wsClient.connect(); |
|||
return () => subscription.unsubscribe(); |
|||
}, [rtPoints, unitPx, xEndPx, xStartPx, yStartPx, yStepPx]); |
|||
|
|||
return ( |
|||
<div> |
|||
<canvas ref={canvasRef} width={props.width} height={props.height}></canvas> |
|||
</div> |
|||
); |
|||
} |
@ -0,0 +1,20 @@ |
|||
// 开始、停止绘制
|
|||
export type TaskState = { |
|||
messageType: "EVENT"; |
|||
data: { |
|||
event: "START_RECORD_SIG" | "END_RECORD_SIG"; |
|||
}; |
|||
path: "/measurement-task/get-task-state"; |
|||
}; |
|||
|
|||
// 连接上报坐标点
|
|||
export type TrackRecordSig = { |
|||
messageType: "EVENT"; |
|||
data: { |
|||
x: number; |
|||
y: number; |
|||
}; |
|||
path: "/measurement-task/profile-record-ctrl-sig"; |
|||
}; |
|||
|
|||
export type Datagram = TrackRecordSig | TaskState; |
1503
src/utils/measure.json
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save
Reference in new issue