Skip to content

Commit bcc1063

Browse files
committed
Implement image export
Fixes #110
1 parent a143bd9 commit bcc1063

File tree

6 files changed

+215
-58
lines changed

6 files changed

+215
-58
lines changed

InteractiveHtmlBom/web/ibom.css

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
--track-color-highlight: #D04040;
1515
--zone-color: #def5f1;
1616
--zone-color-highlight: #d0404080;
17+
background-color: white;
1718
}
1819

1920
html, body {
@@ -131,6 +132,7 @@ textarea.clipboard-temp {
131132

132133
.button-container {
133134
font-size: 0;
135+
margin: 10px 10px 10px 0px;
134136
}
135137

136138
.dark .button-container {
@@ -418,10 +420,44 @@ mark.highlight {
418420
background-repeat: no-repeat;
419421
}
420422

421-
.dark .statsbtn {
423+
.iobtn {
424+
background-color: white;
425+
border: none;
426+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='36' height='36'%3E%3Cpath fill='none' stroke='%23000' stroke-width='2' d='M3 33v-7l6.8-7h16.5l6.7 7v7H3zM3.2 26H33M21 9l5-5.9 5 6h-2.5V15h-5V9H21zm-4.9 0l-5 6-5-6h2.5V3h5v6h2.5z'/%3E%3Cpath fill='none' stroke='%23000' d='M6.1 29.5H10'/%3E%3C/svg%3E");
427+
background-position: center;
428+
background-repeat: no-repeat;
429+
}
430+
431+
.dark .statsbtn, .dark .savebtn, .dark .menubtn, .dark .iobtn {
422432
filter: invert(1);
423433
}
424434

435+
.flexbox {
436+
display: flex;
437+
align-items: center;
438+
justify-content: space-between;
439+
width: 100%;
440+
}
441+
442+
.savebtn {
443+
background-color: #d6d6d6;
444+
width: auto;
445+
height: 30px;
446+
flex-grow: 1;
447+
margin: 5px;
448+
border-radius: 4px;
449+
}
450+
451+
.savebtn:active {
452+
background-color: #0a0;
453+
color: white;
454+
}
455+
456+
.dark .savebtn:active {
457+
/* This will be inverted */
458+
background-color: #b3b;
459+
}
460+
425461
.stats {
426462
border-collapse: collapse;
427463
font-size: 12pt;
@@ -457,13 +493,10 @@ mark.highlight {
457493
background-color: rgba(28, 251, 0, 0.6);
458494
}
459495

460-
.dark .menubtn {
461-
filter: invert(1);
462-
}
463-
464496
.menu {
465497
position: relative;
466498
display: inline-block;
499+
margin: 10px 10px 10px 0px;
467500
}
468501

469502
.menu-content {
@@ -485,12 +518,10 @@ mark.highlight {
485518
display: block;
486519
}
487520

488-
.menu:hover .menubtn {
521+
.menu:hover .menubtn, .menu:hover .iobtn, .menu:hover .statsbtn {
489522
background-color: #eee;
490523
}
491524

492-
.dark .menu:hover .menubtn {}
493-
494525
.menu-label {
495526
display: inline-block;
496527
padding: 8px;
@@ -519,6 +550,10 @@ mark.highlight {
519550
width: calc(100% - 10px);
520551
}
521552

553+
.menu-textbox.invalid, .dark .menu-textbox.invalid {
554+
color: red;
555+
}
556+
522557
.dark .menu-textbox {
523558
background-color: #222;
524559
color: #eee;

InteractiveHtmlBom/web/ibom.html

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
<div id="topmostdiv" style="width: 100%; height: 100%">
4949
<div id="top">
5050
<div style="float: right; height: 100%;">
51-
<div class="hideonprint menu" style="float: right; margin: 10px; top: 8px;">
51+
<div class="hideonprint menu" style="float: right; top: 8px;">
5252
<button class="menubtn"></button>
5353
<div class="menu-content">
5454
<label class="menu-label menu-label-top">
@@ -116,7 +116,7 @@
116116
</div>
117117
</div>
118118
<div class="button-container hideonprint"
119-
style="float: right; margin: 10px; position: relative; top: 8px">
119+
style="float: right; position: relative; top: 8px">
120120
<button id="fl-btn" class="left-most-button" onclick="changeCanvasLayout('F')"
121121
title="Front only">F
122122
</button>
@@ -128,15 +128,15 @@
128128
</button>
129129
</div>
130130
<div class="button-container hideonprint"
131-
style="float: right; margin: 10px; position: relative; top: 8px">
131+
style="float: right; position: relative; top: 8px">
132132
<button id="bom-btn" class="left-most-button" onclick="changeBomLayout('bom-only')"
133133
title="BOM only"></button>
134134
<button id="lr-btn" class="middle-button" onclick="changeBomLayout('left-right')"
135135
title="BOM left, drawings right"></button>
136136
<button id="tb-btn" class="right-most-button" onclick="changeBomLayout('top-bottom')"
137137
title="BOM top, drawings bot"></button>
138138
</div>
139-
<div class="hideonprint menu" style="float: right; margin: 10px; top: 8px;">
139+
<div class="hideonprint menu" style="float: right; top: 8px;">
140140
<button class="statsbtn"></button>
141141
<div class="menu-content">
142142
<table class="stats">
@@ -181,6 +181,33 @@
181181
</table>
182182
</div>
183183
</div>
184+
<div class="hideonprint menu" style="float: right; top: 8px;">
185+
<button class="iobtn"></button>
186+
<div class="menu-content">
187+
<label class="menu-label menu-label-top">
188+
<div style="margin-left: 5px;">Save board image</div>
189+
<div class="flexbox">
190+
<input id="render-save-width" class="menu-textbox" type="text" value="1000" placeholder="Width"
191+
style="flex-grow: 1; width: 50px;" oninput="validateSaveImgDimension(this)">
192+
<span>X</span>
193+
<input id="render-save-height" class="menu-textbox" type="text" value="1000" placeholder="Height"
194+
style="flex-grow: 1; width: 50px;" oninput="validateSaveImgDimension(this)">
195+
</div>
196+
<input id="render-save-transparent" type="checkbox">
197+
Transparent background
198+
<div class="flexbox">
199+
<button class="savebtn" onclick="saveImage('F')">Front</button>
200+
<button class="savebtn" onclick="saveImage('B')">Back</button>
201+
</div>
202+
</label>
203+
<label class="menu-label">
204+
<span style="margin-left: 5px;">Config and checkbox state</span>
205+
<div class="flexbox">
206+
<button class="savebtn">Export</button>
207+
<button class="savebtn">Import</button>
208+
</div>
209+
</div>
210+
</div>
184211
</div>
185212
<div id="fileinfodiv" style="overflow: auto;">
186213
<table class="fileinfo">
@@ -195,7 +222,7 @@
195222
</tr>
196223
<tr>
197224
<td id="company">
198-
Kicad version
225+
Company
199226
</td>
200227
<td id="filedate">
201228
Date
@@ -208,11 +235,11 @@
208235
<div id="bot" class="split" style="height: calc(100% - 80px)">
209236
<div id="bomdiv" class="split split-horizontal">
210237
<div style="width: 100%">
211-
<input id="reflookup" class="searchbox reflookup hideonprint" type="text" placeholder="Ref lookup"
238+
<input id="reflookup" class="textbox searchbox reflookup hideonprint" type="text" placeholder="Ref lookup"
212239
oninput="updateRefLookup(this.value)">
213-
<input id="filter" class="searchbox filter hideonprint" type="text" placeholder="Filter"
240+
<input id="filter" class="textbox searchbox filter hideonprint" type="text" placeholder="Filter"
214241
oninput="updateFilter(this.value)">
215-
<div class="button-container hideonprint" style="float: left">
242+
<div class="button-container hideonprint" style="float: left; margin: 0;">
216243
<button id="copy" title="Copy bom table to clipboard"
217244
onclick="copyToClipboard()"></button>
218245
</div>

InteractiveHtmlBom/web/ibom.js

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -75,19 +75,16 @@ function setDarkMode(value) {
7575
redrawIfInitDone();
7676
}
7777

78-
function layerVisible(visible, frontCavnas, backCanvas, storageString) {
79-
var display = (visible) ? "" : "none";
80-
frontCavnas.style.display = display;
81-
backCanvas.style.display = display;
82-
writeStorage(storageString, visible);
83-
}
84-
85-
function fabricationVisible(visible) {
86-
layerVisible(visible, allcanvas.front.fab, allcanvas.back.fab, "fabricationVisible");
78+
function fabricationVisible(value) {
79+
renderFabrication = value;
80+
writeStorage("fabricationVisible", value);
81+
redrawIfInitDone();
8782
}
8883

89-
function silkscreenVisible(visible) {
90-
layerVisible(visible, allcanvas.front.silk, allcanvas.back.silk, "silkscreenVisible");
84+
function silkscreenVisible(value) {
85+
renderSilkscreen = value;
86+
writeStorage("silkscreenVisible", value);
87+
redrawIfInitDone();
9188
}
9289

9390
function setHighlightPin1(value) {

InteractiveHtmlBom/web/render.js

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ var boardRotation = 0;
55
var renderPads = true;
66
var renderReferences = true;
77
var renderValues = true;
8+
var renderSilkscreen = true;
9+
var renderFabrication = true;
810
var renderDnpOutline = false;
911
var renderTracks = true;
1012
var renderZones = true;
@@ -383,11 +385,16 @@ function drawZones(canvas, layer, color, highlight) {
383385
}
384386
}
385387

386-
function clearCanvas(canvas) {
388+
function clearCanvas(canvas, color = null) {
387389
var ctx = canvas.getContext("2d");
388390
ctx.save();
389391
ctx.setTransform(1, 0, 0, 1, 0, 0);
390-
ctx.clearRect(0, 0, canvas.width, canvas.height);
392+
if (color) {
393+
ctx.fillStyle = color;
394+
ctx.fillRect(0, 0, canvas.width, canvas.height);
395+
} else {
396+
ctx.clearRect(0, 0, canvas.width, canvas.height);
397+
}
391398
ctx.restore();
392399
}
393400

@@ -416,8 +423,10 @@ function drawNets(canvas, layer, highlight) {
416423
}
417424
}
418425

419-
function drawHighlightsOnLayer(canvasdict) {
420-
clearCanvas(canvasdict.highlight);
426+
function drawHighlightsOnLayer(canvasdict, clear = true) {
427+
if (clear) {
428+
clearCanvas(canvasdict.highlight);
429+
}
421430
if (highlightedModules.length > 0) {
422431
drawModules(canvasdict.highlight, canvasdict.layer,
423432
canvasdict.transform.s * canvasdict.transform.zoom, true);
@@ -432,10 +441,12 @@ function drawHighlights() {
432441
drawHighlightsOnLayer(allcanvas.back);
433442
}
434443

435-
function drawBackground(canvasdict) {
436-
clearCanvas(canvasdict.bg);
437-
clearCanvas(canvasdict.fab);
438-
clearCanvas(canvasdict.silk);
444+
function drawBackground(canvasdict, clear = true) {
445+
if (clear) {
446+
clearCanvas(canvasdict.bg);
447+
clearCanvas(canvasdict.fab);
448+
clearCanvas(canvasdict.silk);
449+
}
439450

440451
drawNets(canvasdict.bg, canvasdict.layer, false);
441452
drawModules(canvasdict.bg, canvasdict.layer,
@@ -447,18 +458,21 @@ function drawBackground(canvasdict) {
447458
var edgeColor = style.getPropertyValue('--silkscreen-edge-color');
448459
var polygonColor = style.getPropertyValue('--silkscreen-polygon-color');
449460
var textColor = style.getPropertyValue('--silkscreen-text-color');
450-
drawBgLayer(
451-
"silkscreen", canvasdict.silk, canvasdict.layer,
452-
canvasdict.transform.s * canvasdict.transform.zoom,
453-
edgeColor, polygonColor, textColor);
454-
461+
if (renderSilkscreen) {
462+
drawBgLayer(
463+
"silkscreen", canvasdict.silk, canvasdict.layer,
464+
canvasdict.transform.s * canvasdict.transform.zoom,
465+
edgeColor, polygonColor, textColor);
466+
}
455467
edgeColor = style.getPropertyValue('--fabrication-edge-color');
456468
polygonColor = style.getPropertyValue('--fabrication-polygon-color');
457469
textColor = style.getPropertyValue('--fabrication-text-color');
458-
drawBgLayer(
459-
"fabrication", canvasdict.fab, canvasdict.layer,
460-
canvasdict.transform.s * canvasdict.transform.zoom,
461-
edgeColor, polygonColor, textColor);
470+
if (renderFabrication) {
471+
drawBgLayer(
472+
"fabrication", canvasdict.fab, canvasdict.layer,
473+
canvasdict.transform.s * canvasdict.transform.zoom,
474+
edgeColor, polygonColor, textColor);
475+
}
462476
}
463477

464478
function prepareCanvas(canvas, flip, transform) {
@@ -506,13 +520,7 @@ function applyRotation(bbox) {
506520
}
507521
}
508522

509-
function recalcLayerScale(canvasdict) {
510-
var canvasdivid = {
511-
"F": "frontcanvas",
512-
"B": "backcanvas"
513-
} [canvasdict.layer];
514-
var width = document.getElementById(canvasdivid).clientWidth * devicePixelRatio;
515-
var height = document.getElementById(canvasdivid).clientHeight * devicePixelRatio;
523+
function recalcLayerScale(layerdict, width, height) {
516524
var bbox = applyRotation(pcbdata.edges_bbox);
517525
var scalefactor = 0.98 * Math.min(
518526
width / (bbox.maxx - bbox.minx),
@@ -521,16 +529,16 @@ function recalcLayerScale(canvasdict) {
521529
if (scalefactor < 0.1) {
522530
scalefactor = 1;
523531
}
524-
canvasdict.transform.s = scalefactor;
525-
var flip = (canvasdict.layer == "B");
532+
layerdict.transform.s = scalefactor;
533+
var flip = (layerdict.layer == "B");
526534
if (flip) {
527-
canvasdict.transform.x = -((bbox.maxx + bbox.minx) * scalefactor + width) * 0.5;
535+
layerdict.transform.x = -((bbox.maxx + bbox.minx) * scalefactor + width) * 0.5;
528536
} else {
529-
canvasdict.transform.x = -((bbox.maxx + bbox.minx) * scalefactor - width) * 0.5;
537+
layerdict.transform.x = -((bbox.maxx + bbox.minx) * scalefactor - width) * 0.5;
530538
}
531-
canvasdict.transform.y = -((bbox.maxy + bbox.miny) * scalefactor - height) * 0.5;
539+
layerdict.transform.y = -((bbox.maxy + bbox.miny) * scalefactor - height) * 0.5;
532540
for (var c of ["bg", "fab", "silk", "highlight"]) {
533-
canvas = canvasdict[c];
541+
canvas = layerdict[c];
534542
canvas.width = width;
535543
canvas.height = height;
536544
canvas.style.width = (width / devicePixelRatio) + "px";
@@ -545,7 +553,13 @@ function redrawCanvas(layerdict) {
545553
}
546554

547555
function resizeCanvas(layerdict) {
548-
recalcLayerScale(layerdict);
556+
var canvasdivid = {
557+
"F": "frontcanvas",
558+
"B": "backcanvas"
559+
} [layerdict.layer];
560+
var width = document.getElementById(canvasdivid).clientWidth * devicePixelRatio;
561+
var height = document.getElementById(canvasdivid).clientHeight * devicePixelRatio;
562+
recalcLayerScale(layerdict, width, height);
549563
redrawCanvas(layerdict);
550564
}
551565

0 commit comments

Comments
 (0)