diff --git a/src/pages/measure/components/graph/StandardLayer.tsx b/src/pages/measure/components/graph/StandardLayer.tsx index f2bffeb..fde7c9f 100644 --- a/src/pages/measure/components/graph/StandardLayer.tsx +++ b/src/pages/measure/components/graph/StandardLayer.tsx @@ -1,4 +1,28 @@ import { useCallback, useEffect, useRef } from "react"; +import { calculateCircleAbove, calculateCircleBelow } from "../../../../utils"; + +const unitPx = 8; + +const pointsR: [number, number][] = [ + [0, 0], + [9.949007022412, 0.1650166186941], + [25.35, 2.184814802617], + [35.4, 14.20034968551], + [36.31679456414, 32.538841443], + [32.90417417089, 37.53190928715], + [20.0, 41.8333134842], +]; +const pointsL: [number, number][] = [ + [-20.0, 41.83331348425], + [-32.90417417089, 37.53190928715], + [-36.31679456414, 32.538841443], + [-35.4, 14.20034968551], + [-25.35, 2.184814802617], + [-9.949007022412, 0.1650166186941], + [0, 0], +]; +const pointsRight = pointsR.map(p => [p[0] * unitPx, p[1] * unitPx]); +const pointsLeft = pointsL.map(p => [p[0] * unitPx, p[1] * unitPx]); export default function StandardLayer(props: { width: number; @@ -9,10 +33,101 @@ export default function StandardLayer(props: { bottomPadding: number; }) { const canvasRef = useRef(null); + const draw = useCallback((ctx: CanvasRenderingContext2D) => { // 使用context对象进行绘图 - ctx.fillStyle = "skyblue"; // 设置填充颜色 - ctx.fillRect(50, 50, 150, 100); // 绘制一个矩形 + ctx.fillStyle = "blue"; + ctx.strokeStyle = "blue"; + + ctx.translate(400, 100); + ctx.moveTo(-400, 0); + ctx.lineTo(400, 0); + ctx.moveTo(0, -100); + ctx.lineTo(0, 500); + ctx.stroke(); + + ctx.beginPath(); + ctx.strokeStyle = "red"; + // ---- 右侧 + let point0 = pointsRight[0]; + let point1 = pointsRight[1]; + ctx.moveTo(point0[0], point0[1]); + let param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 300 * unitPx); + console.log(param); + ctx.arc(param.center.x, param.center.y, 300 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); + + point0 = pointsRight[1]; + point1 = pointsRight[2]; + ctx.moveTo(point0[0], point0[1]); + param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 80 * unitPx); + console.log(param); + ctx.arc(param.center.x, param.center.y, 80 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); + + point0 = pointsRight[2]; + point1 = pointsRight[3]; + ctx.moveTo(point0[0], point0[1]); + param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 13 * unitPx); + console.log(param); + ctx.arc(param.center.x, param.center.y, 13 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); + + point0 = pointsRight[3]; + point1 = pointsRight[4]; + ctx.moveTo(point0[0], point0[1]); + ctx.lineTo(point1[0], point1[1]); + + point0 = pointsRight[4]; + point1 = pointsRight[5]; + ctx.moveTo(point0[0], point0[1]); + param = calculateCircleAbove(point0[0], point0[1], point1[0], point1[1], 5 * unitPx); + console.log(param); + ctx.arc(param.center.x, param.center.y, 5 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); + + point0 = pointsRight[5]; + point1 = pointsRight[6]; + ctx.moveTo(point0[0], point0[1]); + ctx.lineTo(point1[0], point1[1]); + + // ---- 左侧 + point0 = pointsLeft[0]; + point1 = pointsLeft[1]; + ctx.moveTo(point0[0], point0[1]); + ctx.lineTo(point1[0], point1[1]); + + point0 = pointsLeft[1]; + point1 = pointsLeft[2]; + ctx.moveTo(point0[0], point0[1]); + param = calculateCircleAbove(point0[0], point0[1], point1[0], point1[1], 5 * unitPx); + console.log(param); + ctx.arc(param.center.x, param.center.y, 5 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); + + point0 = pointsLeft[2]; + point1 = pointsLeft[3]; + ctx.moveTo(point0[0], point0[1]); + ctx.lineTo(point1[0], point1[1]); + + point0 = pointsLeft[3]; + point1 = pointsLeft[4]; + ctx.moveTo(point0[0], point0[1]); + param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 13 * unitPx); + console.log(param); + ctx.arc(param.center.x, param.center.y, 13 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); + + point0 = pointsLeft[4]; + point1 = pointsLeft[5]; + ctx.moveTo(point0[0], point0[1]); + param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 80 * unitPx); + console.log(param); + ctx.arc(param.center.x, param.center.y, 80 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); + + point0 = pointsLeft[5]; + point1 = pointsLeft[6]; + ctx.moveTo(point0[0], point0[1]); + param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 300 * unitPx); + console.log(param); + ctx.arc(param.center.x, param.center.y, 300 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); + + ctx.stroke(); + // ctx.fillRect(100, 100, 150, 100); // 绘制一个矩形 }, []); useEffect(() => { const canvas = canvasRef.current; diff --git a/src/utils/index.ts b/src/utils/index.ts index 1c1eb9a..6c3a9b8 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -3,3 +3,63 @@ export function formatRemainTime(seconds: number) { const sec = (seconds % 60).toFixed(); return min.padStart(2, "0") + ":" + sec.padStart(2, "0"); } + +export function calculateCircleInfo(x1: number, y1: number, x2: number, y2: number, radius: number) { + // 计算P1到P2的中点 + const xm = (x1 + x2) / 2; + const ym = (y1 + y2) / 2; + + // P1到P2的距离的一半 + const dx = x2 - x1; + const dy = y2 - y1; + const d = Math.sqrt(dx * dx + dy * dy) / 2; + + // 如果距离大于直径,则无法形成圆 + if (d > radius) { + throw new Error("Given points are too far apart for the given radius."); + } + + // 计算垂直平分线的方向向量 + const len = Math.sqrt(radius * radius - d * d); + const nx = dy / (2 * d); + const ny = -dx / (2 * d); + + // 计算两个可能的圆心 + const cx1 = xm + nx * len; + const cy1 = ym + ny * len; + const cx2 = xm - nx * len; + const cy2 = ym - ny * len; + + // 使用atan2计算起始角和结束角 + function calculateAngle(cx: number, cy: number, px: number, py: number) { + return Math.atan2(py - cy, px - cx); + } + + const startAngle1 = calculateAngle(cx1, cy1, x1, y1); + const endAngle1 = calculateAngle(cx1, cy1, x2, y2); + const startAngle2 = calculateAngle(cx2, cy2, x1, y1); + const endAngle2 = calculateAngle(cx2, cy2, x2, y2); + + return [ + { center: { x: cx1, y: cy1 }, anglesForCenter: { startAngle: startAngle1, endAngle: endAngle1 } }, + { center: { x: cx2, y: cy2 }, anglesForCenter: { startAngle: startAngle2, endAngle: endAngle2 } }, + ]; +} + +export type CenterAndAngle = ReturnType; +export function calculateCircleBelow(x1: number, y1: number, x2: number, y2: number, radius: number) { + const results = calculateCircleInfo(x1, y1, x2, y2, radius); + if (results[0].center.y > results[1].center.y) { + return results[0]; + } else { + return results[1]; + } +} +export function calculateCircleAbove(x1: number, y1: number, x2: number, y2: number, radius: number) { + const results = calculateCircleInfo(x1, y1, x2, y2, radius); + if (results[0].center.y < results[1].center.y) { + return results[0]; + } else { + return results[1]; + } +}