circuit-to-svg 0.0.124 → 0.0.126

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,22 +1,22 @@
1
1
  import { AnyCircuitElement } from 'circuit-json';
2
2
 
3
- interface Options$2 {
3
+ interface Options$3 {
4
4
  width?: number;
5
5
  height?: number;
6
6
  shouldDrawErrors?: boolean;
7
7
  shouldDrawRatsNest?: boolean;
8
8
  }
9
- declare function convertCircuitJsonToPcbSvg(soup: AnyCircuitElement[], options?: Options$2): string;
9
+ declare function convertCircuitJsonToPcbSvg(soup: AnyCircuitElement[], options?: Options$3): string;
10
10
  /**
11
11
  * @deprecated use `convertCircuitJsonToPcbSvg` instead
12
12
  */
13
13
  declare const circuitJsonToPcbSvg: typeof convertCircuitJsonToPcbSvg;
14
14
 
15
- interface Options$1 {
15
+ interface Options$2 {
16
16
  width?: number;
17
17
  height?: number;
18
18
  }
19
- declare function convertCircuitJsonToAssemblySvg(soup: AnyCircuitElement[], options?: Options$1): string;
19
+ declare function convertCircuitJsonToAssemblySvg(soup: AnyCircuitElement[], options?: Options$2): string;
20
20
 
21
21
  declare const colorMap: {
22
22
  "3d_viewer": {
@@ -181,7 +181,7 @@ type ColorMap = typeof colorMap;
181
181
  type ColorOverrides = {
182
182
  schematic?: Partial<ColorMap["schematic"]>;
183
183
  };
184
- interface Options {
184
+ interface Options$1 {
185
185
  colorOverrides?: ColorOverrides;
186
186
  width?: number;
187
187
  height?: number;
@@ -195,10 +195,17 @@ interface Options {
195
195
  label: string;
196
196
  }>;
197
197
  }
198
- declare function convertCircuitJsonToSchematicSvg(circuitJson: AnyCircuitElement[], options?: Options): string;
198
+ declare function convertCircuitJsonToSchematicSvg(circuitJson: AnyCircuitElement[], options?: Options$1): string;
199
199
  /**
200
200
  * @deprecated use `convertCircuitJsonToSchematicSvg` instead
201
201
  */
202
202
  declare const circuitJsonToSchematicSvg: typeof convertCircuitJsonToSchematicSvg;
203
203
 
204
- export { type ColorMap, type ColorOverrides, circuitJsonToPcbSvg, circuitJsonToSchematicSvg, convertCircuitJsonToAssemblySvg, convertCircuitJsonToPcbSvg, convertCircuitJsonToSchematicSvg };
204
+ interface Options {
205
+ layer: "top" | "bottom";
206
+ width?: number;
207
+ height?: number;
208
+ }
209
+ declare function convertCircuitJsonToSolderPasteMask(soup: AnyCircuitElement[], options: Options): string;
210
+
211
+ export { type ColorMap, type ColorOverrides, circuitJsonToPcbSvg, circuitJsonToSchematicSvg, convertCircuitJsonToAssemblySvg, convertCircuitJsonToPcbSvg, convertCircuitJsonToSchematicSvg, convertCircuitJsonToSolderPasteMask };
package/dist/index.js CHANGED
@@ -578,7 +578,8 @@ function createSvgObjectsFromPcbSilkscreenText(pcbSilkscreenText, transform) {
578
578
  text,
579
579
  font_size = 1,
580
580
  layer = "top",
581
- ccw_rotation = 0
581
+ ccw_rotation = 0,
582
+ anchor_alignment = "center"
582
583
  } = pcbSilkscreenText;
583
584
  if (!anchor_position || typeof anchor_position.x !== "number" || typeof anchor_position.y !== "number") {
584
585
  console.error("Invalid anchor_position:", anchor_position);
@@ -589,6 +590,33 @@ function createSvgObjectsFromPcbSilkscreenText(pcbSilkscreenText, transform) {
589
590
  anchor_position.y
590
591
  ]);
591
592
  const transformedFontSize = font_size * Math.abs(transform.a);
593
+ let textAnchor = "middle";
594
+ let dominantBaseline = "central";
595
+ let dx = 0;
596
+ let dy = 0;
597
+ switch (anchor_alignment) {
598
+ case "top_left":
599
+ textAnchor = "start";
600
+ dominantBaseline = "text-before-edge";
601
+ break;
602
+ case "top_right":
603
+ textAnchor = "end";
604
+ dominantBaseline = "text-before-edge";
605
+ break;
606
+ case "bottom_left":
607
+ textAnchor = "start";
608
+ dominantBaseline = "text-after-edge";
609
+ break;
610
+ case "bottom_right":
611
+ textAnchor = "end";
612
+ dominantBaseline = "text-after-edge";
613
+ break;
614
+ case "center":
615
+ default:
616
+ textAnchor = "middle";
617
+ dominantBaseline = "central";
618
+ break;
619
+ }
592
620
  const textTransform = compose2(
593
621
  translate2(transformedX, transformedY),
594
622
  rotate2(ccw_rotation * Math.PI / 180),
@@ -601,11 +629,13 @@ function createSvgObjectsFromPcbSilkscreenText(pcbSilkscreenText, transform) {
601
629
  attributes: {
602
630
  x: "0",
603
631
  y: "0",
632
+ dx: dx.toString(),
633
+ dy: dy.toString(),
604
634
  fill: color,
605
635
  "font-family": "Arial, sans-serif",
606
636
  "font-size": transformedFontSize.toString(),
607
- "text-anchor": "middle",
608
- "dominant-baseline": "central",
637
+ "text-anchor": textAnchor,
638
+ "dominant-baseline": dominantBaseline,
609
639
  transform: matrixToString2(textTransform),
610
640
  class: `pcb-silkscreen-text pcb-silkscreen-${layer}`,
611
641
  "data-pcb-silkscreen-text-id": pcbSilkscreenText.pcb_component_id,
@@ -773,6 +803,13 @@ var LAYER_NAME_TO_COLOR = {
773
803
  function layerNameToColor(layerName) {
774
804
  return LAYER_NAME_TO_COLOR[layerName] ?? "white";
775
805
  }
806
+ var SOLDER_PASTE_LAYER_NAME_TO_COLOR = {
807
+ bottom: "rgb(105, 105, 105)",
808
+ top: "rgb(105, 105, 105)"
809
+ };
810
+ function solderPasteLayerNameToColor(layerName) {
811
+ return SOLDER_PASTE_LAYER_NAME_TO_COLOR[layerName] ?? "rgb(105, 105, 105)";
812
+ }
776
813
 
777
814
  // lib/pcb/svg-object-fns/create-svg-objects-from-pcb-trace.ts
778
815
  function createSvgObjectsFromPcbTrace(trace, transform) {
@@ -4093,8 +4130,8 @@ var ninePointAnchorToDominantBaseline = {
4093
4130
  middle_bottom: "hanging"
4094
4131
  };
4095
4132
  function getTextOffsets(pathRotation, transform) {
4096
- const scale8 = Math.abs(transform.a);
4097
- const baseOffset = scale8 * 0.1;
4133
+ const scale9 = Math.abs(transform.a);
4134
+ const baseOffset = scale9 * 0.1;
4098
4135
  const rotationOffsetMap = {
4099
4136
  "0": { x: baseOffset * 0.8, y: -baseOffset },
4100
4137
  // Left
@@ -4248,8 +4285,8 @@ var createSvgObjectsForSchNetLabelWithSymbol = ({
4248
4285
  } else if (textValue === "{VAL}") {
4249
4286
  textValue = "";
4250
4287
  }
4251
- const scale8 = Math.abs(realToScreenTransform.a);
4252
- const baseOffset = scale8 * 0.1;
4288
+ const scale9 = Math.abs(realToScreenTransform.a);
4289
+ const baseOffset = scale9 * 0.1;
4253
4290
  const rotationOffset = getTextOffsets(pathRotation, realToScreenTransform);
4254
4291
  const offsetScreenPos = {
4255
4292
  x: screenTextPos.x + rotationOffset.x,
@@ -4659,11 +4696,237 @@ function convertCircuitJsonToSchematicSvg(circuitJson, options) {
4659
4696
  return stringify3(svgObject);
4660
4697
  }
4661
4698
  var circuitJsonToSchematicSvg = convertCircuitJsonToSchematicSvg;
4699
+
4700
+ // lib/pcb/convert-circuit-json-to-solder-paste-mask.ts
4701
+ import { stringify as stringify4 } from "svgson";
4702
+ import {
4703
+ applyToPoint as applyToPoint38,
4704
+ compose as compose10,
4705
+ scale as scale8,
4706
+ translate as translate10
4707
+ } from "transformation-matrix";
4708
+
4709
+ // lib/pcb/svg-object-fns/convert-circuit-json-to-solder-paste-mask.ts
4710
+ import { applyToPoint as applyToPoint37 } from "transformation-matrix";
4711
+ function createSvgObjectsFromSolderPaste(solderPaste, transform) {
4712
+ const [x, y] = applyToPoint37(transform, [solderPaste.x, solderPaste.y]);
4713
+ if (solderPaste.shape === "rect" || solderPaste.shape === "rotated_rect") {
4714
+ const width = solderPaste.width * Math.abs(transform.a);
4715
+ const height = solderPaste.height * Math.abs(transform.d);
4716
+ if (solderPaste.shape === "rotated_rect" && solderPaste.ccw_rotation) {
4717
+ return [
4718
+ {
4719
+ name: "rect",
4720
+ type: "element",
4721
+ attributes: {
4722
+ class: "pcb-solder-paste",
4723
+ fill: solderPasteLayerNameToColor(solderPaste.layer),
4724
+ x: (-width / 2).toString(),
4725
+ y: (-height / 2).toString(),
4726
+ width: width.toString(),
4727
+ height: height.toString(),
4728
+ transform: `translate(${x} ${y}) rotate(${-solderPaste.ccw_rotation})`
4729
+ }
4730
+ }
4731
+ ];
4732
+ }
4733
+ return [
4734
+ {
4735
+ name: "rect",
4736
+ type: "element",
4737
+ attributes: {
4738
+ class: "pcb-solder-paste",
4739
+ fill: solderPasteLayerNameToColor(solderPaste.layer),
4740
+ x: (x - width / 2).toString(),
4741
+ y: (y - height / 2).toString(),
4742
+ width: width.toString(),
4743
+ height: height.toString()
4744
+ }
4745
+ }
4746
+ ];
4747
+ }
4748
+ if (solderPaste.shape === "pill") {
4749
+ const width = solderPaste.width * Math.abs(transform.a);
4750
+ const height = solderPaste.height * Math.abs(transform.d);
4751
+ const radius = solderPaste.radius * Math.abs(transform.a);
4752
+ return [
4753
+ {
4754
+ name: "rect",
4755
+ type: "element",
4756
+ attributes: {
4757
+ class: "pcb-solder-paste",
4758
+ fill: solderPasteLayerNameToColor(solderPaste.layer),
4759
+ x: (x - width / 2).toString(),
4760
+ y: (y - height / 2).toString(),
4761
+ width: width.toString(),
4762
+ height: height.toString(),
4763
+ rx: radius.toString()
4764
+ }
4765
+ }
4766
+ ];
4767
+ }
4768
+ if (solderPaste.shape === "circle") {
4769
+ const radius = solderPaste.radius * Math.abs(transform.a);
4770
+ return [
4771
+ {
4772
+ name: "circle",
4773
+ type: "element",
4774
+ attributes: {
4775
+ class: "pcb-solder-paste",
4776
+ fill: solderPasteLayerNameToColor(solderPaste.layer),
4777
+ cx: x.toString(),
4778
+ cy: y.toString(),
4779
+ r: radius.toString()
4780
+ }
4781
+ }
4782
+ ];
4783
+ }
4784
+ }
4785
+
4786
+ // lib/pcb/convert-circuit-json-to-solder-paste-mask.ts
4787
+ var OBJECT_ORDER3 = [
4788
+ "pcb_board",
4789
+ "pcb_solder_paste"
4790
+ ];
4791
+ function convertCircuitJsonToSolderPasteMask(soup, options) {
4792
+ let minX = Number.POSITIVE_INFINITY;
4793
+ let minY = Number.POSITIVE_INFINITY;
4794
+ let maxX = Number.NEGATIVE_INFINITY;
4795
+ let maxY = Number.NEGATIVE_INFINITY;
4796
+ const filteredSoup = soup.filter(
4797
+ (elm) => elm.type === "pcb_board" || elm.type === "pcb_solder_paste" && elm.layer === options.layer
4798
+ );
4799
+ for (const item of filteredSoup) {
4800
+ if (item.type === "pcb_board") {
4801
+ if (item.outline && Array.isArray(item.outline) && item.outline.length >= 3) {
4802
+ updateBoundsToIncludeOutline(item.outline);
4803
+ } else if ("center" in item && "width" in item && "height" in item) {
4804
+ updateBounds(item.center, item.width, item.height);
4805
+ }
4806
+ } else if (item.type === "pcb_solder_paste" && "x" in item && "y" in item) {
4807
+ updateBounds({ x: item.x, y: item.y }, 0, 0);
4808
+ }
4809
+ }
4810
+ const padding = 1;
4811
+ const circuitWidth = maxX - minX + 2 * padding;
4812
+ const circuitHeight = maxY - minY + 2 * padding;
4813
+ const svgWidth = options.width ?? 800;
4814
+ const svgHeight = options.height ?? 600;
4815
+ const scaleX = svgWidth / circuitWidth;
4816
+ const scaleY = svgHeight / circuitHeight;
4817
+ const scaleFactor = Math.min(scaleX, scaleY);
4818
+ const offsetX = (svgWidth - circuitWidth * scaleFactor) / 2;
4819
+ const offsetY = (svgHeight - circuitHeight * scaleFactor) / 2;
4820
+ const transform = compose10(
4821
+ translate10(
4822
+ offsetX - minX * scaleFactor + padding * scaleFactor,
4823
+ svgHeight - offsetY + minY * scaleFactor - padding * scaleFactor
4824
+ ),
4825
+ scale8(scaleFactor, -scaleFactor)
4826
+ // Flip in y-direction
4827
+ );
4828
+ const svgObjects = filteredSoup.sort(
4829
+ (a, b) => (OBJECT_ORDER3.indexOf(b.type) ?? 9999) - (OBJECT_ORDER3.indexOf(a.type) ?? 9999)
4830
+ ).flatMap((item) => createSvgObjects3(item, transform));
4831
+ const svgObject = {
4832
+ name: "svg",
4833
+ type: "element",
4834
+ attributes: {
4835
+ xmlns: "http://www.w3.org/2000/svg",
4836
+ width: svgWidth.toString(),
4837
+ height: svgHeight.toString()
4838
+ },
4839
+ value: "",
4840
+ children: [
4841
+ {
4842
+ name: "style",
4843
+ type: "element",
4844
+ children: [
4845
+ {
4846
+ type: "text",
4847
+ value: ""
4848
+ }
4849
+ ]
4850
+ },
4851
+ {
4852
+ name: "rect",
4853
+ type: "element",
4854
+ attributes: {
4855
+ class: "boundary",
4856
+ x: "0",
4857
+ y: "0",
4858
+ fill: "#000",
4859
+ width: svgWidth.toString(),
4860
+ height: svgHeight.toString()
4861
+ }
4862
+ },
4863
+ createSvgObjectFromPcbBoundary2(transform, minX, minY, maxX, maxY),
4864
+ ...svgObjects
4865
+ ].filter((child) => child !== null)
4866
+ };
4867
+ try {
4868
+ return stringify4(svgObject);
4869
+ } catch (error) {
4870
+ console.error("Error stringifying SVG object:", error);
4871
+ throw error;
4872
+ }
4873
+ function updateBounds(center, width, height) {
4874
+ const halfWidth = width / 2;
4875
+ const halfHeight = height / 2;
4876
+ minX = Math.min(minX, center.x - halfWidth);
4877
+ minY = Math.min(minY, center.y - halfHeight);
4878
+ maxX = Math.max(maxX, center.x + halfWidth);
4879
+ maxY = Math.max(maxY, center.y + halfHeight);
4880
+ }
4881
+ function updateBoundsToIncludeOutline(outline) {
4882
+ for (const point of outline) {
4883
+ minX = Math.min(minX, point.x);
4884
+ minY = Math.min(minY, point.y);
4885
+ maxX = Math.max(maxX, point.x);
4886
+ maxY = Math.max(maxY, point.y);
4887
+ }
4888
+ }
4889
+ }
4890
+ function createSvgObjects3(elm, transform) {
4891
+ switch (elm.type) {
4892
+ case "pcb_board":
4893
+ return createSvgObjectsFromPcbBoard(elm, transform);
4894
+ case "pcb_solder_paste":
4895
+ return createSvgObjectsFromSolderPaste(elm, transform);
4896
+ default:
4897
+ return [];
4898
+ }
4899
+ }
4900
+ function createSvgObjectFromPcbBoundary2(transform, minX, minY, maxX, maxY) {
4901
+ const [x1, y1] = applyToPoint38(transform, [minX, minY]);
4902
+ const [x2, y2] = applyToPoint38(transform, [maxX, maxY]);
4903
+ const width = Math.abs(x2 - x1);
4904
+ const height = Math.abs(y2 - y1);
4905
+ const x = Math.min(x1, x2);
4906
+ const y = Math.min(y1, y2);
4907
+ return {
4908
+ name: "rect",
4909
+ type: "element",
4910
+ value: "",
4911
+ children: [],
4912
+ attributes: {
4913
+ class: "pcb-boundary",
4914
+ fill: "none",
4915
+ stroke: "#fff",
4916
+ "stroke-width": "0.3",
4917
+ x: x.toString(),
4918
+ y: y.toString(),
4919
+ width: width.toString(),
4920
+ height: height.toString()
4921
+ }
4922
+ };
4923
+ }
4662
4924
  export {
4663
4925
  circuitJsonToPcbSvg,
4664
4926
  circuitJsonToSchematicSvg,
4665
4927
  convertCircuitJsonToAssemblySvg,
4666
4928
  convertCircuitJsonToPcbSvg,
4667
- convertCircuitJsonToSchematicSvg
4929
+ convertCircuitJsonToSchematicSvg,
4930
+ convertCircuitJsonToSolderPasteMask
4668
4931
  };
4669
4932
  //# sourceMappingURL=index.js.map