1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- <template>
- <v-group :config="{ listening: false }">
- <template v-for="line in lines">
- <v-line
- v-for="p in line.points"
- :config="{
- stroke: stroke,
- strokeWidth: strokeWidth,
- points: flatPositions(p),
- }"
- />
- <v-textPath
- :config="{
- fill: stroke,
- align: 'center',
- fontSize,
- textBaseline: 'middle',
- ...line.textConfig,
- }"
- />
- </template>
- </v-group>
- </template>
- <script lang="ts" setup>
- import { computed } from "vue";
- import { LineData } from "../line";
- import {
- getPolygonDirection,
- getVectorLine,
- lineLen,
- lineVector,
- lineVerticalVector,
- Pos,
- vector,
- } from "@/utils/math";
- import { flatPositions } from "@/utils/shared";
- import { useProportion } from "@/core/hook/use-proportion";
- import { TextPathConfig } from "konva/lib/shapes/TextPath";
- const props = withDefaults(
- defineProps<{
- data: Required<Pick<LineData, "points" | "strokeWidth">>;
- stroke?: string;
- strokeWidth?: number;
- closed?: boolean;
- }>(),
- { stroke: "#999", strokeWidth: 1 }
- );
- const fontSize = computed(() => 10 + props.strokeWidth * 2);
- const len = computed(() =>
- props.closed ? props.data.points.length : props.data.points.length - 1
- );
- const getLine = (ndx: number) =>
- [
- props.data.points[ndx % props.data.points.length],
- props.data.points[(ndx + 1) % props.data.points.length],
- ] as [Pos, Pos];
- const isClockwise = computed(() => getPolygonDirection(props.data.points) <= 0);
- const proportion = useProportion();
- const margin = computed(() => -(props.data.strokeWidth + 10));
- const lines = computed(() => {
- const lines: { points: Pos[][]; textConfig: TextPathConfig }[] = [];
- for (let i = 0; i < len.value; i++) {
- const line = getLine(i);
- const lineOffset = isClockwise.value ? margin.value : -margin.value;
- const vv = lineVerticalVector(line);
- const offset = vv.multiplyScalar(lineOffset);
- const p = [vector(line[0]).add(offset), vector(line[1]).add(offset)];
- const text = proportion.transform(lineLen(...line));
- const w = fontSize.value * text.length;
- const lw = lineLen(p[0], p[1]);
- if (w > lw) {
- continue;
- }
- const lv = lineVector(p);
- const line1 = getVectorLine(lv, p[0], (lw - w) / 2);
- const [_, start2] = getVectorLine(lv, line1[1], w);
- const line2 = getVectorLine(lv, start2, (lw - w) / 2);
- lines.push({
- points: [line1, line2],
- textConfig: {
- text: proportion.transform(lineLen(...line)),
- x: 0,
- y: 0,
- data: `M${p[0].x},${p[0].y} L${p[1].x},${p[1].y}`,
- },
- });
- }
- return lines;
- });
- </script>
|