circuit-to-canvas 0.0.111 → 0.0.112

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 CHANGED
@@ -1,4 +1,4 @@
1
- import { AnyCircuitElement, PcbRenderLayer, NinePointAnchor, PcbPlatedHole, PCBVia, PcbHole, PcbSmtPad, PcbVia, PcbCutout, PcbTrace, PcbBoard, PcbPanel, PcbSilkscreenText, PcbSilkscreenRect, PcbSilkscreenCircle, PcbSilkscreenLine, PcbSilkscreenPath, PcbSilkscreenPill, PcbSilkscreenOval, PCBKeepout, PcbCopperPour, PcbCopperText, PcbFabricationNoteText, PcbFabricationNoteRect, PcbNoteRect, PcbFabricationNotePath, PcbNotePath, PcbNoteText, PcbNoteDimension, PcbFabricationNoteDimension, PcbCourtyardCircle } from 'circuit-json';
1
+ import { LayerRef, AnyCircuitElement, PcbRenderLayer, NinePointAnchor, PcbPlatedHole, PCBVia, PcbHole, PcbSmtPad, PcbVia, PcbCutout, PcbTrace, PcbBoard, PcbPanel, PcbSilkscreenText, PcbSilkscreenRect, PcbSilkscreenCircle, PcbSilkscreenLine, PcbSilkscreenPath, PcbSilkscreenPill, PcbSilkscreenOval, PCBKeepout, PcbCopperPour, PcbCopperText, PcbFabricationNoteText, PcbFabricationNoteRect, PcbNoteRect, PcbFabricationNotePath, PcbNotePath, PcbNoteText, PcbNoteDimension, PcbFabricationNoteDimension, PcbCourtyardCircle } from 'circuit-json';
2
2
  import { Matrix } from 'transformation-matrix';
3
3
 
4
4
  /**
@@ -44,7 +44,7 @@ interface CanvasContext {
44
44
  font: string;
45
45
  textAlign: "start" | "end" | "left" | "right" | "center";
46
46
  }
47
- type CopperLayerName = "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6";
47
+ type CopperLayerName = LayerRef;
48
48
  type CopperColorMap = Record<CopperLayerName, string> & {
49
49
  [layer: string]: string;
50
50
  };
@@ -333,7 +333,7 @@ interface DrawPcbPlatedHoleParams {
333
333
  colorMap: PcbColorMap;
334
334
  soldermaskMargin?: number;
335
335
  drawSoldermask?: boolean;
336
- layer?: "top" | "bottom";
336
+ layer?: LayerRef;
337
337
  }
338
338
  declare function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void;
339
339
 
@@ -342,7 +342,7 @@ interface DrawPcbViaParams {
342
342
  via: PCBVia;
343
343
  realToCanvasMat: Matrix;
344
344
  colorMap: PcbColorMap;
345
- layer?: "top" | "bottom";
345
+ layer?: LayerRef;
346
346
  }
347
347
  declare function drawPcbVia(params: DrawPcbViaParams): void;
348
348
 
package/dist/index.js CHANGED
@@ -5217,6 +5217,8 @@ var DEFAULT_PCB_COLOR_MAP = {
5217
5217
  inner4: "rgb(64, 224, 208)",
5218
5218
  inner5: "rgb(138, 43, 226)",
5219
5219
  inner6: "rgb(255, 105, 180)",
5220
+ inner7: "rgb(232, 178, 167)",
5221
+ inner8: "rgb(242, 237, 161)",
5220
5222
  bottom: "rgb(77, 127, 196)"
5221
5223
  },
5222
5224
  copperPour: {
@@ -5256,9 +5258,10 @@ var DEFAULT_PCB_COLOR_MAP = {
5256
5258
  // lib/drawer/CircuitToCanvasDrawer.ts
5257
5259
  function getCopperLayer(layers) {
5258
5260
  if (!layers || layers.length === 0) return "top";
5259
- const hasBottom = layers.some((l) => l.startsWith("bottom"));
5260
- return hasBottom ? "bottom" : "top";
5261
+ const copperLayer = layers.find((candidate) => candidate.endsWith("_copper"));
5262
+ return copperLayer ? copperLayer.slice(0, -"_copper".length) : "top";
5261
5263
  }
5264
+ var isOnCopperLayer = (element, layer) => element.layers?.includes(layer) ?? true;
5262
5265
  var CircuitToCanvasDrawer = class {
5263
5266
  ctx;
5264
5267
  colorMap;
@@ -5344,13 +5347,13 @@ var CircuitToCanvasDrawer = class {
5344
5347
  const renderTopSoldermask = drawSoldermask && (board !== void 0 || panel !== void 0) && (options.drawSoldermaskTop ?? !hasExplicitSoldermaskLayers);
5345
5348
  const renderBottomSoldermask = drawSoldermask && (board !== void 0 || panel !== void 0) && (options.drawSoldermaskBottom ?? false);
5346
5349
  const drawableVias = elements.filter(
5347
- (el) => shouldDrawElement(el, options) && el.type === "pcb_via"
5350
+ (el) => shouldDrawElement(el, options) && el.type === "pcb_via" && isOnCopperLayer(el, layer)
5348
5351
  );
5349
5352
  const drawableHoles = elements.filter(
5350
5353
  (el) => shouldDrawElement(el, options) && el.type === "pcb_hole"
5351
5354
  );
5352
5355
  const drawablePlatedHoles = elements.filter(
5353
- (el) => shouldDrawElement(el, options) && el.type === "pcb_plated_hole"
5356
+ (el) => shouldDrawElement(el, options) && el.type === "pcb_plated_hole" && isOnCopperLayer(el, layer)
5354
5357
  );
5355
5358
  const drawableCutouts = elements.filter(
5356
5359
  (el) => shouldDrawElement(el, options) && el.type === "pcb_cutout"
@@ -5425,7 +5428,7 @@ var CircuitToCanvasDrawer = class {
5425
5428
  drawSoldermask: renderTopSoldermask
5426
5429
  });
5427
5430
  }
5428
- if (element.type === "pcb_plated_hole") {
5431
+ if (element.type === "pcb_plated_hole" && isOnCopperLayer(element, layer)) {
5429
5432
  drawPcbPlatedHole({
5430
5433
  ctx: this.ctx,
5431
5434
  hole: element,
@@ -5436,7 +5439,7 @@ var CircuitToCanvasDrawer = class {
5436
5439
  layer
5437
5440
  });
5438
5441
  }
5439
- if (element.type === "pcb_via") {
5442
+ if (element.type === "pcb_via" && isOnCopperLayer(element, layer)) {
5440
5443
  drawPcbVia({
5441
5444
  ctx: this.ctx,
5442
5445
  via: element,
@@ -5544,7 +5547,7 @@ var CircuitToCanvasDrawer = class {
5544
5547
  }
5545
5548
  for (const element of elements) {
5546
5549
  if (!shouldDrawElement(element, options)) continue;
5547
- if (element.type === "pcb_plated_hole" && !renderTopSoldermask) {
5550
+ if (element.type === "pcb_plated_hole" && !renderTopSoldermask && isOnCopperLayer(element, layer)) {
5548
5551
  drawPcbPlatedHole({
5549
5552
  ctx: this.ctx,
5550
5553
  hole: element,
@@ -5555,7 +5558,7 @@ var CircuitToCanvasDrawer = class {
5555
5558
  layer
5556
5559
  });
5557
5560
  }
5558
- if (element.type === "pcb_via" && !renderTopSoldermask) {
5561
+ if (element.type === "pcb_via" && !renderTopSoldermask && isOnCopperLayer(element, layer)) {
5559
5562
  drawPcbVia({
5560
5563
  ctx: this.ctx,
5561
5564
  via: element,
@@ -1,5 +1,6 @@
1
1
  import type {
2
2
  AnyCircuitElement,
3
+ LayerRef,
3
4
  PCBKeepout,
4
5
  PcbBoard,
5
6
  PcbCopperPour,
@@ -94,12 +95,17 @@ interface CanvasLike {
94
95
  getContext(contextId: "2d"): CanvasContext | null
95
96
  }
96
97
 
97
- function getCopperLayer(layers?: PcbRenderLayer[]): "top" | "bottom" {
98
+ function getCopperLayer(layers?: PcbRenderLayer[]): LayerRef {
98
99
  if (!layers || layers.length === 0) return "top"
99
- const hasBottom = layers.some((l) => l.startsWith("bottom"))
100
- return hasBottom ? "bottom" : "top"
100
+ const copperLayer = layers.find((candidate) => candidate.endsWith("_copper"))
101
+ return copperLayer
102
+ ? (copperLayer.slice(0, -"_copper".length) as LayerRef)
103
+ : "top"
101
104
  }
102
105
 
106
+ const isOnCopperLayer = (element: PcbVia | PcbPlatedHole, layer: LayerRef) =>
107
+ element.layers?.includes(layer) ?? true
108
+
103
109
  export class CircuitToCanvasDrawer {
104
110
  private ctx: CanvasContext
105
111
  private colorMap: PcbColorMap
@@ -233,7 +239,9 @@ export class CircuitToCanvasDrawer {
233
239
  (options.drawSoldermaskBottom ?? false)
234
240
  const drawableVias = elements.filter(
235
241
  (el): el is PcbVia =>
236
- shouldDrawElement(el, options) && el.type === "pcb_via",
242
+ shouldDrawElement(el, options) &&
243
+ el.type === "pcb_via" &&
244
+ isOnCopperLayer(el, layer),
237
245
  )
238
246
  const drawableHoles = elements.filter(
239
247
  (el): el is PcbHole =>
@@ -241,7 +249,9 @@ export class CircuitToCanvasDrawer {
241
249
  )
242
250
  const drawablePlatedHoles = elements.filter(
243
251
  (el): el is PcbPlatedHole =>
244
- shouldDrawElement(el, options) && el.type === "pcb_plated_hole",
252
+ shouldDrawElement(el, options) &&
253
+ el.type === "pcb_plated_hole" &&
254
+ isOnCopperLayer(el, layer),
245
255
  )
246
256
  const drawableCutouts = elements.filter(
247
257
  (el): el is PcbCutout =>
@@ -332,7 +342,10 @@ export class CircuitToCanvasDrawer {
332
342
  })
333
343
  }
334
344
 
335
- if (element.type === "pcb_plated_hole") {
345
+ if (
346
+ element.type === "pcb_plated_hole" &&
347
+ isOnCopperLayer(element, layer)
348
+ ) {
336
349
  drawPcbPlatedHole({
337
350
  ctx: this.ctx,
338
351
  hole: element as PcbPlatedHole,
@@ -344,7 +357,7 @@ export class CircuitToCanvasDrawer {
344
357
  })
345
358
  }
346
359
 
347
- if (element.type === "pcb_via") {
360
+ if (element.type === "pcb_via" && isOnCopperLayer(element, layer)) {
348
361
  drawPcbVia({
349
362
  ctx: this.ctx,
350
363
  via: element as PcbVia,
@@ -474,7 +487,11 @@ export class CircuitToCanvasDrawer {
474
487
  for (const element of elements) {
475
488
  if (!shouldDrawElement(element, options)) continue
476
489
 
477
- if (element.type === "pcb_plated_hole" && !renderTopSoldermask) {
490
+ if (
491
+ element.type === "pcb_plated_hole" &&
492
+ !renderTopSoldermask &&
493
+ isOnCopperLayer(element, layer)
494
+ ) {
478
495
  drawPcbPlatedHole({
479
496
  ctx: this.ctx,
480
497
  hole: element as PcbPlatedHole,
@@ -488,7 +505,11 @@ export class CircuitToCanvasDrawer {
488
505
  })
489
506
  }
490
507
 
491
- if (element.type === "pcb_via" && !renderTopSoldermask) {
508
+ if (
509
+ element.type === "pcb_via" &&
510
+ !renderTopSoldermask &&
511
+ isOnCopperLayer(element, layer)
512
+ ) {
492
513
  drawPcbVia({
493
514
  ctx: this.ctx,
494
515
  via: element as PcbVia,
@@ -1,4 +1,4 @@
1
- import type { PcbPlatedHole } from "circuit-json"
1
+ import type { LayerRef, PcbPlatedHole } from "circuit-json"
2
2
  import type { Matrix } from "transformation-matrix"
3
3
  import { drawCircle } from "../shapes/circle"
4
4
  import { drawOval } from "../shapes/oval"
@@ -15,7 +15,7 @@ export interface DrawPcbPlatedHoleParams {
15
15
  colorMap: PcbColorMap
16
16
  soldermaskMargin?: number
17
17
  drawSoldermask?: boolean
18
- layer?: "top" | "bottom"
18
+ layer?: LayerRef
19
19
  }
20
20
 
21
21
  export function drawPcbPlatedHole(params: DrawPcbPlatedHoleParams): void {
@@ -1,4 +1,4 @@
1
- import type { PCBVia } from "circuit-json"
1
+ import type { LayerRef, PCBVia } from "circuit-json"
2
2
  import type { Matrix } from "transformation-matrix"
3
3
  import { drawCircle } from "../shapes/circle"
4
4
  import type { CanvasContext, PcbColorMap } from "../types"
@@ -8,7 +8,7 @@ export interface DrawPcbViaParams {
8
8
  via: PCBVia
9
9
  realToCanvasMat: Matrix
10
10
  colorMap: PcbColorMap
11
- layer?: "top" | "bottom"
11
+ layer?: LayerRef
12
12
  }
13
13
 
14
14
  export function drawPcbVia(params: DrawPcbViaParams): void {
@@ -1,3 +1,4 @@
1
+ import type { LayerRef } from "circuit-json"
1
2
  import type { Matrix } from "transformation-matrix"
2
3
 
3
4
  /**
@@ -56,15 +57,7 @@ export interface CanvasContext {
56
57
  textAlign: "start" | "end" | "left" | "right" | "center"
57
58
  }
58
59
 
59
- export type CopperLayerName =
60
- | "top"
61
- | "bottom"
62
- | "inner1"
63
- | "inner2"
64
- | "inner3"
65
- | "inner4"
66
- | "inner5"
67
- | "inner6"
60
+ export type CopperLayerName = LayerRef
68
61
 
69
62
  export type CopperColorMap = Record<CopperLayerName, string> & {
70
63
  [layer: string]: string
@@ -115,6 +108,8 @@ export const DEFAULT_PCB_COLOR_MAP: PcbColorMap = {
115
108
  inner4: "rgb(64, 224, 208)",
116
109
  inner5: "rgb(138, 43, 226)",
117
110
  inner6: "rgb(255, 105, 180)",
111
+ inner7: "rgb(232, 178, 167)",
112
+ inner8: "rgb(242, 237, 161)",
118
113
  bottom: "rgb(77, 127, 196)",
119
114
  },
120
115
  copperPour: {
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.111",
4
+ "version": "0.0.112",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "build": "tsup-node ./lib/index.ts --format esm --dts",
@@ -13,13 +13,14 @@
13
13
  "@napi-rs/canvas": "^0.1.84",
14
14
  "@resvg/resvg-js": "^2.6.2",
15
15
  "@tscircuit/alphabet": "^0.0.23",
16
- "@tscircuit/circuit-json-util": "^0.0.91",
16
+ "@tscircuit/circuit-json-util": "^0.0.99",
17
17
  "@tscircuit/math-utils": "^0.0.36",
18
18
  "@types/bun": "latest",
19
19
  "bun-match-svg": "^0.0.14",
20
- "circuit-json": "^0.0.433",
20
+ "circuit-json": "^0.0.450",
21
21
  "circuit-json-to-connectivity-map": "^0.0.23",
22
- "circuit-to-svg": "^0.0.324",
22
+ "circuit-to-svg": "^0.0.390",
23
+ "format-si-unit": "^0.0.7",
23
24
  "looks-same": "^10.0.1",
24
25
  "schematic-symbols": "^0.0.202",
25
26
  "tsup": "^8.5.1"
@@ -1,9 +1,12 @@
1
1
  import { expect, test } from "bun:test"
2
2
  import { createCanvas } from "@napi-rs/canvas"
3
- import type { AnyCircuitElement } from "circuit-json"
3
+ import type { AnyCircuitElement, LayerRef, PcbRenderLayer } from "circuit-json"
4
4
  import { CircuitToCanvasDrawer } from "../../lib/drawer"
5
5
 
6
- function renderCopperPourScene(elements: AnyCircuitElement[]): Buffer {
6
+ function renderCopperPourScene(
7
+ elements: AnyCircuitElement[],
8
+ layer: LayerRef,
9
+ ): Buffer {
7
10
  const canvas = createCanvas(100, 100)
8
11
  const ctx = canvas.getContext("2d")
9
12
  const drawer = new CircuitToCanvasDrawer(ctx)
@@ -11,7 +14,9 @@ function renderCopperPourScene(elements: AnyCircuitElement[]): Buffer {
11
14
  ctx.fillStyle = "#1a1a1a"
12
15
  ctx.fillRect(0, 0, 100, 100)
13
16
 
14
- drawer.drawElements(elements)
17
+ drawer.drawElements(elements, {
18
+ layers: [`${layer}_copper` as PcbRenderLayer],
19
+ })
15
20
 
16
21
  return canvas.toBuffer("image/png")
17
22
  }
@@ -23,6 +28,8 @@ const INNER_LAYERS = [
23
28
  "inner4",
24
29
  "inner5",
25
30
  "inner6",
31
+ "inner7",
32
+ "inner8",
26
33
  ] as const
27
34
 
28
35
  function createCopperPourWithTraceScene(
@@ -78,9 +85,10 @@ for (const layer of INNER_LAYERS) {
78
85
  test(`draw ${layer} copper pour with trace`, async () => {
79
86
  const elements = createCopperPourWithTraceScene(layer)
80
87
 
81
- const withTrace = renderCopperPourScene(elements)
88
+ const withTrace = renderCopperPourScene(elements, layer)
82
89
  const withoutTrace = renderCopperPourScene(
83
90
  elements.filter((element) => element.type !== "pcb_trace"),
91
+ layer,
84
92
  )
85
93
 
86
94
  expect(Buffer.compare(withTrace, withoutTrace)).not.toBe(0)
@@ -0,0 +1,36 @@
1
+ import { expect, test } from "bun:test"
2
+ import { createCanvas } from "@napi-rs/canvas"
3
+ import type { PcbRenderLayer, PcbVia } from "circuit-json"
4
+ import { CircuitToCanvasDrawer } from "../../lib/drawer"
5
+
6
+ const renderViaLayer = (via: PcbVia | undefined, layer: PcbRenderLayer) => {
7
+ const canvas = createCanvas(100, 100)
8
+ const ctx = canvas.getContext("2d")
9
+ const drawer = new CircuitToCanvasDrawer(ctx)
10
+
11
+ ctx.fillStyle = "#1a1a1a"
12
+ ctx.fillRect(0, 0, 100, 100)
13
+ drawer.drawElements(via ? [via] : [], { layers: [layer] })
14
+
15
+ return canvas.toBuffer("image/png")
16
+ }
17
+
18
+ test("draw buried via only on layers in its span", async () => {
19
+ const via: PcbVia = {
20
+ type: "pcb_via",
21
+ pcb_via_id: "via_inner8",
22
+ x: 50,
23
+ y: 50,
24
+ outer_diameter: 40,
25
+ hole_diameter: 20,
26
+ layers: ["inner7", "inner8"],
27
+ }
28
+
29
+ const inner8 = renderViaLayer(via, "inner8_copper")
30
+ const inner6 = renderViaLayer(via, "inner6_copper")
31
+ const blank = renderViaLayer(undefined, "inner6_copper")
32
+
33
+ expect(Buffer.compare(inner8, blank)).not.toBe(0)
34
+ expect(Buffer.compare(inner6, blank)).toBe(0)
35
+ await expect(inner8).toMatchPngSnapshot(import.meta.path)
36
+ })