Skip to content

Commit e047572

Browse files
authored
feat: make components nestable
1 parent 4382047 commit e047572

File tree

16 files changed

+149
-99
lines changed

16 files changed

+149
-99
lines changed

src/components/Angle.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
:color="color"
2323
:size="labelSize"
2424
/>
25+
26+
<slot />
2527
</g>
2628
</template>
2729

@@ -33,6 +35,7 @@ import { useGraphContext } from "../composables/useGraphContext.ts";
3335
import { Color } from "../types.ts";
3436
import { useColors } from "../composables/useColors.ts";
3537
import { usePointerIntersection } from "../composables/usePointerIntersection.ts";
38+
import { useLocalToWorld } from "../composables/useLocalToWorld.ts";
3639
import { pointInsideSector } from "../utils/geometry.ts";
3740
import Label from "./Label.vue";
3841
@@ -58,7 +61,8 @@ const props = withDefaults(
5861
},
5962
);
6063
61-
const { matrix, invScale } = useGraphContext();
64+
const { invScale } = useGraphContext();
65+
const matrix = useLocalToWorld(toRef(props, "position"));
6266
const { parseColor } = useColors();
6367
6468
const stroke = parseColor(toRef(props, "color"), "stroke");

src/components/Arc.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
:color="color"
1111
:label="label"
1212
:label-size="labelSize"
13-
/>
13+
>
14+
<slot />
15+
</Angle>
1416
</template>
1517

1618
<script setup lang="ts">

src/components/Circle.vue

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
<template>
2-
<circle
3-
v-bind="$attrs"
4-
:cx="position.x"
5-
:cy="position.y"
6-
:r="scaledRadius"
7-
:fill="fill"
8-
:stroke="stroke"
9-
:stroke-width="lineWidth * invScale"
10-
:stroke-dasharray="dashArray"
11-
/>
2+
<g v-bind="$attrs">
3+
<circle
4+
:cx="position.x"
5+
:cy="position.y"
6+
:r="scaledRadius"
7+
:fill="fill"
8+
:stroke="stroke"
9+
:stroke-width="lineWidth * invScale"
10+
:stroke-dasharray="dashArray"
11+
/>
12+
<slot />
13+
</g>
1214
</template>
1315

1416
<script setup lang="ts">
@@ -19,6 +21,7 @@ import { useGraphContext } from "../composables/useGraphContext.ts";
1921
import { type Color } from "../types.ts";
2022
import { useColors } from "../composables/useColors.ts";
2123
import { usePointerIntersection } from "../composables/usePointerIntersection.ts";
24+
import { useLocalToWorld } from "../composables/useLocalToWorld.ts";
2225
import { pointInsideCircle } from "../utils/geometry.ts";
2326
2427
const props = withDefaults(
@@ -37,7 +40,8 @@ const props = withDefaults(
3740
},
3841
);
3942
40-
const { matrix, invScale } = useGraphContext();
43+
const { invScale } = useGraphContext();
44+
const matrix = useLocalToWorld(toRef(props, "position"));
4145
const { parseColor } = useColors();
4246
4347
const stroke = parseColor(toRef(props, "color"), "stroke");

src/components/Ellipse.vue

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
<template>
2-
<ellipse
3-
v-bind="$attrs"
4-
:cx="position.x"
5-
:cy="position.y"
6-
:rx="scaledRadius.x"
7-
:ry="scaledRadius.y"
8-
:fill="fill"
9-
:stroke="stroke"
10-
:stroke-width="lineWidth * invScale"
11-
:stroke-dasharray="dashArray"
12-
:transform="`rotate(${-rotation}, ${position.x}, ${position.y})`"
13-
/>
2+
<g v-bind="$attrs">
3+
<ellipse
4+
:cx="position.x"
5+
:cy="position.y"
6+
:rx="scaledRadius.x"
7+
:ry="scaledRadius.y"
8+
:fill="fill"
9+
:stroke="stroke"
10+
:stroke-width="lineWidth * invScale"
11+
:stroke-dasharray="dashArray"
12+
:transform="`rotate(${-rotation}, ${position.x}, ${position.y})`"
13+
/>
14+
<slot />
15+
</g>
1416
</template>
1517

1618
<script setup lang="ts">
@@ -21,6 +23,7 @@ import { useGraphContext } from "../composables/useGraphContext.ts";
2123
import { type Color } from "../types.ts";
2224
import { useColors } from "../composables/useColors.ts";
2325
import { usePointerIntersection } from "../composables/usePointerIntersection.ts";
26+
import { useLocalToWorld } from "../composables/useLocalToWorld.ts";
2427
import { pointInsideEllipse } from "../utils/geometry.ts";
2528
2629
const props = withDefaults(
@@ -44,7 +47,8 @@ const props = withDefaults(
4447
},
4548
);
4649
47-
const { matrix, invScale } = useGraphContext();
50+
const { invScale } = useGraphContext();
51+
const matrix = useLocalToWorld(toRef(props, "position"));
4852
const { parseColor } = useColors();
4953
5054
const stroke = parseColor(toRef(props, "color"), "stroke");

src/components/FunctionPlot.vue

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { computed, onMounted, ref, toRef, watch } from "vue";
1212
1313
import { Color } from "../types.ts";
1414
import { useGraphContext } from "../composables/useGraphContext.ts";
15+
import { useLocalToWorld } from "../composables/useLocalToWorld.ts";
1516
import { PossibleVector2, Vector2 } from "../utils/Vector2.ts";
1617
import { useColors } from "../composables/useColors.ts";
1718
@@ -35,7 +36,8 @@ const props = withDefaults(
3536
3637
let animationFrameID: number | null = null;
3738
38-
const { domain, scale, offset, size, invScale } = useGraphContext();
39+
const { domain, size, invScale } = useGraphContext();
40+
const matrix = useLocalToWorld();
3941
const { parseColor } = useColors();
4042
4143
const color = parseColor(toRef(props, "color"), "stroke");
@@ -53,18 +55,17 @@ const visiblePoints = computed(() => {
5355
});
5456
5557
const path = computed(() => {
56-
const points = visiblePoints.value;
58+
const points = visiblePoints.value.map((point) =>
59+
point.transform(matrix.value),
60+
);
5761
5862
if (points.length === 0) {
5963
return "";
6064
}
6165
62-
return `M ${points[0].x * scale.value.x + offset.value.x} ${points[0].y * scale.value.y + offset.value.y} L ${points
66+
return `M ${points[0].x} ${points[0].y} L ${points
6367
.slice(1)
64-
.map(
65-
(p) =>
66-
`${p.x * scale.value.x + offset.value.x} ${p.y * scale.value.y + offset.value.y}`,
67-
)
68+
.map((p) => `${p.x} ${p.y}`)
6869
.join("L ")}`;
6970
});
7071

src/components/Graph.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@
118118
<script setup lang="ts">
119119
import { computed, onMounted, provide, ref } from "vue";
120120
121-
import { graphContext } from "../types.ts";
121+
import { graphContext, parentToWorld } from "../types.ts";
122122
import { PossibleVector2, Vector2 } from "../utils/Vector2.ts";
123123
import { useColors } from "../composables/useColors.ts";
124124
import { Matrix2D } from "../utils/Matrix2D.ts";
@@ -187,10 +187,9 @@ const size = computed(() => {
187187
const invScale = computed(() => Math.max(1, props.width / size.value.x));
188188
189189
const matrixWorld = computed(() => {
190-
const matrix = new Matrix2D();
191-
matrix.translate([offset.value.x, offset.value.y]);
192-
matrix.scale([scale.value.x, -scale.value.y]);
193-
return matrix;
190+
return new Matrix2D()
191+
.translate([offset.value.x, offset.value.y])
192+
.scale([scale.value.x, -scale.value.y]);
194193
});
195194
196195
const cursor = computed<Vector2 | null>(() => {
@@ -215,6 +214,7 @@ const context = {
215214
};
216215
217216
provide(graphContext, context);
217+
provide(parentToWorld, matrixWorld);
218218
219219
function formatLabelValue(value: number) {
220220
return value.toFixed(2).replace(/\.?0+$/, "");

src/components/Label.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
>
2323
{{ text }}
2424
</text>
25+
26+
<slot />
2527
</g>
2628
</template>
2729

@@ -33,6 +35,7 @@ import { type PossibleVector2, Vector2 } from "../utils/Vector2.ts";
3335
import { useGraphContext } from "../composables/useGraphContext.ts";
3436
import { useColors } from "../composables/useColors.ts";
3537
import { usePointerIntersection } from "../composables/usePointerIntersection.ts";
38+
import { useLocalToWorld } from "../composables/useLocalToWorld.ts";
3639
import { pointInsideRectangle } from "../utils/geometry.ts";
3740
3841
const props = withDefaults(
@@ -64,7 +67,8 @@ const sizes = {
6467
large: 12,
6568
};
6669
67-
const { matrix, invScale } = useGraphContext();
70+
const { invScale } = useGraphContext();
71+
const matrix = useLocalToWorld(toRef(props, "position"));
6872
const { colors, parseColor } = useColors();
6973
7074
const color = parseColor(toRef(props, "color"), "stroke");

src/components/Line.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
:color="color"
1717
:size="labelSize"
1818
/>
19+
20+
<slot />
1921
</g>
2022
</template>
2123

@@ -28,6 +30,7 @@ import Label from "./Label.vue";
2830
import { useGraphContext } from "../composables/useGraphContext.ts";
2931
import { useColors } from "../composables/useColors.ts";
3032
import { usePointerIntersection } from "../composables/usePointerIntersection.ts";
33+
import { useLocalToWorld } from "../composables/useLocalToWorld.ts";
3134
import { distanceToLineSegment } from "../utils/geometry.ts";
3235
3336
const props = withDefaults(
@@ -56,8 +59,9 @@ if (props.to === undefined && props.slope === undefined) {
5659
throw new Error("Line requires either a `to` prop or a `slope` prop");
5760
}
5861
59-
const { domain, matrix, invScale } = useGraphContext();
62+
const { domain, invScale } = useGraphContext();
6063
const { parseColor } = useColors();
64+
const matrix = useLocalToWorld();
6165
6266
const color = parseColor(toRef(props, "color"), "stroke");
6367
const active = defineModel("active", { default: false });

src/components/Point.vue

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
:color="color"
1818
size="small"
1919
/>
20+
21+
<slot />
2022
</g>
2123
</template>
2224

@@ -29,6 +31,7 @@ import Label from "./Label.vue";
2931
import { useGraphContext } from "../composables/useGraphContext.ts";
3032
import { useColors } from "../composables/useColors.ts";
3133
import { usePointerIntersection } from "../composables/usePointerIntersection.ts";
34+
import { useLocalToWorld } from "../composables/useLocalToWorld.ts";
3235
import { pointInsideCircle } from "../utils/geometry.ts";
3336
3437
type LabelPosition = "top" | "bottom" | "left" | "right";
@@ -54,13 +57,14 @@ const props = withDefaults(
5457
},
5558
);
5659
57-
const { matrix, invScale } = useGraphContext();
60+
const { invScale } = useGraphContext();
61+
const matrix = useLocalToWorld(toRef(props, "position"));
5862
const { parseColor } = useColors();
5963
const color = parseColor(toRef(props, "color"), "points");
6064
const labelActive = ref(false);
6165
const active = defineModel("active", { default: false });
6266
usePointerIntersection(active, (point) => {
63-
const center = Vector2.wrap(props.position);
67+
const center = position.value;
6468
const pointActive = pointInsideCircle(
6569
center,
6670
(props.radius + props.lineWidth) / matrix.value.a +

src/components/PolyLine.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { PossibleVector2, Vector2 } from "../utils/Vector2.ts";
2020
import { useGraphContext } from "../composables/useGraphContext.ts";
2121
import { useColors } from "../composables/useColors.ts";
2222
import { usePointerIntersection } from "../composables/usePointerIntersection.ts";
23+
import { useLocalToWorld } from "../composables/useLocalToWorld.ts";
2324
import { distanceToLineSegment } from "../utils/geometry.ts";
2425
2526
const props = withDefaults(
@@ -37,7 +38,8 @@ const props = withDefaults(
3738
},
3839
);
3940
40-
const { matrix, invScale } = useGraphContext();
41+
const { invScale } = useGraphContext();
42+
const matrix = useLocalToWorld();
4143
const { parseColor } = useColors();
4244
4345
const color = parseColor(toRef(props, "color"), "stroke");

0 commit comments

Comments
 (0)