diff --git a/InteractiveHtmlBom/web/ibom.css b/InteractiveHtmlBom/web/ibom.css
index 11695286..f9eca784 100644
--- a/InteractiveHtmlBom/web/ibom.css
+++ b/InteractiveHtmlBom/web/ibom.css
@@ -11,7 +11,9 @@
--fabrication-polygon-color: #907651;
--fabrication-text-color: #a27c24;
--track-color: #def5f1;
+ --track-color-highlight: #D04040;
--zone-color: #def5f1;
+ --zone-color-highlight: #d0404080;
}
html, body {
diff --git a/InteractiveHtmlBom/web/ibom.js b/InteractiveHtmlBom/web/ibom.js
index 79013366..d2d51b31 100644
--- a/InteractiveHtmlBom/web/ibom.js
+++ b/InteractiveHtmlBom/web/ibom.js
@@ -12,6 +12,7 @@ var currentHighlightedRowId;
var highlightHandlers = [];
var moduleIndexToHandler = {};
var highlightedModules = [];
+var highlightedNet = null;
var checkboxes = [];
var bomCheckboxes = "";
var highlightpin1 = false;
@@ -162,6 +163,14 @@ function createCheckboxChangeHandler(checkbox, references) {
}
}
+function clearHighlightedModules() {
+ if (currentHighlightedRowId) {
+ document.getElementById(currentHighlightedRowId).classList.remove("highlighted");
+ currentHighlightedRowId = null;
+ highlightedModules = [];
+ }
+}
+
function createRowHighlightHandler(rowid, refs) {
return function() {
if (currentHighlightedRowId) {
diff --git a/InteractiveHtmlBom/web/render.js b/InteractiveHtmlBom/web/render.js
index 2dde21c0..bb1229e4 100644
--- a/InteractiveHtmlBom/web/render.js
+++ b/InteractiveHtmlBom/web/render.js
@@ -328,11 +328,12 @@ function drawBgLayer(layername, canvas, layer, scalefactor, edgeColor, polygonCo
}
}
-function drawTracks(canvas, layer, color) {
+function drawTracks(canvas, layer, color, highlight) {
ctx = canvas.getContext("2d");
ctx.strokeStyle = color;
ctx.lineCap = "round";
for(var track of pcbdata.tracks[layer]) {
+ if (highlight && highlightedNet != track.net) continue;
ctx.lineWidth = track.width;
ctx.beginPath();
ctx.moveTo(...track.start);
@@ -341,11 +342,12 @@ function drawTracks(canvas, layer, color) {
}
}
-function drawZones(canvas, layer, color) {
+function drawZones(canvas, layer, color, highlight) {
ctx = canvas.getContext("2d");
ctx.strokeStyle = color;
ctx.lineJoin = "round";
for(var zone of pcbdata.zones[layer]) {
+ if (highlight && highlightedNet != zone.net) continue;
ctx.lineWidth = zone.width;
drawPolygons(ctx, color, zone.polygons, ctx.stroke.bind(ctx));
drawPolygons(ctx, color, zone.polygons, ctx.fill.bind(ctx));
@@ -360,11 +362,41 @@ function clearCanvas(canvas) {
ctx.restore();
}
+function drawNets(canvas, layer, highlight) {
+ var style = getComputedStyle(topmostdiv);
+ if (renderTracks) {
+ var trackColor = style.getPropertyValue(highlight ? '--track-color-highlight' : '--track-color');
+ drawTracks(canvas, layer, trackColor, highlight);
+ }
+ if (renderZones) {
+ var zoneColor = style.getPropertyValue(highlight ? '--zone-color-highlight' : '--zone-color');
+ drawZones(canvas, layer, zoneColor, highlight);
+ }
+ if (highlight && renderPads) {
+ var padColor = style.getPropertyValue('--pad-color-highlight');
+ var ctx = canvas.getContext("2d");
+ for (var mod of pcbdata.modules) {
+ // draw pads
+ for (var pad of mod.pads) {
+ if (highlightedNet != pad.net) continue;
+ if (pad.layers.includes(layer)) {
+ drawPad(ctx, pad, padColor, false, true);
+ }
+ }
+ }
+ }
+}
+
function drawHighlightsOnLayer(canvasdict) {
clearCanvas(canvasdict.highlight);
- drawModules(canvasdict.highlight, canvasdict.layer,
- canvasdict.transform.s * canvasdict.transform.zoom, true);
-}
+ if (highlightedModules.length > 0) {
+ drawModules(canvasdict.highlight, canvasdict.layer,
+ canvasdict.transform.s * canvasdict.transform.zoom, true);
+ }
+ if (highlightedNet !== null) {
+ drawNets(canvasdict.highlight, canvasdict.layer, true);
+ }
+}
function drawHighlights() {
drawHighlightsOnLayer(allcanvas.front);
@@ -377,19 +409,11 @@ function drawBackground(canvasdict) {
clearCanvas(canvasdict.silk);
drawEdgeCuts(canvasdict.bg, canvasdict.transform.s);
- var style = getComputedStyle(topmostdiv);
- if (renderTracks) {
- var trackColor = style.getPropertyValue('--track-color');
- drawTracks(canvasdict.bg, canvasdict.layer, trackColor);
- }
- if (renderZones) {
- var zoneColor = style.getPropertyValue('--zone-color');
- drawZones(canvasdict.bg, canvasdict.layer, zoneColor);
- }
-
+ drawNets(canvasdict.bg, canvasdict.layer, false);
drawModules(canvasdict.bg, canvasdict.layer,
canvasdict.transform.s * canvasdict.transform.zoom, false);
+ var style = getComputedStyle(topmostdiv);
var edgeColor = style.getPropertyValue('--silkscreen-edge-color');
var polygonColor = style.getPropertyValue('--silkscreen-polygon-color');
var textColor = style.getPropertyValue('--silkscreen-text-color');
@@ -500,7 +524,52 @@ function resizeAll() {
resizeCanvas(allcanvas.back);
}
-function bboxScan(layer, x, y) {
+function pointWithinDistanceToSegment(x, y, x1, y1, x2, y2, d) {
+ var A = x - x1;
+ var B = y - y1;
+ var C = x2 - x1;
+ var D = y2 - y1;
+
+ var dot = A * C + B * D;
+ var len_sq = C * C + D * D;
+ var dx, dy;
+ if (len_sq == 0) {
+ // start and end of the segment coincide
+ dx = x - x1;
+ dy = y - y1;
+ } else {
+ var param = dot / len_sq;
+ var xx, yy;
+ if (param < 0) {
+ xx = x1;
+ yy = y1;
+ } else if (param > 1) {
+ xx = x2;
+ yy = y2;
+ } else {
+ xx = x1 + param * C;
+ yy = y1 + param * D;
+ }
+ dx = x - xx;
+ dy = y - yy;
+ }
+ return dx * dx + dy * dy <= d * d;
+}
+
+function netHitScan(layer, x, y) {
+ // Check track segments
+ if ("tracks" in pcbdata) {
+ for(var track of pcbdata.tracks[layer]) {
+ if (pointWithinDistanceToSegment(x, y, ...track.start, ...track.end, track.width / 2)) {
+ return track.net;
+ }
+ }
+ }
+ // Check pads
+ return null;
+}
+
+function bboxHitScan(layer, x, y) {
var result = [];
for (var i = 0; i < pcbdata.modules.length; i++) {
var module = pcbdata.modules[i];
@@ -553,9 +622,19 @@ function handleMouseClick(e, layerdict) {
}
y = (devicePixelRatio * y / t.zoom - t.y - t.pany) / t.s;
var v = rotateVector([x, y], -boardRotation);
- var modules = bboxScan(layerdict.layer, v[0], v[1]);
- if (modules.length > 0) {
- modulesClicked(modules);
+ if ("nets" in pcbdata) {
+ var net = netHitScan(layerdict.layer, ...v);
+ if (net !== highlightedNet) {
+ highlightedNet = net;
+ clearHighlightedModules();
+ drawHighlights();
+ }
+ }
+ if (highlightedNet === null) {
+ var modules = bboxHitScan(layerdict.layer, ...v);
+ if (modules.length > 0) {
+ modulesClicked(modules);
+ }
}
}