Skip to content

Commit 2daf701

Browse files
committed
Implement reverse lookup on click
Notes: only works when corresponding bom row is not filtered out. When there is ambiguity on click, subsequent clicks will cycle through possible interpretations. Fixes #9
1 parent 945f3d1 commit 2daf701

File tree

4 files changed

+79
-22
lines changed

4 files changed

+79
-22
lines changed

InteractiveHtmlBom/ibom.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,5 +379,5 @@ mark.highlight {
379379
}
380380

381381
#dbg {
382-
display: none;
382+
display: block;
383383
}

InteractiveHtmlBom/ibom.js

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ var highlightedRefs = [];
1212
var checkboxes = [];
1313
var bomCheckboxes = "";
1414
var storage;
15+
var lastClickedRef;
1516

1617
function initStorage(key) {
1718
try {
@@ -44,8 +45,8 @@ function writeStorage(key, value) {
4445
}
4546
}
4647

47-
function dbg(str) {
48-
dbgdiv.textContent = str;
48+
function dbg(html) {
49+
dbgdiv.innerHTML = html;
4950
}
5051

5152
function setDarkMode(value) {
@@ -272,7 +273,8 @@ function populateBomBody() {
272273
tr.onmousemove = handler;
273274
highlightHandlers.push({
274275
id: tr.id,
275-
handler: handler
276+
handler: handler,
277+
refs: references
276278
});
277279
if ((filter || reflookup) && first) {
278280
highlightedRefs = references;
@@ -282,6 +284,13 @@ function populateBomBody() {
282284
}
283285
}
284286

287+
function smoothScrollToRow(rowid) {
288+
document.getElementById(rowid).scrollIntoView({
289+
behavior: "smooth",
290+
block: "center",
291+
inline: "nearest"
292+
});}
293+
285294
function highlightPreviousRow() {
286295
if (!currentHighlightedRowId) {
287296
highlightHandlers[highlightHandlers.length - 1].handler();
@@ -298,11 +307,7 @@ function highlightPreviousRow() {
298307
}
299308
}
300309
}
301-
document.getElementById(currentHighlightedRowId).scrollIntoView({
302-
behavior: "smooth",
303-
block: "center",
304-
inline: "nearest"
305-
});
310+
smoothScrollToRow(currentHighlightedRowId);
306311
}
307312

308313
function highlightNextRow() {
@@ -321,11 +326,7 @@ function highlightNextRow() {
321326
}
322327
}
323328
}
324-
document.getElementById(currentHighlightedRowId).scrollIntoView({
325-
behavior: "smooth",
326-
block: "center",
327-
inline: "nearest"
328-
});
329+
smoothScrollToRow(currentHighlightedRowId);
329330
}
330331

331332
function populateBomTable() {
@@ -339,6 +340,19 @@ function populateBomTable() {
339340
populateBomBody();
340341
}
341342

343+
function modulesClicked(references) {
344+
var lastClickedIndex = references.indexOf(lastClickedRef);
345+
var ref = references[(lastClickedIndex + 1) % references.length];
346+
for (var handler of highlightHandlers) {
347+
if (handler.refs.indexOf(ref) >= 0) {
348+
lastClickedRef = ref;
349+
handler.handler();
350+
smoothScrollToRow(currentHighlightedRowId);
351+
break;
352+
}
353+
}
354+
}
355+
342356
function updateFilter(input) {
343357
filter = input.toLowerCase();
344358
populateBomTable();

InteractiveHtmlBom/render.js

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,8 @@ function clearCanvas(canvas) {
236236

237237
function drawHighlightsOnLayer(canvasdict) {
238238
clearCanvas(canvasdict.highlight);
239-
drawModules(canvasdict.highlight, canvasdict.layer, canvasdict.transform.s, highlightedRefs);
239+
drawModules(canvasdict.highlight, canvasdict.layer,
240+
canvasdict.transform.s, highlightedRefs);
240241
}
241242

242243
function drawHighlights() {
@@ -268,7 +269,7 @@ function prepareCanvas(canvas, flip, transform) {
268269
}
269270

270271
function prepareLayer(canvasdict) {
271-
flip = (canvasdict.layer == "B");
272+
var flip = (canvasdict.layer == "B");
272273
for (c of ["bg", "silk", "highlight"]) {
273274
prepareCanvas(canvasdict[c], flip, canvasdict.transform);
274275
}
@@ -290,7 +291,7 @@ function recalcLayerScale(canvasdict) {
290291
scalefactor = 1;
291292
}
292293
canvasdict.transform.s = scalefactor;
293-
flip = (canvasdict.layer == "B");
294+
var flip = (canvasdict.layer == "B");
294295
if (flip) {
295296
canvasdict.transform.x = -((bbox.maxx + bbox.minx) * scalefactor + width) * 0.5;
296297
} else {
@@ -311,9 +312,6 @@ function redrawCanvas(layerdict) {
311312
prepareLayer(layerdict);
312313
drawBackground(layerdict);
313314
drawHighlights(layerdict);
314-
t = layerdict.transform;
315-
dbgdiv.innerHTML = "x: " + t.x + "</br>y: " + t.y + "</br>s: " + t.s +
316-
"</br>panx: " + t.panx + "</br>pany: " + t.pany + "</br>zoom: " + t.zoom;
317315
}
318316

319317
function resizeCanvas(layerdict) {
@@ -326,6 +324,21 @@ function resizeAll() {
326324
resizeCanvas(allcanvas.back);
327325
}
328326

327+
function bboxScan(layer, x, y) {
328+
var result = [];
329+
for (var i in pcbdata.modules) {
330+
var module = pcbdata.modules[i];
331+
if (module.layer == layer) {
332+
var b = module.bbox;
333+
if (b.pos[0] <= x && b.pos[0] + b.size[0] >= x &&
334+
b.pos[1] <= y && b.pos[1] + b.size[1] >= y) {
335+
result.push(module.ref);
336+
}
337+
}
338+
}
339+
return result;
340+
}
341+
329342
function handleMouseDown(e, layerdict) {
330343
if (e.which != 1) {
331344
return;
@@ -334,12 +347,37 @@ function handleMouseDown(e, layerdict) {
334347
e.stopPropagation();
335348
layerdict.transform.mousestartx = e.offsetX;
336349
layerdict.transform.mousestarty = e.offsetY;
350+
layerdict.transform.mousedownx = e.offsetX;
351+
layerdict.transform.mousedowny = e.offsetY;
337352
layerdict.transform.mousedown = true;
338353
}
339354

355+
function handleMouseClick(e, layerdict) {
356+
var x = e.offsetX;
357+
var y = e.offsetY;
358+
var t = layerdict.transform;
359+
if (layerdict.layer == "B") {
360+
x = (2 * x / t.zoom - t.panx + t.x) / -t.s;
361+
} else {
362+
x = (2 * x / t.zoom - t.panx - t.x) / t.s;
363+
}
364+
y = (2 * y / t.zoom - t.y - t.pany) / t.s;
365+
var reflist = bboxScan(layerdict.layer, x, y);
366+
if (reflist.length > 0) {
367+
modulesClicked(reflist);
368+
}
369+
}
370+
340371
function handleMouseUp(e, layerdict) {
341372
e.preventDefault();
342373
e.stopPropagation();
374+
if (e.which == 1 &&
375+
layerdict.transform.mousedown &&
376+
layerdict.transform.mousedownx == e.offsetX &&
377+
layerdict.transform.mousedowny == e.offsetY) {
378+
// This is just a click
379+
handleMouseClick(e, layerdict);
380+
}
343381
layerdict.transform.mousedown = false;
344382
if (e.which == 3) {
345383
// Reset pan and zoom on right click.

README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,13 @@ path/to/kicad/bin/python.exe .../generate_interactive_bom.py .../board.kicad_pcb
8989

9090
### BOM mouse actions
9191

92-
You can pan the pcb drawings using left mouse button, zoom using mouse wheel
93-
and reset view by right click.
92+
You can pan the pcb drawings by dragging with left mouse button, zoom using
93+
mouse wheel and reset view by right click.
94+
95+
Left click on a component drawing will highlight corresponding component group,
96+
unless it is currently filtered out by filter or reference lookup fields.
97+
If there are multiple components under mouse cursor, subsequent clicks
98+
will cycle through possible interpretations.
9499

95100
### BOM keyboard shortcuts
96101

0 commit comments

Comments
 (0)