Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
35 changes: 35 additions & 0 deletions examples/polygons.fixture.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { InteractiveGraphics } from "site/components/InteractiveGraphics/InteractiveGraphics"
import type { GraphicsObject } from "../lib"

const polygonGraphics: GraphicsObject = {
title: "Polygons Example",
coordinateSystem: "screen",
polygons: [
{
points: [
{ x: 40, y: 40 },
{ x: 140, y: 40 },
{ x: 90, y: 120 },
],
fill: "gold",
stroke: "black",
label: "Triangle",
},
{
points: [
{ x: 200, y: 60 },
{ x: 320, y: 80 },
{ x: 300, y: 170 },
{ x: 220, y: 150 },
],
fill: "rgba(0, 120, 180, 0.35)",
stroke: "#0078b4",
label: "Quad",
},
],
points: [{ x: 90, y: 120, color: "red", label: "Apex" }],
}

export default () => {
return <InteractiveGraphics graphics={polygonGraphics} />
}
29 changes: 29 additions & 0 deletions lib/drawGraphicsToCanvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export function getBounds(graphics: GraphicsObject): Viewbox {
const points = [
...(graphics.points || []),
...(graphics.lines || []).flatMap((line) => line.points),
...(graphics.polygons || []).flatMap((polygon) => polygon.points),
...(graphics.rects || []).flatMap((rect) => {
const halfWidth = rect.width / 2
const halfHeight = rect.height / 2
Expand Down Expand Up @@ -247,6 +248,34 @@ export function drawGraphicsToCanvas(
})
}

// Draw polygons
if (graphics.polygons && graphics.polygons.length > 0) {
graphics.polygons.forEach((polygon) => {
if (polygon.points.length === 0) return

const projectedPoints = polygon.points.map((point) =>
applyToPoint(matrix, point),
)

ctx.beginPath()
ctx.moveTo(projectedPoints[0].x, projectedPoints[0].y)
for (let i = 1; i < projectedPoints.length; i++) {
ctx.lineTo(projectedPoints[i].x, projectedPoints[i].y)
}
ctx.closePath()

if (polygon.fill) {
ctx.fillStyle = polygon.fill
ctx.fill()
}

if (polygon.stroke) {
ctx.strokeStyle = polygon.stroke
ctx.stroke()
}
})
}

if (graphics.arrows && graphics.arrows.length > 0) {
graphics.arrows.forEach((arrow, arrowIndex) => {
const geometry = getArrowGeometry(arrow)
Expand Down
59 changes: 57 additions & 2 deletions lib/getSvgFromGraphicsObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ function getBounds(graphics: GraphicsObject): Bounds {
const points: Point[] = [
...(graphics.points || []),
...(graphics.lines || []).flatMap((line) => line.points),
...(graphics.polygons || []).flatMap((polygon) => polygon.points),
...(graphics.rects || []).flatMap((rect) => {
const halfWidth = rect.width / 2
const halfHeight = rect.height / 2
Expand Down Expand Up @@ -126,7 +127,9 @@ export function getSvgFromGraphicsObject(
svgWidth = DEFAULT_SVG_SIZE,
svgHeight = DEFAULT_SVG_SIZE,
}: {
includeTextLabels?: boolean | Array<"points" | "lines" | "rects">
includeTextLabels?:
| boolean
| Array<"points" | "lines" | "rects" | "polygons">
backgroundColor?: string | null
svgWidth?: number
svgHeight?: number
Expand All @@ -141,7 +144,9 @@ export function getSvgFromGraphicsObject(
)
const strokeScale = Math.abs(matrix.a)

const shouldRenderLabel = (type: "points" | "lines" | "rects"): boolean => {
const shouldRenderLabel = (
type: "points" | "lines" | "rects" | "polygons",
): boolean => {
if (typeof includeTextLabels === "boolean") {
return includeTextLabels
}
Expand Down Expand Up @@ -330,6 +335,56 @@ export function getSvgFromGraphicsObject(
],
}
}),
// Polygons
...(graphics.polygons || []).map((polygon) => {
const projectedPoints = polygon.points.map((point) =>
projectPoint(point, matrix),
)
const xs = projectedPoints.map((p) => p.x)
const ys = projectedPoints.map((p) => p.y)
const minX = xs.length > 0 ? Math.min(...xs) : 0
const minY = ys.length > 0 ? Math.min(...ys) : 0

return {
name: "g",
type: "element",
attributes: {},
children: [
{
name: "polygon",
type: "element",
attributes: {
"data-type": "polygon",
"data-label": polygon.label || "",
"data-points": polygon.points
.map((p) => `${p.x},${p.y}`)
.join(" "),
points: projectedPoints.map((p) => `${p.x},${p.y}`).join(" "),
fill: polygon.fill || "none",
stroke: polygon.stroke || "black",
"stroke-width": Math.abs(1 / matrix.a).toString(),
},
},
...(shouldRenderLabel("polygons") && polygon.label
? [
{
name: "text",
type: "element",
attributes: {
x: (minX + 5).toString(),
y: minY.toString(),
"font-family": "sans-serif",
"dominant-baseline": "text-before-edge",
"font-size": "12",
fill: polygon.stroke || "black",
},
children: [{ type: "text", value: polygon.label }],
},
]
: []),
],
}
}),
// Circles
...(graphics.circles || []).map((circle) => {
const projected = projectPoint(circle.center, matrix)
Expand Down
2 changes: 1 addition & 1 deletion lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
computeTransformFromViewbox,
getBounds,
} from "./drawGraphicsToCanvas"
import { translateGraphics } from "./translateGraphics"
import { mergeGraphics } from "./mergeGraphics"
import { setStepOfAllObjects } from "./setStepOfAllObjects"
import {
Expand All @@ -19,6 +18,7 @@ export type {
Line,
Rect,
Circle,
Polygon,
Arrow,
Text,
NinePointAnchor,
Expand Down
1 change: 1 addition & 0 deletions lib/mergeGraphics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const mergeGraphics = (
rects: [...(graphics1.rects ?? []), ...(graphics2.rects ?? [])],
points: [...(graphics1.points ?? []), ...(graphics2.points ?? [])],
lines: [...(graphics1.lines ?? []), ...(graphics2.lines ?? [])],
polygons: [...(graphics1.polygons ?? []), ...(graphics2.polygons ?? [])],
circles: [...(graphics1.circles ?? []), ...(graphics2.circles ?? [])],
arrows: [...(graphics1.arrows ?? []), ...(graphics2.arrows ?? [])],
texts: [...(graphics1.texts ?? []), ...(graphics2.texts ?? [])],
Expand Down
5 changes: 5 additions & 0 deletions lib/setStepOfAllObjects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ export function setStepOfAllObjects(
line.step = step
}
}
if (graphics.polygons) {
for (const polygon of graphics.polygons) {
polygon.step = step
}
}
if (graphics.rects) {
for (const rect of graphics.rects) {
rect.step = step
Expand Down
4 changes: 4 additions & 0 deletions lib/translateGraphics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ export function translateGraphics(
...line,
points: line.points.map((pt) => ({ x: pt.x + dx, y: pt.y + dy })),
})),
polygons: graphics.polygons?.map((polygon) => ({
...polygon,
points: polygon.points.map((pt) => ({ x: pt.x + dx, y: pt.y + dy })),
})),
rects: graphics.rects?.map((rect) => ({
...rect,
center: { x: rect.center.x + dx, y: rect.center.y + dy },
Expand Down
11 changes: 11 additions & 0 deletions lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ export interface Circle {
label?: string
}

export interface Polygon {
points: { x: number; y: number }[]
fill?: string
stroke?: string
color?: string
layer?: string
step?: number
label?: string
}

export interface Arrow {
start: { x: number; y: number }
end: { x: number; y: number }
Expand Down Expand Up @@ -73,6 +83,7 @@ export interface GraphicsObject {
lines?: Line[]
rects?: Rect[]
circles?: Circle[]
polygons?: Polygon[]
arrows?: Arrow[]
texts?: Text[]
coordinateSystem?: "cartesian" | "screen"
Expand Down
12 changes: 12 additions & 0 deletions scripts/example-usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@ debugGraphics(
color: "green",
},
],
polygons: [
{
points: [
{ x: -60, y: -40 },
{ x: -20, y: -40 },
{ x: -40, y: -10 },
],
fill: "gold",
stroke: "black",
label: "Triangle",
},
],
points: [{ x: 50, y: 50, color: "red", label: "Test Output!" }],
}),
)
Expand Down
23 changes: 22 additions & 1 deletion site/components/InteractiveGraphics/InteractiveGraphics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,16 @@ import {
useFilterCircles,
useFilterTexts,
useFilterArrows,
useFilterPolygons,
} from "./hooks"
import { DimensionOverlay } from "../DimensionOverlay"
import { getMaxStep } from "site/utils/getMaxStep"
import { ContextMenu } from "./ContextMenu"
import { Marker, MarkerPoint } from "./Marker"
import { Polygon } from "./Polygon"

export type GraphicsObjectClickEvent = {
type: "point" | "line" | "rect" | "circle" | "text" | "arrow"
type: "point" | "line" | "rect" | "circle" | "text" | "arrow" | "polygon"
index: number
object: any
}
Expand Down Expand Up @@ -66,6 +68,7 @@ export const InteractiveGraphics = ({
new Set([
...(graphics.lines?.map((l) => l.layer!).filter(Boolean) ?? []),
...(graphics.rects?.map((r) => r.layer!).filter(Boolean) ?? []),
...(graphics.polygons?.map((p) => p.layer!).filter(Boolean) ?? []),
...(graphics.points?.map((p) => p.layer!).filter(Boolean) ?? []),
...(graphics.texts?.map((t) => t.layer!).filter(Boolean) ?? []),
...(graphics.circles?.map((c) => c.layer!).filter(Boolean) ?? []),
Expand Down Expand Up @@ -337,6 +340,11 @@ export const InteractiveGraphics = ({
isPointOnScreen,
doesLineIntersectViewport,
)
const filterPolygons = useFilterPolygons(
isPointOnScreen,
doesLineIntersectViewport,
filterLayerAndStep,
)

const filterAndLimit = <T,>(
objects: T[] | undefined,
Expand All @@ -357,6 +365,10 @@ export const InteractiveGraphics = ({
() => sortRectsByArea(filterAndLimit(graphics.rects, filterRects)),
[graphics.rects, filterRects, objectLimit],
)
const filteredPolygons = useMemo(
() => filterAndLimit(graphics.polygons, filterPolygons),
[graphics.polygons, filterPolygons, objectLimit],
)
const filteredPoints = useMemo(
() => filterAndLimit(graphics.points, filterPoints),
[graphics.points, filterPoints, objectLimit],
Expand All @@ -377,6 +389,7 @@ export const InteractiveGraphics = ({
const totalFilteredObjects =
filteredLines.length +
filteredRects.length +
filteredPolygons.length +
filteredPoints.length +
filteredCircles.length +
filteredTexts.length +
Expand Down Expand Up @@ -491,6 +504,14 @@ export const InteractiveGraphics = ({
interactiveState={interactiveState}
/>
))}
{filteredPolygons.map((polygon) => (
<Polygon
key={polygon.originalIndex}
polygon={polygon}
index={polygon.originalIndex}
interactiveState={interactiveState}
/>
))}
{filteredPoints.map((point) => (
<Point
key={point.originalIndex}
Expand Down
Loading