circuit-to-canvas 0.0.17 → 0.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +32 -8
- package/dist/index.js +179 -13
- package/lib/drawer/CircuitToCanvasDrawer.ts +14 -2
- package/lib/drawer/elements/index.ts +5 -0
- package/lib/drawer/elements/pcb-copper-text.ts +2 -2
- package/lib/drawer/elements/pcb-note-dimension.ts +201 -0
- package/lib/drawer/shapes/arrow.ts +36 -0
- package/lib/drawer/shapes/index.ts +1 -0
- package/lib/drawer/shapes/text/getAlphabetLayout.ts +41 -0
- package/lib/drawer/shapes/text/getTextStartPosition.ts +53 -0
- package/lib/drawer/shapes/text/index.ts +3 -0
- package/lib/drawer/shapes/{text.ts → text/text.ts} +5 -104
- package/package.json +2 -1
- package/tests/board-snapshot/__snapshots__/usb-c-flashlight-board.snap.png +0 -0
- package/tests/board-snapshot/usb-c-flashlight-board.test.ts +15 -0
- package/tests/board-snapshot/usb-c-flashlight.json +2456 -0
- package/tests/elements/__snapshots__/fabrication-note-text-descenders.snap.png +0 -0
- package/tests/elements/__snapshots__/fabrication-note-text-full-charset.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-fabrication-note-text-rgba-color.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-fabrication-note-text-small.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-note-dimension-angled-and-vertical.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-note-dimension-basic.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-note-dimension-vertical.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-note-dimension-with-offset.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-note-text-anchor-alignment.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-note-text-custom-color.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-note-text-small.snap.png +0 -0
- package/tests/elements/pcb-note-dimension-angled-and-vertical.test.ts +37 -0
- package/tests/elements/pcb-note-dimension-basic.test.ts +36 -0
- package/tests/elements/pcb-note-dimension-vertical.test.ts +42 -0
- package/tests/elements/pcb-note-dimension-with-offset.test.ts +38 -0
- package/tests/fixtures/assets/label-circuit-to-canvas.png +0 -0
- package/tests/fixtures/assets/label-circuit-to-svg.png +0 -0
- package/tests/fixtures/getStackedPngSvgComparison.ts +62 -0
- package/tests/fixtures/stackPngsVertically.ts +82 -0
- package/tests/shapes/__snapshots__/oval.snap.png +0 -0
- package/tsconfig.json +1 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export const GLYPH_WIDTH_RATIO = 0.62
|
|
2
|
+
export const LETTER_SPACING_RATIO = 0.3 // Letter spacing between characters (25% of glyph width)
|
|
3
|
+
export const SPACE_WIDTH_RATIO = 1
|
|
4
|
+
export const STROKE_WIDTH_RATIO = 0.13
|
|
5
|
+
|
|
6
|
+
export type AlphabetLayout = {
|
|
7
|
+
width: number
|
|
8
|
+
height: number
|
|
9
|
+
glyphWidth: number
|
|
10
|
+
letterSpacing: number
|
|
11
|
+
spaceWidth: number
|
|
12
|
+
strokeWidth: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function getAlphabetLayout(
|
|
16
|
+
text: string,
|
|
17
|
+
fontSize: number,
|
|
18
|
+
): AlphabetLayout {
|
|
19
|
+
const glyphWidth = fontSize * GLYPH_WIDTH_RATIO
|
|
20
|
+
const letterSpacing = glyphWidth * LETTER_SPACING_RATIO
|
|
21
|
+
const spaceWidth = glyphWidth * SPACE_WIDTH_RATIO
|
|
22
|
+
const characters = Array.from(text)
|
|
23
|
+
|
|
24
|
+
let width = 0
|
|
25
|
+
characters.forEach((char, index) => {
|
|
26
|
+
const advance = char === " " ? spaceWidth : glyphWidth
|
|
27
|
+
width += advance
|
|
28
|
+
if (index < characters.length - 1) width += letterSpacing
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
const strokeWidth = Math.max(fontSize * STROKE_WIDTH_RATIO, 0.35)
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
width,
|
|
35
|
+
height: fontSize,
|
|
36
|
+
glyphWidth,
|
|
37
|
+
letterSpacing,
|
|
38
|
+
spaceWidth,
|
|
39
|
+
strokeWidth,
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { NinePointAnchor } from "circuit-json"
|
|
2
|
+
import type { AlphabetLayout } from "./getAlphabetLayout"
|
|
3
|
+
|
|
4
|
+
export type AnchorAlignment = NinePointAnchor
|
|
5
|
+
|
|
6
|
+
export function getTextStartPosition(
|
|
7
|
+
alignment: NinePointAnchor,
|
|
8
|
+
layout: AlphabetLayout,
|
|
9
|
+
): { x: number; y: number } {
|
|
10
|
+
const totalWidth = layout.width + layout.strokeWidth
|
|
11
|
+
const totalHeight = layout.height + layout.strokeWidth
|
|
12
|
+
|
|
13
|
+
let x = 0
|
|
14
|
+
let y = 0
|
|
15
|
+
|
|
16
|
+
// Horizontal alignment
|
|
17
|
+
if (alignment === "center") {
|
|
18
|
+
x = -totalWidth / 2
|
|
19
|
+
} else if (
|
|
20
|
+
alignment === "top_left" ||
|
|
21
|
+
alignment === "bottom_left" ||
|
|
22
|
+
alignment === "center_left"
|
|
23
|
+
) {
|
|
24
|
+
x = 0
|
|
25
|
+
} else if (
|
|
26
|
+
alignment === "top_right" ||
|
|
27
|
+
alignment === "bottom_right" ||
|
|
28
|
+
alignment === "center_right"
|
|
29
|
+
) {
|
|
30
|
+
x = -totalWidth
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Vertical alignment
|
|
34
|
+
if (alignment === "center") {
|
|
35
|
+
y = -totalHeight / 2
|
|
36
|
+
} else if (
|
|
37
|
+
alignment === "top_left" ||
|
|
38
|
+
alignment === "top_right" ||
|
|
39
|
+
alignment === "top_center"
|
|
40
|
+
) {
|
|
41
|
+
y = 0
|
|
42
|
+
} else if (
|
|
43
|
+
alignment === "bottom_left" ||
|
|
44
|
+
alignment === "bottom_right" ||
|
|
45
|
+
alignment === "bottom_center"
|
|
46
|
+
) {
|
|
47
|
+
y = -totalHeight
|
|
48
|
+
} else {
|
|
49
|
+
y = 0
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return { x, y }
|
|
53
|
+
}
|
|
@@ -1,113 +1,14 @@
|
|
|
1
1
|
import { lineAlphabet } from "@tscircuit/alphabet"
|
|
2
2
|
import type { Matrix } from "transformation-matrix"
|
|
3
3
|
import { applyToPoint } from "transformation-matrix"
|
|
4
|
-
import type { CanvasContext } from "
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const SPACE_WIDTH_RATIO = 1
|
|
9
|
-
const STROKE_WIDTH_RATIO = 0.13
|
|
10
|
-
|
|
11
|
-
export type AlphabetLayout = {
|
|
12
|
-
width: number
|
|
13
|
-
height: number
|
|
14
|
-
glyphWidth: number
|
|
15
|
-
letterSpacing: number
|
|
16
|
-
spaceWidth: number
|
|
17
|
-
strokeWidth: number
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function getAlphabetLayout(
|
|
21
|
-
text: string,
|
|
22
|
-
fontSize: number,
|
|
23
|
-
): AlphabetLayout {
|
|
24
|
-
const glyphWidth = fontSize * GLYPH_WIDTH_RATIO
|
|
25
|
-
const letterSpacing = glyphWidth * LETTER_SPACING_RATIO
|
|
26
|
-
const spaceWidth = glyphWidth * SPACE_WIDTH_RATIO
|
|
27
|
-
const characters = Array.from(text)
|
|
28
|
-
|
|
29
|
-
let width = 0
|
|
30
|
-
characters.forEach((char, index) => {
|
|
31
|
-
const advance = char === " " ? spaceWidth : glyphWidth
|
|
32
|
-
width += advance
|
|
33
|
-
if (index < characters.length - 1) width += letterSpacing
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
const strokeWidth = Math.max(fontSize * STROKE_WIDTH_RATIO, 0.35)
|
|
37
|
-
|
|
38
|
-
return {
|
|
39
|
-
width,
|
|
40
|
-
height: fontSize,
|
|
41
|
-
glyphWidth,
|
|
42
|
-
letterSpacing,
|
|
43
|
-
spaceWidth,
|
|
44
|
-
strokeWidth,
|
|
45
|
-
}
|
|
46
|
-
}
|
|
4
|
+
import type { CanvasContext } from "../../types"
|
|
5
|
+
import type { NinePointAnchor } from "circuit-json"
|
|
6
|
+
import { getAlphabetLayout, type AlphabetLayout } from "./getAlphabetLayout"
|
|
7
|
+
import { getTextStartPosition } from "./getTextStartPosition"
|
|
47
8
|
|
|
48
9
|
const getGlyphLines = (char: string) =>
|
|
49
10
|
lineAlphabet[char] ?? lineAlphabet[char.toUpperCase()]
|
|
50
11
|
|
|
51
|
-
export type AnchorAlignment =
|
|
52
|
-
| "center"
|
|
53
|
-
| "top_left"
|
|
54
|
-
| "top_right"
|
|
55
|
-
| "bottom_left"
|
|
56
|
-
| "bottom_right"
|
|
57
|
-
| "left"
|
|
58
|
-
| "right"
|
|
59
|
-
| "top"
|
|
60
|
-
| "bottom"
|
|
61
|
-
|
|
62
|
-
export function getTextStartPosition(
|
|
63
|
-
alignment: AnchorAlignment,
|
|
64
|
-
layout: AlphabetLayout,
|
|
65
|
-
): { x: number; y: number } {
|
|
66
|
-
const totalWidth = layout.width + layout.strokeWidth
|
|
67
|
-
const totalHeight = layout.height + layout.strokeWidth
|
|
68
|
-
|
|
69
|
-
let x = 0
|
|
70
|
-
let y = 0
|
|
71
|
-
|
|
72
|
-
// Horizontal alignment
|
|
73
|
-
if (alignment === "center") {
|
|
74
|
-
x = -totalWidth / 2
|
|
75
|
-
} else if (
|
|
76
|
-
alignment === "top_left" ||
|
|
77
|
-
alignment === "bottom_left" ||
|
|
78
|
-
alignment === "left"
|
|
79
|
-
) {
|
|
80
|
-
x = 0
|
|
81
|
-
} else if (
|
|
82
|
-
alignment === "top_right" ||
|
|
83
|
-
alignment === "bottom_right" ||
|
|
84
|
-
alignment === "right"
|
|
85
|
-
) {
|
|
86
|
-
x = -totalWidth
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Vertical alignment
|
|
90
|
-
if (alignment === "center") {
|
|
91
|
-
y = -totalHeight / 2
|
|
92
|
-
} else if (
|
|
93
|
-
alignment === "top_left" ||
|
|
94
|
-
alignment === "top_right" ||
|
|
95
|
-
alignment === "top"
|
|
96
|
-
) {
|
|
97
|
-
y = 0
|
|
98
|
-
} else if (
|
|
99
|
-
alignment === "bottom_left" ||
|
|
100
|
-
alignment === "bottom_right" ||
|
|
101
|
-
alignment === "bottom"
|
|
102
|
-
) {
|
|
103
|
-
y = -totalHeight
|
|
104
|
-
} else {
|
|
105
|
-
y = 0
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return { x, y }
|
|
109
|
-
}
|
|
110
|
-
|
|
111
12
|
export function strokeAlphabetText(
|
|
112
13
|
ctx: CanvasContext,
|
|
113
14
|
text: string,
|
|
@@ -154,7 +55,7 @@ export interface DrawTextParams {
|
|
|
154
55
|
fontSize: number
|
|
155
56
|
color: string
|
|
156
57
|
realToCanvasMat: Matrix
|
|
157
|
-
anchorAlignment:
|
|
58
|
+
anchorAlignment: NinePointAnchor
|
|
158
59
|
rotation?: number
|
|
159
60
|
}
|
|
160
61
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "circuit-to-canvas",
|
|
3
3
|
"main": "dist/index.js",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.19",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"build": "tsup-node ./lib/index.ts --format esm --dts",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"circuit-json": "^0.0.335",
|
|
21
21
|
"circuit-json-to-connectivity-map": "^0.0.23",
|
|
22
22
|
"circuit-to-svg": "^0.0.297",
|
|
23
|
+
"looks-same": "^10.0.1",
|
|
23
24
|
"schematic-symbols": "^0.0.202",
|
|
24
25
|
"tsup": "^8.5.1"
|
|
25
26
|
},
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import type { AnyCircuitElement } from "circuit-json"
|
|
3
|
+
import { getStackedPngSvgComparison } from "../fixtures/getStackedPngSvgComparison"
|
|
4
|
+
import usbcFlashlightCircuit from "./usb-c-flashlight.json"
|
|
5
|
+
|
|
6
|
+
const circuitElements = usbcFlashlightCircuit as AnyCircuitElement[]
|
|
7
|
+
|
|
8
|
+
test.skip("USB-C flashlight - comprehensive comparison (circuit-to-canvas vs circuit-to-svg)", async () => {
|
|
9
|
+
const stackedPng = await getStackedPngSvgComparison(circuitElements, {
|
|
10
|
+
width: 400,
|
|
11
|
+
height: 800,
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
await expect(stackedPng).toMatchPngSnapshot(import.meta.path)
|
|
15
|
+
})
|