app
Adom Symbol
Public Made by Adomby adom
KiCad symbol creator with interactive viewer and delivery to KiCad/Fusion 360
← Commit history
1.1.6: remove KiCad drawing-sheet by STRIPPING elements outside the symbol box (not clipping) — fixes the app's 3D-chip outline disappearing + keeps the worksheet off on zoom-out; flat SVG so pan/zoom + 3D layering are intact
5 files changed
+69−23
Cargo.toml+1−1@@ -1,6 +1,6 @@ [package] name = "adom-symbol"-version = "1.1.5"+version = "1.1.6" edition = "2021" description = "Create and preview KiCad/Fusion 360 schematic symbols with interactive viewer"
VERSION+1−1@@ -1 +1 @@-1.1.5+1.1.6
bin/adom-symbol⋯ 1 unchanged line ⋯
package.json+1−1@@ -1,6 +1,6 @@ { "slug": "adom-symbol",- "version": "1.1.5",+ "version": "1.1.6", "type": "app", "description": "KiCad symbol creator with interactive viewer and delivery to KiCad/Fusion 360", "dependencies": {
src/render.rs+66−20@@ -37,34 +37,76 @@ pub fn render_symbol_svg(kicad_sym: &str, symbol_name: &str) -> Result<String> { // Drop KiCad 10's warm-white page background so the dark canvas shows. let svg = svg.replace("fill:#F5F4EF", "fill:none").replace("stroke:#F5F4EF", "stroke:none");+ // crop_to_symbol also STRIPS the KiCad drawing-sheet (A4 border + Sheet/File/+ // Title/Size title block) — every top-level element that lies entirely outside+ // the symbol's box is deleted, so it can't appear on zoom-out. Removing it+ // (rather than clipping) keeps the SVG flat, so the app's SVG-space pan/zoom+ // and its 3D-chip layering are untouched. let cropped = crop_to_symbol(&svg, &block); let themed = crate::theme::apply_dark_theme_to_symbol(&cropped);- // Hard-clip everything to the symbol's viewBox so KiCad's A4 drawing sheet- // (border + "Sheet/File/Title/Size" title block, drawn out at the page edges)- // can NEVER appear when the viewer zooms out. We want a symbol, not a sheet.- Ok(clip_to_viewbox(&themed))+ Ok(strip_drawing_sheet(&themed)) } -/// Wrap the SVG body in a userSpace clip = its own viewBox, so nothing painted-/// outside the symbol's cropped box (i.e. the KiCad worksheet frame + title-/// block) is ever visible — even under the viewer's CSS zoom-out transform.-fn clip_to_viewbox(svg: &str) -> String {+/// Delete the KiCad drawing-sheet (A4 border + "Sheet/File/Title/Size" title+/// block) from the SVG: every `<path>`/`<polyline>`/`<text>` whose coordinates+/// lie ENTIRELY outside the symbol's viewBox (the sheet is drawn out at the page+/// edges, axis-aligned) is dropped. Removing it — rather than clipping — keeps+/// the SVG flat, so the app's SVG-space pan/zoom transform and its 3D-chip+/// layering are untouched, and nothing can appear on zoom-out.+fn strip_drawing_sheet(svg: &str) -> String { let vb = Regex::new(r#"viewBox="(-?[\d.]+) (-?[\d.]+) (-?[\d.]+) (-?[\d.]+)""#).unwrap();- let (x, y, w, h) = match vb.captures(svg) {- Some(c) => (c[1].to_string(), c[2].to_string(), c[3].to_string(), c[4].to_string()),+ let (vx, vy, vw, vh) = match vb.captures(svg) {+ Some(c) => (+ c[1].parse::<f64>().unwrap_or(0.0),+ c[2].parse::<f64>().unwrap_or(0.0),+ c[3].parse::<f64>().unwrap_or(0.0),+ c[4].parse::<f64>().unwrap_or(0.0),+ ), None => return svg.to_string(), };- let open = format!(- "<defs><clipPath id=\"asym-crop\" clipPathUnits=\"userSpaceOnUse\"><rect x=\"{x}\" y=\"{y}\" width=\"{w}\" height=\"{h}\"/></clipPath></defs><g clip-path=\"url(#asym-crop)\">"- );- match svg.find('>') {- Some(pos) => {- let (head, tail) = svg.split_at(pos + 1);- let body = tail.strip_suffix("</svg>").unwrap_or(tail);- format!("{head}{open}{body}</g></svg>")+ let m = 1.0;+ let (x0, x1, y0, y1) = (vx - m, vx + vw + m, vy - m, vy + vh + m);+ let num = Regex::new(r"-?\d+\.?\d*").unwrap();+ // A shape is drawing-sheet iff ALL its X are outside the box OR ALL its Y are+ // (true for the axis-aligned page border + the bottom-right title block, never+ // for the symbol, which lives inside the box).+ let outside = |coords: &str, attr_pair: Option<(f64, f64)>| -> bool {+ let nums: Vec<f64> = match attr_pair {+ Some((x, y)) => vec![x, y],+ None => num.find_iter(coords).filter_map(|m| m.as_str().parse().ok()).collect(),+ };+ if nums.len() < 2 {+ return false; }- None => svg.to_string(),+ let all_x_out = nums.iter().step_by(2).all(|&x| x < x0 || x > x1);+ let all_y_out = nums.iter().skip(1).step_by(2).all(|&y| y < y0 || y > y1);+ all_x_out || all_y_out+ };+ let mut s = svg.to_string();+ for attr in ["d", "points"] {+ let re = Regex::new(&format!(r#"<(?:path|polyline)\b[^>]*\b{attr}="([^"]*)"[^>]*/?>"#)).unwrap();+ s = re+ .replace_all(&s, |c: ®ex::Captures| {+ if outside(&c[1], None) { String::new() } else { c[0].to_string() }+ })+ .into_owned(); }+ // Invisible title-block strings (<text x=".." y="..">Sheet: /…</text>); their+ // paired stroked-text glyph <path>s are already gone from the pass above.+ let tre = Regex::new(r#"<text\b([^>]*)>[^<]*</text>"#).unwrap();+ let xre = Regex::new(r#"\bx="(-?[\d.]+)""#).unwrap();+ let yre = Regex::new(r#"\by="(-?[\d.]+)""#).unwrap();+ tre.replace_all(&s, |c: ®ex::Captures| {+ let a = &c[1];+ match (+ xre.captures(a).and_then(|m| m[1].parse::<f64>().ok()),+ yre.captures(a).and_then(|m| m[1].parse::<f64>().ok()),+ ) {+ (Some(x), Some(y)) if outside("", Some((x, y))) => String::new(),+ _ => c[0].to_string(),+ }+ })+ .into_owned() } fn extract_symbol_block(content: &str, name: &str) -> Option<String> {@@ -97,6 +139,10 @@ fn build_schematic(name: &str, block: &str) -> String { let (rx, ry) = prop_at(block, "Reference").unwrap_or((0.0, 12.7)); let (vx, vy) = prop_at(block, "Value").unwrap_or((0.0, -12.7)); let rpre = prop_val(block, "Reference").unwrap_or_else(|| "U".to_string());+ // The on-canvas Value is the symbol's OWN Value property (a short human value+ // like "33Ω" for a clean discrete) — NOT the symbol name (the MPN). Falling+ // back to the name only when there is no Value keeps IC behavior unchanged.+ let vval = prop_val(block, "Value").filter(|v| !v.is_empty()).unwrap_or_else(|| name.to_string()); let rjust = prop_justify(block, "Reference"); let vjust = prop_justify(block, "Value"); // If the library symbol hides the Value (chip name laser-marked on the 3D@@ -114,7 +160,7 @@ fn build_schematic(name: &str, block: &str) -> String { (in_bom yes) (on_board yes)\n \ (uuid \"00000000-0000-0000-0000-000000000002\")\n \ (property \"Reference\" \"{rpre}?\" (at {srx:.3} {sry:.3} 0) (effects (font (size 1.27 1.27)){rjust}))\n \- (property \"Value\" \"{name}\" (at {svx:.3} {svy:.3} 0) (effects (font (size 1.27 1.27)){vjust}{vhide}))\n )\n \+ (property \"Value\" \"{vval}\" (at {svx:.3} {svy:.3} 0) (effects (font (size 1.27 1.27)){vjust}{vhide}))\n )\n \ (sheet_instances (path \"/\" (page \"1\")))\n)\n" ) }