4710 lines
295 KiB
HTML
4710 lines
295 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Interactive BOM for KiCAD</title>
|
|
<style type="text/css">
|
|
:root {
|
|
--pcb-edge-color: black;
|
|
--pad-color: #878787;
|
|
--pad-hole-color: #CCCCCC;
|
|
--pad-color-highlight: #D04040;
|
|
--pad-color-highlight-both: #D0D040;
|
|
--pad-color-highlight-marked: #44a344;
|
|
--pin1-outline-color: #ffb629;
|
|
--pin1-outline-color-highlight: #ffb629;
|
|
--pin1-outline-color-highlight-both: #fcbb39;
|
|
--pin1-outline-color-highlight-marked: #fdbe41;
|
|
--silkscreen-edge-color: #aa4;
|
|
--silkscreen-polygon-color: #4aa;
|
|
--silkscreen-text-color: #4aa;
|
|
--fabrication-edge-color: #907651;
|
|
--fabrication-polygon-color: #907651;
|
|
--fabrication-text-color: #a27c24;
|
|
--track-color: #def5f1;
|
|
--track-color-highlight: #D04040;
|
|
--zone-color: #def5f1;
|
|
--zone-color-highlight: #d0404080;
|
|
}
|
|
|
|
html,
|
|
body {
|
|
margin: 0px;
|
|
height: 100%;
|
|
font-family: Verdana, sans-serif;
|
|
}
|
|
|
|
.dark.topmostdiv {
|
|
--pcb-edge-color: #eee;
|
|
--pad-color: #808080;
|
|
--pin1-outline-color: #ffa800;
|
|
--pin1-outline-color-highlight: #ccff00;
|
|
--track-color: #42524f;
|
|
--zone-color: #42524f;
|
|
background-color: #252c30;
|
|
color: #eee;
|
|
}
|
|
|
|
button {
|
|
background-color: #eee;
|
|
border: 1px solid #888;
|
|
color: black;
|
|
height: 44px;
|
|
width: 44px;
|
|
text-align: center;
|
|
text-decoration: none;
|
|
display: inline-block;
|
|
font-size: 14px;
|
|
font-weight: bolder;
|
|
}
|
|
|
|
.dark button {
|
|
/* This will be inverted */
|
|
background-color: #c3b7b5;
|
|
}
|
|
|
|
button.depressed {
|
|
background-color: #0a0;
|
|
color: white;
|
|
}
|
|
|
|
.dark button.depressed {
|
|
/* This will be inverted */
|
|
background-color: #b3b;
|
|
}
|
|
|
|
button:focus {
|
|
outline: 0;
|
|
}
|
|
|
|
button#tb-btn {
|
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8.47 8.47'%3E%3Crect transform='translate(0 -288.53)' ry='1.17' y='288.8' x='.27' height='7.94' width='7.94' fill='%23f9f9f9'/%3E%3Cg transform='translate(0 -288.53)'%3E%3Crect width='7.94' height='7.94' x='.27' y='288.8' ry='1.17' fill='none' stroke='%23000' stroke-width='.4' stroke-linejoin='round'/%3E%3Cpath d='M1.32 290.12h5.82M1.32 291.45h5.82' fill='none' stroke='%23000' stroke-width='.4'/%3E%3Cpath d='M4.37 292.5v4.23M.26 292.63H8.2' fill='none' stroke='%23000' stroke-width='.3'/%3E%3Ctext font-weight='700' font-size='3.17' font-family='sans-serif'%3E%3Ctspan x='1.35' y='295.73'%3EF%3C/tspan%3E%3Ctspan x='5.03' y='295.68'%3EB%3C/tspan%3E%3C/text%3E%3C/g%3E%3C/svg%3E%0A");
|
|
}
|
|
|
|
button#lr-btn {
|
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8.47 8.47'%3E%3Crect transform='translate(0 -288.53)' ry='1.17' y='288.8' x='.27' height='7.94' width='7.94' fill='%23f9f9f9'/%3E%3Cg transform='translate(0 -288.53)'%3E%3Crect width='7.94' height='7.94' x='.27' y='288.8' ry='1.17' fill='none' stroke='%23000' stroke-width='.4' stroke-linejoin='round'/%3E%3Cpath d='M1.06 290.12H3.7m-2.64 1.33H3.7m-2.64 1.32H3.7m-2.64 1.3H3.7m-2.64 1.33H3.7' fill='none' stroke='%23000' stroke-width='.4'/%3E%3Cpath d='M4.37 288.8v7.94m0-4.11h3.96' fill='none' stroke='%23000' stroke-width='.3'/%3E%3Ctext font-weight='700' font-size='3.17' font-family='sans-serif'%3E%3Ctspan x='5.11' y='291.96'%3EF%3C/tspan%3E%3Ctspan x='5.03' y='295.68'%3EB%3C/tspan%3E%3C/text%3E%3C/g%3E%3C/svg%3E%0A");
|
|
}
|
|
|
|
button#bom-btn {
|
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8.47 8.47'%3E%3Crect transform='translate(0 -288.53)' ry='1.17' y='288.8' x='.27' height='7.94' width='7.94' fill='%23f9f9f9'/%3E%3Cg transform='translate(0 -288.53)' fill='none' stroke='%23000' stroke-width='.4'%3E%3Crect width='7.94' height='7.94' x='.27' y='288.8' ry='1.17' stroke-linejoin='round'/%3E%3Cpath d='M1.59 290.12h5.29M1.59 291.45h5.33M1.59 292.75h5.33M1.59 294.09h5.33M1.59 295.41h5.33'/%3E%3C/g%3E%3C/svg%3E");
|
|
}
|
|
|
|
button#bom-grouped-btn {
|
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32'%3E%3Cg stroke='%23000' stroke-linejoin='round' class='layer'%3E%3Crect width='29' height='29' x='1.5' y='1.5' stroke-width='2' fill='%23fff' rx='5' ry='5'/%3E%3Cpath stroke-linecap='square' stroke-width='2' d='M6 10h4m4 0h5m4 0h3M6.1 22h3m3.9 0h5m4 0h4m-16-8h4m4 0h4'/%3E%3Cpath stroke-linecap='null' d='M5 17.5h22M5 26.6h22M5 5.5h22'/%3E%3C/g%3E%3C/svg%3E");
|
|
}
|
|
|
|
button#bom-ungrouped-btn {
|
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32'%3E%3Cg stroke='%23000' stroke-linejoin='round' class='layer'%3E%3Crect width='29' height='29' x='1.5' y='1.5' stroke-width='2' fill='%23fff' rx='5' ry='5'/%3E%3Cpath stroke-linecap='square' stroke-width='2' d='M6 10h4m-4 8h3m-3 8h4'/%3E%3Cpath stroke-linecap='null' d='M5 13.5h22m-22 8h22M5 5.5h22'/%3E%3C/g%3E%3C/svg%3E");
|
|
}
|
|
|
|
button#bom-netlist-btn {
|
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32'%3E%3Cg fill='none' stroke='%23000' class='layer'%3E%3Crect width='29' height='29' x='1.5' y='1.5' stroke-width='2' fill='%23fff' rx='5' ry='5'/%3E%3Cpath stroke-width='2' d='M6 26l6-6v-8m13.8-6.3l-6 6v8'/%3E%3Ccircle cx='11.8' cy='9.5' r='2.8' stroke-width='2'/%3E%3Ccircle cx='19.8' cy='22.8' r='2.8' stroke-width='2'/%3E%3C/g%3E%3C/svg%3E");
|
|
}
|
|
|
|
button#copy {
|
|
background-image: url("data:image/svg+xml,%3Csvg height='48' viewBox='0 0 48 48' width='48' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0h48v48h-48z' fill='none'/%3E%3Cpath d='M32 2h-24c-2.21 0-4 1.79-4 4v28h4v-28h24v-4zm6 8h-22c-2.21 0-4 1.79-4 4v28c0 2.21 1.79 4 4 4h22c2.21 0 4-1.79 4-4v-28c0-2.21-1.79-4-4-4zm0 32h-22v-28h22v28z'/%3E%3C/svg%3E");
|
|
background-position: 6px 6px;
|
|
background-repeat: no-repeat;
|
|
background-size: 26px 26px;
|
|
border-radius: 6px;
|
|
height: 40px;
|
|
width: 40px;
|
|
margin: 10px 5px;
|
|
}
|
|
|
|
button#copy:active {
|
|
box-shadow: inset 0px 0px 5px #6c6c6c;
|
|
}
|
|
|
|
textarea.clipboard-temp {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 2em;
|
|
height: 2em;
|
|
padding: 0;
|
|
border: None;
|
|
outline: None;
|
|
box-shadow: None;
|
|
background: transparent;
|
|
}
|
|
|
|
.left-most-button {
|
|
border-right: 0;
|
|
border-top-left-radius: 6px;
|
|
border-bottom-left-radius: 6px;
|
|
}
|
|
|
|
.middle-button {
|
|
border-right: 0;
|
|
}
|
|
|
|
.right-most-button {
|
|
border-top-right-radius: 6px;
|
|
border-bottom-right-radius: 6px;
|
|
}
|
|
|
|
.button-container {
|
|
font-size: 0;
|
|
margin: 0.4rem 0.4rem 0.4rem 0;
|
|
}
|
|
|
|
.dark .button-container {
|
|
filter: invert(1);
|
|
}
|
|
|
|
.button-container button {
|
|
background-size: 32px 32px;
|
|
background-position: 5px 5px;
|
|
background-repeat: no-repeat;
|
|
}
|
|
|
|
@media print {
|
|
.hideonprint {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
canvas {
|
|
cursor: crosshair;
|
|
}
|
|
|
|
canvas:active {
|
|
cursor: grabbing;
|
|
}
|
|
|
|
.fileinfo {
|
|
width: 100%;
|
|
max-width: 1000px;
|
|
border: none;
|
|
padding: 3px;
|
|
}
|
|
|
|
.fileinfo .title {
|
|
font-size: 20pt;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.fileinfo td {
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
max-width: 1px;
|
|
width: 50%;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.bom {
|
|
border-collapse: collapse;
|
|
font-family: Consolas, "DejaVu Sans Mono", Monaco, monospace;
|
|
font-size: 10pt;
|
|
table-layout: fixed;
|
|
width: 100%;
|
|
margin-top: 1px;
|
|
position: relative;
|
|
}
|
|
|
|
.bom th,
|
|
.bom td {
|
|
border: 1px solid black;
|
|
padding: 5px;
|
|
word-wrap: break-word;
|
|
text-align: center;
|
|
position: relative;
|
|
}
|
|
|
|
.dark .bom th,
|
|
.dark .bom td {
|
|
border: 1px solid #777;
|
|
}
|
|
|
|
.bom th {
|
|
background-color: #CCCCCC;
|
|
background-clip: padding-box;
|
|
}
|
|
|
|
.dark .bom th {
|
|
background-color: #3b4749;
|
|
}
|
|
|
|
.bom tr.highlighted:nth-child(n) {
|
|
background-color: #cfc;
|
|
}
|
|
|
|
.dark .bom tr.highlighted:nth-child(n) {
|
|
background-color: #226022;
|
|
}
|
|
|
|
.bom tr:nth-child(even) {
|
|
background-color: #f2f2f2;
|
|
}
|
|
|
|
.dark .bom tr:nth-child(even) {
|
|
background-color: #313b40;
|
|
}
|
|
|
|
.bom tr.checked {
|
|
color: #1cb53d;
|
|
}
|
|
|
|
.dark .bom tr.checked {
|
|
color: #2cce54;
|
|
}
|
|
|
|
.bom tr {
|
|
transition: background-color 0.2s;
|
|
}
|
|
|
|
.bom .numCol {
|
|
width: 30px;
|
|
}
|
|
|
|
.bom .value {
|
|
width: 15%;
|
|
}
|
|
|
|
.bom .quantity {
|
|
width: 65px;
|
|
}
|
|
|
|
.bom th .sortmark {
|
|
position: absolute;
|
|
right: 1px;
|
|
top: 1px;
|
|
margin-top: -5px;
|
|
border-width: 5px;
|
|
border-style: solid;
|
|
border-color: transparent transparent #221 transparent;
|
|
transform-origin: 50% 85%;
|
|
transition: opacity 0.2s, transform 0.4s;
|
|
}
|
|
|
|
.dark .bom th .sortmark {
|
|
filter: invert(1);
|
|
}
|
|
|
|
.bom th .sortmark.none {
|
|
opacity: 0;
|
|
}
|
|
|
|
.bom th .sortmark.desc {
|
|
transform: rotate(180deg);
|
|
}
|
|
|
|
.bom th:hover .sortmark.none {
|
|
opacity: 0.5;
|
|
}
|
|
|
|
.bom .bom-checkbox {
|
|
width: 30px;
|
|
position: relative;
|
|
user-select: none;
|
|
-moz-user-select: none;
|
|
}
|
|
|
|
.bom .bom-checkbox:before {
|
|
content: "";
|
|
position: absolute;
|
|
border-width: 15px;
|
|
border-style: solid;
|
|
border-color: #51829f transparent transparent transparent;
|
|
visibility: hidden;
|
|
top: -15px;
|
|
}
|
|
|
|
.bom .bom-checkbox:after {
|
|
content: "Double click to set/unset all";
|
|
position: absolute;
|
|
color: white;
|
|
top: -35px;
|
|
left: -26px;
|
|
background: #51829f;
|
|
padding: 5px 15px;
|
|
border-radius: 8px;
|
|
white-space: nowrap;
|
|
visibility: hidden;
|
|
}
|
|
|
|
.bom .bom-checkbox:hover:before,
|
|
.bom .bom-checkbox:hover:after {
|
|
visibility: visible;
|
|
transition: visibility 0.2s linear 1s;
|
|
}
|
|
|
|
.split {
|
|
-webkit-box-sizing: border-box;
|
|
-moz-box-sizing: border-box;
|
|
box-sizing: border-box;
|
|
overflow-y: auto;
|
|
overflow-x: hidden;
|
|
background-color: inherit;
|
|
}
|
|
|
|
.split.split-horizontal,
|
|
.gutter.gutter-horizontal {
|
|
height: 100%;
|
|
float: left;
|
|
}
|
|
|
|
.gutter {
|
|
background-color: #ddd;
|
|
background-repeat: no-repeat;
|
|
background-position: 50%;
|
|
transition: background-color 0.3s;
|
|
}
|
|
|
|
.dark .gutter {
|
|
background-color: #777;
|
|
}
|
|
|
|
.gutter.gutter-horizontal {
|
|
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==');
|
|
cursor: ew-resize;
|
|
width: 5px;
|
|
}
|
|
|
|
.gutter.gutter-vertical {
|
|
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAFAQMAAABo7865AAAABlBMVEVHcEzMzMzyAv2sAAAAAXRSTlMAQObYZgAAABBJREFUeF5jOAMEEAIEEFwAn3kMwcB6I2AAAAAASUVORK5CYII=');
|
|
cursor: ns-resize;
|
|
height: 5px;
|
|
}
|
|
|
|
.searchbox {
|
|
float: left;
|
|
height: 40px;
|
|
margin: 10px 5px;
|
|
padding: 12px 32px;
|
|
font-family: Consolas, "DejaVu Sans Mono", Monaco, monospace;
|
|
font-size: 18px;
|
|
box-sizing: border-box;
|
|
border: 1px solid #888;
|
|
border-radius: 6px;
|
|
outline: none;
|
|
background-color: #eee;
|
|
transition: background-color 0.2s, border 0.2s;
|
|
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABNklEQVQ4T8XSMUvDQBQH8P/LElFa/AIZHcTBQSz0I/gFstTBRR2KUC4ldDxw7h0Bl3RRUATxi4iiODgoiLNrbQYp5J6cpJJqomkX33Z37/14d/dIa33MzDuYI4johOI4XhyNRteO46zNYjDzAxE1yBZprVeZ+QbAUhXEGJMA2Ox2u4+fQIa0mPmsCgCgJYQ4t7lfgF0opQYAdv9ABkKI/UnOFCClXKjX61cA1osQY8x9kiRNKeV7IWA3oyhaSdP0FkAtjxhj3hzH2RBCPOf3pzqYHCilfAAX+URm9oMguPzeWSGQvUcMYC8rOBJCHBRdqxTo9/vbRHRqi8bj8XKv1xvODbiuW2u32/bvf0SlDv4XYOY7z/Mavu+nM1+BmQ+NMc0wDF/LprP0DbTWW0T00ul0nn4b7Q87+X4Qmfiq2wAAAABJRU5ErkJggg==');
|
|
background-position: 10px 10px;
|
|
background-repeat: no-repeat;
|
|
}
|
|
|
|
.dark .searchbox {
|
|
background-color: #111;
|
|
color: #eee;
|
|
}
|
|
|
|
.searchbox::placeholder {
|
|
color: #ccc;
|
|
}
|
|
|
|
.dark .searchbox::placeholder {
|
|
color: #666;
|
|
}
|
|
|
|
.filter {
|
|
width: calc(60% - 64px);
|
|
}
|
|
|
|
.reflookup {
|
|
width: calc(40% - 10px);
|
|
}
|
|
|
|
input[type=text]:focus {
|
|
background-color: white;
|
|
border: 1px solid #333;
|
|
}
|
|
|
|
.dark input[type=text]:focus {
|
|
background-color: #333;
|
|
border: 1px solid #ccc;
|
|
}
|
|
|
|
mark.highlight {
|
|
background-color: #5050ff;
|
|
color: #fff;
|
|
padding: 2px;
|
|
border-radius: 6px;
|
|
}
|
|
|
|
.dark mark.highlight {
|
|
background-color: #76a6da;
|
|
color: #111;
|
|
}
|
|
|
|
.menubtn {
|
|
background-color: white;
|
|
border: none;
|
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='36' height='36' viewBox='0 0 20 20'%3E%3Cpath fill='none' d='M0 0h20v20H0V0z'/%3E%3Cpath d='M15.95 10.78c.03-.25.05-.51.05-.78s-.02-.53-.06-.78l1.69-1.32c.15-.12.19-.34.1-.51l-1.6-2.77c-.1-.18-.31-.24-.49-.18l-1.99.8c-.42-.32-.86-.58-1.35-.78L12 2.34c-.03-.2-.2-.34-.4-.34H8.4c-.2 0-.36.14-.39.34l-.3 2.12c-.49.2-.94.47-1.35.78l-1.99-.8c-.18-.07-.39 0-.49.18l-1.6 2.77c-.1.18-.06.39.1.51l1.69 1.32c-.04.25-.07.52-.07.78s.02.53.06.78L2.37 12.1c-.15.12-.19.34-.1.51l1.6 2.77c.1.18.31.24.49.18l1.99-.8c.42.32.86.58 1.35.78l.3 2.12c.04.2.2.34.4.34h3.2c.2 0 .37-.14.39-.34l.3-2.12c.49-.2.94-.47 1.35-.78l1.99.8c.18.07.39 0 .49-.18l1.6-2.77c.1-.18.06-.39-.1-.51l-1.67-1.32zM10 13c-1.65 0-3-1.35-3-3s1.35-3 3-3 3 1.35 3 3-1.35 3-3 3z'/%3E%3C/svg%3E%0A");
|
|
background-position: center;
|
|
background-repeat: no-repeat;
|
|
}
|
|
|
|
.statsbtn {
|
|
background-color: white;
|
|
border: none;
|
|
background-image: url("data:image/svg+xml,%3Csvg width='36' height='36' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4 6h28v24H4V6zm0 8h28v8H4m9-16v24h10V5.8' fill='none' stroke='%23000' stroke-width='2'/%3E%3C/svg%3E");
|
|
background-position: center;
|
|
background-repeat: no-repeat;
|
|
}
|
|
|
|
.iobtn {
|
|
background-color: white;
|
|
border: none;
|
|
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");
|
|
background-position: center;
|
|
background-repeat: no-repeat;
|
|
}
|
|
|
|
.visbtn {
|
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath fill='none' stroke='%23333' d='M2.5 4.5h5v15h-5zM9.5 4.5h5v15h-5zM16.5 4.5h5v15h-5z'/%3E%3C/svg%3E");
|
|
background-position: center;
|
|
background-repeat: no-repeat;
|
|
padding: 15px;
|
|
}
|
|
|
|
#vismenu-content {
|
|
left: 0px;
|
|
font-family: Verdana, sans-serif;
|
|
}
|
|
|
|
.dark .statsbtn,
|
|
.dark .savebtn,
|
|
.dark .menubtn,
|
|
.dark .iobtn,
|
|
.dark .visbtn {
|
|
filter: invert(1);
|
|
}
|
|
|
|
.flexbox {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
width: 100%;
|
|
}
|
|
|
|
.savebtn {
|
|
background-color: #d6d6d6;
|
|
width: auto;
|
|
height: 30px;
|
|
flex-grow: 1;
|
|
margin: 5px;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.savebtn:active {
|
|
background-color: #0a0;
|
|
color: white;
|
|
}
|
|
|
|
.dark .savebtn:active {
|
|
/* This will be inverted */
|
|
background-color: #b3b;
|
|
}
|
|
|
|
.stats {
|
|
border-collapse: collapse;
|
|
font-size: 12pt;
|
|
table-layout: fixed;
|
|
width: 100%;
|
|
min-width: 450px;
|
|
}
|
|
|
|
.dark .stats td {
|
|
border: 1px solid #bbb;
|
|
}
|
|
|
|
.stats td {
|
|
border: 1px solid black;
|
|
padding: 5px;
|
|
word-wrap: break-word;
|
|
text-align: center;
|
|
position: relative;
|
|
}
|
|
|
|
#checkbox-stats div {
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0;
|
|
height: 100%;
|
|
width: 100%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
#checkbox-stats .bar {
|
|
background-color: rgba(28, 251, 0, 0.6);
|
|
}
|
|
|
|
.menu {
|
|
position: relative;
|
|
display: inline-block;
|
|
margin: 0.4rem 0.4rem 0.4rem 0;
|
|
}
|
|
|
|
.menu-content {
|
|
font-size: 12pt !important;
|
|
text-align: left !important;
|
|
font-weight: normal !important;
|
|
display: none;
|
|
position: absolute;
|
|
background-color: white;
|
|
right: 0;
|
|
min-width: 300px;
|
|
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
|
|
z-index: 100;
|
|
padding: 8px;
|
|
}
|
|
|
|
.dark .menu-content {
|
|
background-color: #111;
|
|
}
|
|
|
|
.menu:hover .menu-content {
|
|
display: block;
|
|
}
|
|
|
|
.menu:hover .menubtn,
|
|
.menu:hover .iobtn,
|
|
.menu:hover .statsbtn {
|
|
background-color: #eee;
|
|
}
|
|
|
|
.menu-label {
|
|
display: inline-block;
|
|
padding: 8px;
|
|
border: 1px solid #ccc;
|
|
border-top: 0;
|
|
width: calc(100% - 18px);
|
|
}
|
|
|
|
.menu-label-top {
|
|
border-top: 1px solid #ccc;
|
|
}
|
|
|
|
.menu-textbox {
|
|
float: left;
|
|
height: 24px;
|
|
margin: 10px 5px;
|
|
padding: 5px 5px;
|
|
font-family: Consolas, "DejaVu Sans Mono", Monaco, monospace;
|
|
font-size: 14px;
|
|
box-sizing: border-box;
|
|
border: 1px solid #888;
|
|
border-radius: 4px;
|
|
outline: none;
|
|
background-color: #eee;
|
|
transition: background-color 0.2s, border 0.2s;
|
|
width: calc(100% - 10px);
|
|
}
|
|
|
|
.menu-textbox.invalid,
|
|
.dark .menu-textbox.invalid {
|
|
color: red;
|
|
}
|
|
|
|
.dark .menu-textbox {
|
|
background-color: #222;
|
|
color: #eee;
|
|
}
|
|
|
|
.radio-container {
|
|
margin: 4px;
|
|
}
|
|
|
|
.topmostdiv {
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 100%;
|
|
background-color: white;
|
|
transition: background-color 0.3s;
|
|
min-height: 100%;
|
|
}
|
|
|
|
#top {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
justify-content: flex-end;
|
|
align-items: center;
|
|
}
|
|
|
|
#topdivider {
|
|
border-bottom: 2px solid black;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
.dark #topdivider {
|
|
border-bottom: 2px solid #ccc;
|
|
}
|
|
|
|
#topdivider>div {
|
|
position: relative;
|
|
}
|
|
|
|
#toptoggle {
|
|
cursor: pointer;
|
|
user-select: none;
|
|
position: absolute;
|
|
padding: 0.1rem 0.3rem;
|
|
top: -0.4rem;
|
|
left: -1rem;
|
|
font-size: 1.4rem;
|
|
line-height: 60%;
|
|
border: 1px solid black;
|
|
border-radius: 1rem;
|
|
background-color: #fff;
|
|
z-index: 100;
|
|
}
|
|
|
|
.flipped {
|
|
transform: rotate(0.5turn);
|
|
}
|
|
|
|
.dark #toptoggle {
|
|
border: 1px solid #fff;
|
|
background-color: #222;
|
|
}
|
|
|
|
#fileinfodiv {
|
|
flex: 20rem 1 0;
|
|
overflow: auto;
|
|
}
|
|
|
|
#bomcontrols {
|
|
display: flex;
|
|
flex-direction: row-reverse;
|
|
}
|
|
|
|
#bomcontrols>* {
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
#dbg {
|
|
display: block;
|
|
}
|
|
|
|
::-webkit-scrollbar {
|
|
width: 8px;
|
|
}
|
|
|
|
::-webkit-scrollbar-track {
|
|
background: #aaa;
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb {
|
|
background: #666;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb:hover {
|
|
background: #555;
|
|
}
|
|
|
|
.slider {
|
|
-webkit-appearance: none;
|
|
width: 100%;
|
|
margin: 3px 0;
|
|
padding: 0;
|
|
outline: none;
|
|
opacity: 0.7;
|
|
-webkit-transition: .2s;
|
|
transition: opacity .2s;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
.slider:hover {
|
|
opacity: 1;
|
|
}
|
|
|
|
.slider:focus {
|
|
outline: none;
|
|
}
|
|
|
|
.slider::-webkit-slider-runnable-track {
|
|
-webkit-appearance: none;
|
|
width: 100%;
|
|
height: 8px;
|
|
background: #d3d3d3;
|
|
border-radius: 3px;
|
|
border: none;
|
|
}
|
|
|
|
.slider::-webkit-slider-thumb {
|
|
-webkit-appearance: none;
|
|
width: 15px;
|
|
height: 15px;
|
|
border-radius: 50%;
|
|
background: #0a0;
|
|
cursor: pointer;
|
|
margin-top: -4px;
|
|
}
|
|
|
|
.dark .slider::-webkit-slider-thumb {
|
|
background: #3d3;
|
|
}
|
|
|
|
.slider::-moz-range-thumb {
|
|
width: 15px;
|
|
height: 15px;
|
|
border-radius: 50%;
|
|
background: #0a0;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.slider::-moz-range-track {
|
|
height: 8px;
|
|
background: #d3d3d3;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
.dark .slider::-moz-range-thumb {
|
|
background: #3d3;
|
|
}
|
|
|
|
.slider::-ms-track {
|
|
width: 100%;
|
|
height: 8px;
|
|
border-width: 3px 0;
|
|
background: transparent;
|
|
border-color: transparent;
|
|
color: transparent;
|
|
transition: opacity .2s;
|
|
}
|
|
|
|
.slider::-ms-fill-lower {
|
|
background: #d3d3d3;
|
|
border: none;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
.slider::-ms-fill-upper {
|
|
background: #d3d3d3;
|
|
border: none;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
.slider::-ms-thumb {
|
|
width: 15px;
|
|
height: 15px;
|
|
border-radius: 50%;
|
|
background: #0a0;
|
|
cursor: pointer;
|
|
margin: 0;
|
|
}
|
|
|
|
.shameless-plug {
|
|
font-size: 0.8em;
|
|
text-align: center;
|
|
display: block;
|
|
}
|
|
|
|
a {
|
|
color: #0278a4;
|
|
}
|
|
|
|
.dark a {
|
|
color: #00b9fd;
|
|
}
|
|
|
|
#frontcanvas,
|
|
#backcanvas {
|
|
touch-action: none;
|
|
}
|
|
|
|
.placeholder {
|
|
border: 1px dashed #9f9fda !important;
|
|
background-color: #edf2f7 !important;
|
|
}
|
|
|
|
.dragging {
|
|
z-index: 999;
|
|
}
|
|
|
|
.dark .dragging>table>tbody>tr {
|
|
background-color: #252c30;
|
|
}
|
|
|
|
.dark .placeholder {
|
|
filter: invert(1);
|
|
}
|
|
|
|
.column-spacer {
|
|
top: 0;
|
|
left: 0;
|
|
width: calc(100% - 4px);
|
|
position: absolute;
|
|
cursor: pointer;
|
|
user-select: none;
|
|
height: 100%;
|
|
}
|
|
|
|
.column-width-handle {
|
|
top: 0;
|
|
right: 0;
|
|
width: 4px;
|
|
position: absolute;
|
|
cursor: col-resize;
|
|
user-select: none;
|
|
height: 100%;
|
|
}
|
|
|
|
.column-width-handle:hover {
|
|
background-color: #4f99bd;
|
|
}
|
|
|
|
.help-link {
|
|
border: 1px solid #0278a4;
|
|
padding-inline: 0.3rem;
|
|
border-radius: 3px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.dark .help-link {
|
|
border: 1px solid #00b9fd;
|
|
}
|
|
|
|
.bom-color {
|
|
width: 20%;
|
|
}
|
|
|
|
.color-column input {
|
|
width: 1.6rem;
|
|
height: 1rem;
|
|
border: 1px solid black;
|
|
cursor: pointer;
|
|
padding: 0;
|
|
}
|
|
|
|
/* removes default styling from input color element */
|
|
::-webkit-color-swatch {
|
|
border: none;
|
|
}
|
|
|
|
::-webkit-color-swatch-wrapper {
|
|
padding: 0;
|
|
}
|
|
|
|
::-moz-color-swatch,
|
|
::-moz-focus-inner {
|
|
border: none;
|
|
}
|
|
|
|
::-moz-focus-inner {
|
|
padding: 0;
|
|
}
|
|
|
|
</style>
|
|
<script type="text/javascript" >
|
|
///////////////////////////////////////////////
|
|
/*
|
|
Split.js - v1.3.5
|
|
MIT License
|
|
https://github.com/nathancahill/Split.js
|
|
*/
|
|
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.Split=t()}(this,function(){"use strict";var e=window,t=e.document,n="addEventListener",i="removeEventListener",r="getBoundingClientRect",s=function(){return!1},o=e.attachEvent&&!e[n],a=["","-webkit-","-moz-","-o-"].filter(function(e){var n=t.createElement("div");return n.style.cssText="width:"+e+"calc(9px)",!!n.style.length}).shift()+"calc",l=function(e){return"string"==typeof e||e instanceof String?t.querySelector(e):e};return function(u,c){function z(e,t,n){var i=A(y,t,n);Object.keys(i).forEach(function(t){return e.style[t]=i[t]})}function h(e,t){var n=B(y,t);Object.keys(n).forEach(function(t){return e.style[t]=n[t]})}function f(e){var t=E[this.a],n=E[this.b],i=t.size+n.size;t.size=e/this.size*i,n.size=i-e/this.size*i,z(t.element,t.size,this.aGutterSize),z(n.element,n.size,this.bGutterSize)}function m(e){var t;this.dragging&&((t="touches"in e?e.touches[0][b]-this.start:e[b]-this.start)<=E[this.a].minSize+M+this.aGutterSize?t=E[this.a].minSize+this.aGutterSize:t>=this.size-(E[this.b].minSize+M+this.bGutterSize)&&(t=this.size-(E[this.b].minSize+this.bGutterSize)),f.call(this,t),c.onDrag&&c.onDrag())}function g(){var e=E[this.a].element,t=E[this.b].element;this.size=e[r]()[y]+t[r]()[y]+this.aGutterSize+this.bGutterSize,this.start=e[r]()[G]}function d(){var t=this,n=E[t.a].element,r=E[t.b].element;t.dragging&&c.onDragEnd&&c.onDragEnd(),t.dragging=!1,e[i]("mouseup",t.stop),e[i]("touchend",t.stop),e[i]("touchcancel",t.stop),t.parent[i]("mousemove",t.move),t.parent[i]("touchmove",t.move),delete t.stop,delete t.move,n[i]("selectstart",s),n[i]("dragstart",s),r[i]("selectstart",s),r[i]("dragstart",s),n.style.userSelect="",n.style.webkitUserSelect="",n.style.MozUserSelect="",n.style.pointerEvents="",r.style.userSelect="",r.style.webkitUserSelect="",r.style.MozUserSelect="",r.style.pointerEvents="",t.gutter.style.cursor="",t.parent.style.cursor=""}function S(t){var i=this,r=E[i.a].element,o=E[i.b].element;!i.dragging&&c.onDragStart&&c.onDragStart(),t.preventDefault(),i.dragging=!0,i.move=m.bind(i),i.stop=d.bind(i),e[n]("mouseup",i.stop),e[n]("touchend",i.stop),e[n]("touchcancel",i.stop),i.parent[n]("mousemove",i.move),i.parent[n]("touchmove",i.move),r[n]("selectstart",s),r[n]("dragstart",s),o[n]("selectstart",s),o[n]("dragstart",s),r.style.userSelect="none",r.style.webkitUserSelect="none",r.style.MozUserSelect="none",r.style.pointerEvents="none",o.style.userSelect="none",o.style.webkitUserSelect="none",o.style.MozUserSelect="none",o.style.pointerEvents="none",i.gutter.style.cursor=j,i.parent.style.cursor=j,g.call(i)}function v(e){e.forEach(function(t,n){if(n>0){var i=F[n-1],r=E[i.a],s=E[i.b];r.size=e[n-1],s.size=t,z(r.element,r.size,i.aGutterSize),z(s.element,s.size,i.bGutterSize)}})}function p(){F.forEach(function(e){e.parent.removeChild(e.gutter),E[e.a].element.style[y]="",E[e.b].element.style[y]=""})}void 0===c&&(c={});var y,b,G,E,w=l(u[0]).parentNode,D=e.getComputedStyle(w).flexDirection,U=c.sizes||u.map(function(){return 100/u.length}),k=void 0!==c.minSize?c.minSize:100,x=Array.isArray(k)?k:u.map(function(){return k}),L=void 0!==c.gutterSize?c.gutterSize:10,M=void 0!==c.snapOffset?c.snapOffset:30,O=c.direction||"horizontal",j=c.cursor||("horizontal"===O?"ew-resize":"ns-resize"),C=c.gutter||function(e,n){var i=t.createElement("div");return i.className="gutter gutter-"+n,i},A=c.elementStyle||function(e,t,n){var i={};return"string"==typeof t||t instanceof String?i[e]=t:i[e]=o?t+"%":a+"("+t+"% - "+n+"px)",i},B=c.gutterStyle||function(e,t){return n={},n[e]=t+"px",n;var n};"horizontal"===O?(y="width","clientWidth",b="clientX",G="left","paddingLeft"):"vertical"===O&&(y="height","clientHeight",b="clientY",G="top","paddingTop");var F=[];return E=u.map(function(e,t){var i,s={element:l(e),size:U[t],minSize:x[t]};if(t>0&&(i={a:t-1,b:t,dragging:!1,isFirst:1===t,isLast:t===u.length-1,direction:O,parent:w},i.aGutterSize=L,i.bGutterSize=L,i.isFirst&&(i.aGutterSize=L/2),i.isLast&&(i.bGutterSize=L/2),"row-reverse"===D||"column-reverse"===D)){var a=i.a;i.a=i.b,i.b=a}if(!o&&t>0){var c=C(t,O);h(c,L),c[n]("mousedown",S.bind(i)),c[n]("touchstart",S.bind(i)),w.insertBefore(c,s.element),i.gutter=c}0===t||t===u.length-1?z(s.element,s.size,L/2):z(s.element,s.size,L);var f=s.element[r]()[y];return f<s.minSize&&(s.minSize=f),t>0&&F.push(i),s}),o?{setSizes:v,destroy:p}:{setSizes:v,getSizes:function(){return E.map(function(e){return e.size})},collapse:function(e){if(e===F.length){var t=F[e-1];g.call(t),o||f.call(t,t.size-t.bGutterSize)}else{var n=F[e];g.call(n),o||f.call(n,n.aGutterSize)}},destroy:p}}});
|
|
|
|
///////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////////////
|
|
// Copyright (c) 2013 Pieroxy <pieroxy@pieroxy.net>
|
|
// This work is free. You can redistribute it and/or modify it
|
|
// under the terms of the WTFPL, Version 2
|
|
// For more information see LICENSE.txt or http://www.wtfpl.net/
|
|
//
|
|
// For more information, the home page:
|
|
// http://pieroxy.net/blog/pages/lz-string/testing.html
|
|
//
|
|
// LZ-based compression algorithm, version 1.4.4
|
|
var LZString=function(){var o=String.fromCharCode,i={};var n={decompressFromBase64:function(o){return null==o?"":""==o?null:n._decompress(o.length,32,function(n){return function(o,n){if(!i[o]){i[o]={};for(var t=0;t<o.length;t++)i[o][o.charAt(t)]=t}return i[o][n]}("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",o.charAt(n))})},_decompress:function(i,n,t){var r,e,a,s,p,u,l,f=[],c=4,d=4,h=3,v="",g=[],m={val:t(0),position:n,index:1};for(r=0;r<3;r+=1)f[r]=r;for(a=0,p=Math.pow(2,2),u=1;u!=p;)s=m.val&m.position,m.position>>=1,0==m.position&&(m.position=n,m.val=t(m.index++)),a|=(s>0?1:0)*u,u<<=1;switch(a){case 0:for(a=0,p=Math.pow(2,8),u=1;u!=p;)s=m.val&m.position,m.position>>=1,0==m.position&&(m.position=n,m.val=t(m.index++)),a|=(s>0?1:0)*u,u<<=1;l=o(a);break;case 1:for(a=0,p=Math.pow(2,16),u=1;u!=p;)s=m.val&m.position,m.position>>=1,0==m.position&&(m.position=n,m.val=t(m.index++)),a|=(s>0?1:0)*u,u<<=1;l=o(a);break;case 2:return""}for(f[3]=l,e=l,g.push(l);;){if(m.index>i)return"";for(a=0,p=Math.pow(2,h),u=1;u!=p;)s=m.val&m.position,m.position>>=1,0==m.position&&(m.position=n,m.val=t(m.index++)),a|=(s>0?1:0)*u,u<<=1;switch(l=a){case 0:for(a=0,p=Math.pow(2,8),u=1;u!=p;)s=m.val&m.position,m.position>>=1,0==m.position&&(m.position=n,m.val=t(m.index++)),a|=(s>0?1:0)*u,u<<=1;f[d++]=o(a),l=d-1,c--;break;case 1:for(a=0,p=Math.pow(2,16),u=1;u!=p;)s=m.val&m.position,m.position>>=1,0==m.position&&(m.position=n,m.val=t(m.index++)),a|=(s>0?1:0)*u,u<<=1;f[d++]=o(a),l=d-1,c--;break;case 2:return g.join("")}if(0==c&&(c=Math.pow(2,h),h++),f[l])v=f[l];else{if(l!==d)return null;v=e+e.charAt(0)}g.push(v),f[d++]=e+v.charAt(0),e=v,0==--c&&(c=Math.pow(2,h),h++)}}};return n}();"function"==typeof define&&define.amd?define(function(){return LZString}):"undefined"!=typeof module&&null!=module?module.exports=LZString:"undefined"!=typeof angular&&null!=angular&&angular.module("LZString",[]).factory("LZString",function(){return LZString});
|
|
///////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////////////
|
|
/*!
|
|
* PEP v0.4.3 | https://github.com/jquery/PEP
|
|
* Copyright jQuery Foundation and other contributors | http://jquery.org/license
|
|
*/
|
|
!function(a,b){"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):a.PointerEventsPolyfill=b()}(this,function(){"use strict";function a(a,b){b=b||Object.create(null);var c=document.createEvent("Event");c.initEvent(a,b.bubbles||!1,b.cancelable||!1);
|
|
for(var d,e=2;e<m.length;e++)d=m[e],c[d]=b[d]||n[e];c.buttons=b.buttons||0;
|
|
var f=0;return f=b.pressure&&c.buttons?b.pressure:c.buttons?.5:0,c.x=c.clientX,c.y=c.clientY,c.pointerId=b.pointerId||0,c.width=b.width||0,c.height=b.height||0,c.pressure=f,c.tiltX=b.tiltX||0,c.tiltY=b.tiltY||0,c.twist=b.twist||0,c.tangentialPressure=b.tangentialPressure||0,c.pointerType=b.pointerType||"",c.hwTimestamp=b.hwTimestamp||0,c.isPrimary=b.isPrimary||!1,c}function b(){this.array=[],this.size=0}function c(a,b,c,d){this.addCallback=a.bind(d),this.removeCallback=b.bind(d),this.changedCallback=c.bind(d),A&&(this.observer=new A(this.mutationWatcher.bind(this)))}function d(a){return"body /shadow-deep/ "+e(a)}function e(a){return'[touch-action="'+a+'"]'}function f(a){return"{ -ms-touch-action: "+a+"; touch-action: "+a+"; }"}function g(){if(F){D.forEach(function(a){String(a)===a?(E+=e(a)+f(a)+"\n",G&&(E+=d(a)+f(a)+"\n")):(E+=a.selectors.map(e)+f(a.rule)+"\n",G&&(E+=a.selectors.map(d)+f(a.rule)+"\n"))});var a=document.createElement("style");a.textContent=E,document.head.appendChild(a)}}function h(){if(!window.PointerEvent){if(window.PointerEvent=a,window.navigator.msPointerEnabled){var b=window.navigator.msMaxTouchPoints;Object.defineProperty(window.navigator,"maxTouchPoints",{value:b,enumerable:!0}),u.registerSource("ms",_)}else Object.defineProperty(window.navigator,"maxTouchPoints",{value:0,enumerable:!0}),u.registerSource("mouse",N),void 0!==window.ontouchstart&&u.registerSource("touch",V);u.register(document)}}function i(a){if(!u.pointermap.has(a)){var b=new Error("InvalidPointerId");throw b.name="InvalidPointerId",b}}function j(a){for(var b=a.parentNode;b&&b!==a.ownerDocument;)b=b.parentNode;if(!b){var c=new Error("InvalidStateError");throw c.name="InvalidStateError",c}}function k(a){var b=u.pointermap.get(a);return 0!==b.buttons}function l(){window.Element&&!Element.prototype.setPointerCapture&&Object.defineProperties(Element.prototype,{setPointerCapture:{value:W},releasePointerCapture:{value:X},hasPointerCapture:{value:Y}})}
|
|
var m=["bubbles","cancelable","view","detail","screenX","screenY","clientX","clientY","ctrlKey","altKey","shiftKey","metaKey","button","relatedTarget","pageX","pageY"],n=[!1,!1,null,null,0,0,0,0,!1,!1,!1,!1,0,null,0,0],o=window.Map&&window.Map.prototype.forEach,p=o?Map:b;b.prototype={set:function(a,b){return void 0===b?this["delete"](a):(this.has(a)||this.size++,void(this.array[a]=b))},has:function(a){return void 0!==this.array[a]},"delete":function(a){this.has(a)&&(delete this.array[a],this.size--)},get:function(a){return this.array[a]},clear:function(){this.array.length=0,this.size=0},forEach:function(a,b){return this.array.forEach(function(c,d){a.call(b,c,d,this)},this)}};var q=["bubbles","cancelable","view","detail","screenX","screenY","clientX","clientY","ctrlKey","altKey","shiftKey","metaKey","button","relatedTarget","buttons","pointerId","width","height","pressure","tiltX","tiltY","pointerType","hwTimestamp","isPrimary","type","target","currentTarget","which","pageX","pageY","timeStamp"],r=[!1,!1,null,null,0,0,0,0,!1,!1,!1,!1,0,null,0,0,0,0,0,0,0,"",0,!1,"",null,null,0,0,0,0],s={pointerover:1,pointerout:1,pointerenter:1,pointerleave:1},t="undefined"!=typeof SVGElementInstance,u={pointermap:new p,eventMap:Object.create(null),captureInfo:Object.create(null),eventSources:Object.create(null),eventSourceList:[],registerSource:function(a,b){var c=b,d=c.events;d&&(d.forEach(function(a){c[a]&&(this.eventMap[a]=c[a].bind(c))},this),this.eventSources[a]=c,this.eventSourceList.push(c))},register:function(a){for(var b,c=this.eventSourceList.length,d=0;d<c&&(b=this.eventSourceList[d]);d++)
|
|
b.register.call(b,a)},unregister:function(a){for(var b,c=this.eventSourceList.length,d=0;d<c&&(b=this.eventSourceList[d]);d++)
|
|
b.unregister.call(b,a)},contains:function(a,b){try{return a.contains(b)}catch(c){return!1}},down:function(a){a.bubbles=!0,this.fireEvent("pointerdown",a)},move:function(a){a.bubbles=!0,this.fireEvent("pointermove",a)},up:function(a){a.bubbles=!0,this.fireEvent("pointerup",a)},enter:function(a){a.bubbles=!1,this.fireEvent("pointerenter",a)},leave:function(a){a.bubbles=!1,this.fireEvent("pointerleave",a)},over:function(a){a.bubbles=!0,this.fireEvent("pointerover",a)},out:function(a){a.bubbles=!0,this.fireEvent("pointerout",a)},cancel:function(a){a.bubbles=!0,this.fireEvent("pointercancel",a)},leaveOut:function(a){this.out(a),this.propagate(a,this.leave,!1)},enterOver:function(a){this.over(a),this.propagate(a,this.enter,!0)},eventHandler:function(a){if(!a._handledByPE){var b=a.type,c=this.eventMap&&this.eventMap[b];c&&c(a),a._handledByPE=!0}},listen:function(a,b){b.forEach(function(b){this.addEvent(a,b)},this)},unlisten:function(a,b){b.forEach(function(b){this.removeEvent(a,b)},this)},addEvent:function(a,b){a.addEventListener(b,this.boundHandler)},removeEvent:function(a,b){a.removeEventListener(b,this.boundHandler)},makeEvent:function(b,c){this.captureInfo[c.pointerId]&&(c.relatedTarget=null);var d=new a(b,c);return c.preventDefault&&(d.preventDefault=c.preventDefault),d._target=d._target||c.target,d},fireEvent:function(a,b){var c=this.makeEvent(a,b);return this.dispatchEvent(c)},cloneEvent:function(a){for(var b,c=Object.create(null),d=0;d<q.length;d++)b=q[d],c[b]=a[b]||r[d],!t||"target"!==b&&"relatedTarget"!==b||c[b]instanceof SVGElementInstance&&(c[b]=c[b].correspondingUseElement);return a.preventDefault&&(c.preventDefault=function(){a.preventDefault()}),c},getTarget:function(a){var b=this.captureInfo[a.pointerId];return b?a._target!==b&&a.type in s?void 0:b:a._target},propagate:function(a,b,c){for(var d=a.target,e=[];d!==document&&!d.contains(a.relatedTarget);) if(e.push(d),d=d.parentNode,!d)return;c&&e.reverse(),e.forEach(function(c){a.target=c,b.call(this,a)},this)},setCapture:function(b,c,d){this.captureInfo[b]&&this.releaseCapture(b,d),this.captureInfo[b]=c,this.implicitRelease=this.releaseCapture.bind(this,b,d),document.addEventListener("pointerup",this.implicitRelease),document.addEventListener("pointercancel",this.implicitRelease);var e=new a("gotpointercapture");e.pointerId=b,e._target=c,d||this.asyncDispatchEvent(e)},releaseCapture:function(b,c){var d=this.captureInfo[b];if(d){this.captureInfo[b]=void 0,document.removeEventListener("pointerup",this.implicitRelease),document.removeEventListener("pointercancel",this.implicitRelease);var e=new a("lostpointercapture");e.pointerId=b,e._target=d,c||this.asyncDispatchEvent(e)}},dispatchEvent:/*scope.external.dispatchEvent || */function(a){var b=this.getTarget(a);if(b)return b.dispatchEvent(a)},asyncDispatchEvent:function(a){requestAnimationFrame(this.dispatchEvent.bind(this,a))}};u.boundHandler=u.eventHandler.bind(u);var v={shadow:function(a){if(a)return a.shadowRoot||a.webkitShadowRoot},canTarget:function(a){return a&&Boolean(a.elementFromPoint)},targetingShadow:function(a){var b=this.shadow(a);if(this.canTarget(b))return b},olderShadow:function(a){var b=a.olderShadowRoot;if(!b){var c=a.querySelector("shadow");c&&(b=c.olderShadowRoot)}return b},allShadows:function(a){for(var b=[],c=this.shadow(a);c;)b.push(c),c=this.olderShadow(c);return b},searchRoot:function(a,b,c){if(a){var d,e,f=a.elementFromPoint(b,c);for(e=this.targetingShadow(f);e;){if(d=e.elementFromPoint(b,c)){var g=this.targetingShadow(d);return this.searchRoot(g,b,c)||d} e=this.olderShadow(e)} return f}},owner:function(a){
|
|
for(var b=a;b.parentNode;)b=b.parentNode;
|
|
return b.nodeType!==Node.DOCUMENT_NODE&&b.nodeType!==Node.DOCUMENT_FRAGMENT_NODE&&(b=document),b},findTarget:function(a){var b=a.clientX,c=a.clientY,d=this.owner(a.target);
|
|
return d.elementFromPoint(b,c)||(d=document),this.searchRoot(d,b,c)}},w=Array.prototype.forEach.call.bind(Array.prototype.forEach),x=Array.prototype.map.call.bind(Array.prototype.map),y=Array.prototype.slice.call.bind(Array.prototype.slice),z=Array.prototype.filter.call.bind(Array.prototype.filter),A=window.MutationObserver||window.WebKitMutationObserver,B="[touch-action]",C={subtree:!0,childList:!0,attributes:!0,attributeOldValue:!0,attributeFilter:["touch-action"]};c.prototype={watchSubtree:function(a){
|
|
//
|
|
this.observer&&v.canTarget(a)&&this.observer.observe(a,C)},enableOnSubtree:function(a){this.watchSubtree(a),a===document&&"complete"!==document.readyState?this.installOnLoad():this.installNewSubtree(a)},installNewSubtree:function(a){w(this.findElements(a),this.addElement,this)},findElements:function(a){return a.querySelectorAll?a.querySelectorAll(B):[]},removeElement:function(a){this.removeCallback(a)},addElement:function(a){this.addCallback(a)},elementChanged:function(a,b){this.changedCallback(a,b)},concatLists:function(a,b){return a.concat(y(b))},
|
|
installOnLoad:function(){document.addEventListener("readystatechange",function(){"complete"===document.readyState&&this.installNewSubtree(document)}.bind(this))},isElement:function(a){return a.nodeType===Node.ELEMENT_NODE},flattenMutationTree:function(a){
|
|
var b=x(a,this.findElements,this);
|
|
return b.push(z(a,this.isElement)),b.reduce(this.concatLists,[])},mutationWatcher:function(a){a.forEach(this.mutationHandler,this)},mutationHandler:function(a){if("childList"===a.type){var b=this.flattenMutationTree(a.addedNodes);b.forEach(this.addElement,this);var c=this.flattenMutationTree(a.removedNodes);c.forEach(this.removeElement,this)}else"attributes"===a.type&&this.elementChanged(a.target,a.oldValue)}};var D=["none","auto","pan-x","pan-y",{rule:"pan-x pan-y",selectors:["pan-x pan-y","pan-y pan-x"]}],E="",F=window.PointerEvent||window.MSPointerEvent,G=!window.ShadowDOMPolyfill&&document.head.createShadowRoot,H=u.pointermap,I=25,J=[1,4,2,8,16],K=!1;try{K=1===new MouseEvent("test",{buttons:1}).buttons}catch(L){}
|
|
var M,N={POINTER_ID:1,POINTER_TYPE:"mouse",events:["mousedown","mousemove","mouseup","mouseover","mouseout"],register:function(a){u.listen(a,this.events)},unregister:function(a){u.unlisten(a,this.events)},lastTouches:[],
|
|
isEventSimulatedFromTouch:function(a){for(var b,c=this.lastTouches,d=a.clientX,e=a.clientY,f=0,g=c.length;f<g&&(b=c[f]);f++){
|
|
var h=Math.abs(d-b.x),i=Math.abs(e-b.y);if(h<=I&&i<=I)return!0}},prepareEvent:function(a){var b=u.cloneEvent(a),c=b.preventDefault;return b.preventDefault=function(){a.preventDefault(),c()},b.pointerId=this.POINTER_ID,b.isPrimary=!0,b.pointerType=this.POINTER_TYPE,b},prepareButtonsForMove:function(a,b){var c=H.get(this.POINTER_ID);
|
|
0!==b.which&&c?a.buttons=c.buttons:a.buttons=0,b.buttons=a.buttons},mousedown:function(a){if(!this.isEventSimulatedFromTouch(a)){var b=H.get(this.POINTER_ID),c=this.prepareEvent(a);K||(c.buttons=J[c.button],b&&(c.buttons|=b.buttons),a.buttons=c.buttons),H.set(this.POINTER_ID,a),b&&0!==b.buttons?u.move(c):u.down(c)}},mousemove:function(a){if(!this.isEventSimulatedFromTouch(a)){var b=this.prepareEvent(a);K||this.prepareButtonsForMove(b,a),b.button=-1,H.set(this.POINTER_ID,a),u.move(b)}},mouseup:function(a){if(!this.isEventSimulatedFromTouch(a)){var b=H.get(this.POINTER_ID),c=this.prepareEvent(a);if(!K){var d=J[c.button];
|
|
c.buttons=b?b.buttons&~d:0,a.buttons=c.buttons}H.set(this.POINTER_ID,a),
|
|
c.buttons&=~J[c.button],0===c.buttons?u.up(c):u.move(c)}},mouseover:function(a){if(!this.isEventSimulatedFromTouch(a)){var b=this.prepareEvent(a);K||this.prepareButtonsForMove(b,a),b.button=-1,H.set(this.POINTER_ID,a),u.enterOver(b)}},mouseout:function(a){if(!this.isEventSimulatedFromTouch(a)){var b=this.prepareEvent(a);K||this.prepareButtonsForMove(b,a),b.button=-1,u.leaveOut(b)}},cancel:function(a){var b=this.prepareEvent(a);u.cancel(b),this.deactivateMouse()},deactivateMouse:function(){H["delete"](this.POINTER_ID)}},O=u.captureInfo,P=v.findTarget.bind(v),Q=v.allShadows.bind(v),R=u.pointermap,S=2500,T=200,U="touch-action",V={events:["touchstart","touchmove","touchend","touchcancel"],register:function(a){M.enableOnSubtree(a)},unregister:function(){},elementAdded:function(a){var b=a.getAttribute(U),c=this.touchActionToScrollType(b);c&&(a._scrollType=c,u.listen(a,this.events),
|
|
Q(a).forEach(function(a){a._scrollType=c,u.listen(a,this.events)},this))},elementRemoved:function(a){a._scrollType=void 0,u.unlisten(a,this.events),
|
|
Q(a).forEach(function(a){a._scrollType=void 0,u.unlisten(a,this.events)},this)},elementChanged:function(a,b){var c=a.getAttribute(U),d=this.touchActionToScrollType(c),e=this.touchActionToScrollType(b);
|
|
d&&e?(a._scrollType=d,Q(a).forEach(function(a){a._scrollType=d},this)):e?this.elementRemoved(a):d&&this.elementAdded(a)},scrollTypes:{EMITTER:"none",XSCROLLER:"pan-x",YSCROLLER:"pan-y",SCROLLER:/^(?:pan-x pan-y)|(?:pan-y pan-x)|auto$/},touchActionToScrollType:function(a){var b=a,c=this.scrollTypes;return"none"===b?"none":b===c.XSCROLLER?"X":b===c.YSCROLLER?"Y":c.SCROLLER.exec(b)?"XY":void 0},POINTER_TYPE:"touch",firstTouch:null,isPrimaryTouch:function(a){return this.firstTouch===a.identifier},setPrimaryTouch:function(a){
|
|
(0===R.size||1===R.size&&R.has(1))&&(this.firstTouch=a.identifier,this.firstXY={X:a.clientX,Y:a.clientY},this.scrolling=!1,this.cancelResetClickCount())},removePrimaryPointer:function(a){a.isPrimary&&(this.firstTouch=null,this.firstXY=null,this.resetClickCount())},clickCount:0,resetId:null,resetClickCount:function(){var a=function(){this.clickCount=0,this.resetId=null}.bind(this);this.resetId=setTimeout(a,T)},cancelResetClickCount:function(){this.resetId&&clearTimeout(this.resetId)},typeToButtons:function(a){var b=0;return"touchstart"!==a&&"touchmove"!==a||(b=1),b},touchToPointer:function(a){var b=this.currentTouchEvent,c=u.cloneEvent(a),d=c.pointerId=a.identifier+2;c.target=O[d]||P(c),c.bubbles=!0,c.cancelable=!0,c.detail=this.clickCount,c.button=0,c.buttons=this.typeToButtons(b.type),c.width=2*(a.radiusX||a.webkitRadiusX||0),c.height=2*(a.radiusY||a.webkitRadiusY||0),c.pressure=a.force||a.webkitForce||.5,c.isPrimary=this.isPrimaryTouch(a),c.pointerType=this.POINTER_TYPE,
|
|
c.altKey=b.altKey,c.ctrlKey=b.ctrlKey,c.metaKey=b.metaKey,c.shiftKey=b.shiftKey;
|
|
var e=this;return c.preventDefault=function(){e.scrolling=!1,e.firstXY=null,b.preventDefault()},c},processTouches:function(a,b){var c=a.changedTouches;this.currentTouchEvent=a;for(var d,e=0;e<c.length;e++)d=c[e],b.call(this,this.touchToPointer(d))},
|
|
shouldScroll:function(a){if(this.firstXY){var b,c=a.currentTarget._scrollType;if("none"===c)
|
|
b=!1;else if("XY"===c)
|
|
b=!0;else{var d=a.changedTouches[0],e=c,f="Y"===c?"X":"Y",g=Math.abs(d["client"+e]-this.firstXY[e]),h=Math.abs(d["client"+f]-this.firstXY[f]);
|
|
b=g>=h}return this.firstXY=null,b}},findTouch:function(a,b){for(var c,d=0,e=a.length;d<e&&(c=a[d]);d++)if(c.identifier===b)return!0},
|
|
vacuumTouches:function(a){var b=a.touches;
|
|
if(R.size>=b.length){var c=[];R.forEach(function(a,d){
|
|
if(1!==d&&!this.findTouch(b,d-2)){var e=a.out;c.push(e)}},this),c.forEach(this.cancelOut,this)}},touchstart:function(a){this.vacuumTouches(a),this.setPrimaryTouch(a.changedTouches[0]),this.dedupSynthMouse(a),this.scrolling||(this.clickCount++,this.processTouches(a,this.overDown))},overDown:function(a){R.set(a.pointerId,{target:a.target,out:a,outTarget:a.target}),u.enterOver(a),u.down(a)},touchmove:function(a){this.scrolling||(this.shouldScroll(a)?(this.scrolling=!0,this.touchcancel(a)):(a.preventDefault(),this.processTouches(a,this.moveOverOut)))},moveOverOut:function(a){var b=a,c=R.get(b.pointerId);
|
|
if(c){var d=c.out,e=c.outTarget;u.move(b),d&&e!==b.target&&(d.relatedTarget=b.target,b.relatedTarget=e,
|
|
d.target=e,b.target?(u.leaveOut(d),u.enterOver(b)):(
|
|
b.target=e,b.relatedTarget=null,this.cancelOut(b))),c.out=b,c.outTarget=b.target}},touchend:function(a){this.dedupSynthMouse(a),this.processTouches(a,this.upOut)},upOut:function(a){this.scrolling||(u.up(a),u.leaveOut(a)),this.cleanUpPointer(a)},touchcancel:function(a){this.processTouches(a,this.cancelOut)},cancelOut:function(a){u.cancel(a),u.leaveOut(a),this.cleanUpPointer(a)},cleanUpPointer:function(a){R["delete"](a.pointerId),this.removePrimaryPointer(a)},
|
|
dedupSynthMouse:function(a){var b=N.lastTouches,c=a.changedTouches[0];
|
|
if(this.isPrimaryTouch(c)){
|
|
var d={x:c.clientX,y:c.clientY};b.push(d);var e=function(a,b){var c=a.indexOf(b);c>-1&&a.splice(c,1)}.bind(null,b,d);setTimeout(e,S)}}};M=new c(V.elementAdded,V.elementRemoved,V.elementChanged,V);var W,X,Y,Z=u.pointermap,$=window.MSPointerEvent&&"number"==typeof window.MSPointerEvent.MSPOINTER_TYPE_MOUSE,_={events:["MSPointerDown","MSPointerMove","MSPointerUp","MSPointerOut","MSPointerOver","MSPointerCancel","MSGotPointerCapture","MSLostPointerCapture"],register:function(a){u.listen(a,this.events)},unregister:function(a){u.unlisten(a,this.events)},POINTER_TYPES:["","unavailable","touch","pen","mouse"],prepareEvent:function(a){var b=a;return $&&(b=u.cloneEvent(a),b.pointerType=this.POINTER_TYPES[a.pointerType]),b},cleanup:function(a){Z["delete"](a)},MSPointerDown:function(a){Z.set(a.pointerId,a);var b=this.prepareEvent(a);u.down(b)},MSPointerMove:function(a){var b=this.prepareEvent(a);u.move(b)},MSPointerUp:function(a){var b=this.prepareEvent(a);u.up(b),this.cleanup(a.pointerId)},MSPointerOut:function(a){var b=this.prepareEvent(a);u.leaveOut(b)},MSPointerOver:function(a){var b=this.prepareEvent(a);u.enterOver(b)},MSPointerCancel:function(a){var b=this.prepareEvent(a);u.cancel(b),this.cleanup(a.pointerId)},MSLostPointerCapture:function(a){var b=u.makeEvent("lostpointercapture",a);u.dispatchEvent(b)},MSGotPointerCapture:function(a){var b=u.makeEvent("gotpointercapture",a);u.dispatchEvent(b)}},aa=window.navigator;aa.msPointerEnabled?(W=function(a){i(a),j(this),k(a)&&(u.setCapture(a,this,!0),this.msSetPointerCapture(a))},X=function(a){i(a),u.releaseCapture(a,!0),this.msReleasePointerCapture(a)}):(W=function(a){i(a),j(this),k(a)&&u.setCapture(a,this)},X=function(a){i(a),u.releaseCapture(a)}),Y=function(a){return!!u.captureInfo[a]},g(),h(),l();var ba={dispatcher:u,Installer:c,PointerEvent:a,PointerMap:p,targetFinding:v};return ba});
|
|
|
|
///////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////////////
|
|
var config = {"dark_mode": false, "show_pads": true, "show_fabrication": false, "show_silkscreen": true, "highlight_pin1": "none", "redraw_on_drag": true, "board_rotation": 0, "checkboxes": "Sourced,Placed", "bom_view": "left-right", "layer_view": "FB", "offset_back_rotation": false, "kicad_text_formatting": true, "fields": ["Value", "Footprint", "Rating"]}
|
|
///////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////////////
|
|
var pcbdata = JSON.parse(LZString.decompressFromBase64("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3rgeRyBHEkegRy6G4EYcRhhHEUeDebZGAzKEALJH3ob6RzBGG9kKR4FHikdBR85HDAED1M9ADsPLcCJHftiiR+ZH6kcWRtjllkacRmBGtZH7hlJHmUdRRlxGdkexRvZG8UbyRwFHfEeGR/xGSUbXhy4ByUZ0ERmVqkfkuWlHYUdiRw+HrEY+RpFHkkbaRlZGkUcxR7GKeUd6Rz6H+ke4Ro5HBUf4RkZHl4bCAVeHgkfXhgLQzEcbhmFGFkYPh8jamUfRRuvNlUccR+1HWkfSR7lH3EeyR7VH8UahhoFGhUZBR41GJkcYUYRHQ4ZmACOHBkdhh9IR4Yb0kRGHpEeRvVgBE4d8hmuHfL1s6SxJMtTAATOHDAHURql5M0ehRpKHdEZbzfRH5Ufph1wBGYerhsKHZx2TR735LUZ2R2VGGkceRxVHaEdeRzlGnkbPhz5HXUaxR91HcUc9R/lGCUZ9Rg1HhUf9RsFHCEcuARwRqUZVjVW8aUbmRmtGGUc74OtHVUYbR1lGUUfZR51H1kbmRzVGPUbfhrxGBkb1RoZG+0b9R6wATUbKR9eGR0fHRtMjhKhqR5kBJ0etRsBHbUdnRjlHHUbRRzZG1Ua+Rt1GekfXR3JHN0d1RwlHfUeJRgdHSUZiAJNHFamW8GVGr0fhRk+G70cbRpdHH0YxR59H20dfRztGN0YORrdGv0d3Rn9H90YDR01Hh0cLYYRMgMZuRpEA7kdrRhFGoMYdRiDGVUY5R9VGMgB+R1KHjV3+Rn6Gw0ZORo1G0McHRuYAy0awxsmRkCQvRq1H6UZtRpZHb0eXRllHKJDZR0jG+MabR1dGO0dYAGjHDkeQxgwABEYYx1aH0McPR4dG99AlRsdGVgtqR7GKp0e4xxlHeMaIxuxGSMadRnTGV0YyRtdH4MffRxDHP0d7R6THDUbGR39HRUcMALfRlKAOwyybsX2lRy9GuMevRnjHCMeeR1ZGF0ZdRh9GvMafRttGNUbExjhG+UY/R/JGpMZkx6zHGMb/RjIBwbwrR+VFgMbcx0DHqEeEx+9H3kbnRphGYMaCxuDHxMdCxszHwsYsxyLGzkcDR0GHg0fDhmIBvUZhhiRGo0akRkAAPIboAeRGk4c2hpb9yGgNh8IQ00bURqKHc4ahstTHkcRShtKHp0ZwADKHDEeLRquHvTJrh1WLWsZ72cxHOYYl8CqHD4exfO1GDMf4xqwBBMf0x/zHoMcCx04GNMZCxrtGwsYFRndHLMf7R6LHbMY/MArBV7gnRlhH9oZNhw6GFsZOhlLHlseRR3zH0sbIxrLHtsavRiTGkMcKxqzHbTKDR8GGxEbDR6rG5gERhjyHUYZ0AeNHFEfXhjRVXnGChjrH14fCh0gkYzvOccKGcOBzR//ZuCQmwu3cF3COh4bGi0bCAEtHxsc2h98UYcdVzMhG8MeEne5G7sYVR6+HxgBQALJRlJB7hoGQstuZmD9InsfWR+tHMsa2xx+Ge/GoxvLGAUZ7R/VGjsb3RuTGmMcxhy4Bocas8bdwycbhAPzTBseOh6nHwMZ8x9nGMseexneGakHKh+RRPsfMxwXGiseDhu+GysYBx7dHw0dYASNHgcdqx6RGyAEaxhNGWMcpzeZDU0fTRmIBs0dzhrRHesYMAPNGcAlrRoxHS0aPR3cJ3SSrRupG3oc0xmdHPMZbRpVG9Mb8x0PHNsc6RozHgsa1xgrGdcZ+xkVGMMbsx+0Ba5EYQsTpx0ddx6JHA8fcxrTGQ8ZvhsPGlcbeR5tGC8ajxrlHYMZxR3LG9sfyxg7G+EaFx1DGRcZixgwBWdDTx2cIlUXPRmbH3saSxwtHtMY2x4jGi8abRjnHVcdExnLHdsYQx/nHKscOxorGk8YUxuzG60TRIoVxEsZzx5LGS8eaRgfHIMb7x4fGY8dHxuPHa8foxqLHG8dOx2LH58btxjjHc0fJxthS5cYVx1LHw8Zex4THyMYMASjG/kb5x2jGjcf3x4rHk8f/Rk/HwwkXx1zHl8Z7x/PG18YExxdGhMcexh/HukcrxsfHTMYnxz+GiUdORmfHwUaPRnIFlMfVSVvGs8bpR//Gb0cAJl5H18dAJzfHDMZfRyAnd8YFxqfHE8Zsxz/HYseQJylGW3ixCFzHOMcwJjzGwMZvx3An1scjxznHo8cIJ3lHq8ZgJujG4Cdkxg9HECcUx/Sw/caXxuFGACaYJx7G0sdXxjpHy8eyxogmX8ckx77HjscPxkVQ/sdER0NGjcaBxlyHasbchhOH0YetxqHHiceVM5SIQobURxHGJsJRx2KGz8fRxpShRUB78AbGg8aGxzKHRseMR8XGjCZIqFJzO8d3hmXH3lyOhxbHe8cC5OnGGcbAAYWGmcZGC4RQ5nTrcNnHi8aHxggnSoZ5xzXG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OqblxoGmWaeQpmOmsSeqpoaHy6dspyum3SaaJhGnNCaRps3H2iZ2AKcmZyczpwAhNukicOby4cbfphKmP6dXJr+n+sZ8jB5Hqab2pzaHkNsYZ9BnVieZpyBnWaZLpv/G4GcVpk+nEGeuJnSm6fqCBSrpoSYKprenJ6ZBp3en46bEZ+gmJGawpnumAqdKx/7GxqaqxihntCfaJpGGaGd6J5BnQwoBGIVw8aYzR8MnEqZoUKMn54Cph2MmTyf/prKneGahxyxnq8zapuSmXibIpqWnzycepjEn8ye9p1SnFYcIZj6nK6aQZuhnLGc8Jo6mvye4pvxneKZEZnBmAKZUpuinwmfgZiuml6aDhi+mDAC9Joxm2idvptUqH6YMJtwnHStWJmxnHcaWp5HHWSbWpjHHqCU2p2YntqYAZxYmMifS2l+n4mZyJinHwGa6p8IRZScCZxUmyIFZxqBnZ6fSZ16m/aY0pxen6qeXpo/GxnEdK2BTPye6ZiUnuSdeJ4yn3acvJveneqYPp9XGTYcSJrJmiGZyZ37G9GfUJshngqevp5GmrABRpsHG40fMZuhm+tWxp5L5Qyfxp7twxideZkmnZJXzRmYmqaYWJ3cnxcdseJRMnmbFp2Bm86eDx7enVGaNp9untme9p+WnOae0Z1OnpGcap6un/Aw1puEB66dFpjemQWeUZ3BmkKenpp6mxmc7p+emImbqp6fGZGbtplFnR0ZxaWVRR6eBZpmn9aZxZsqmoWdlpwlmj6ckZhBnPqbJZ5BmHmaUTJ2naWZdp6OnsGbxZ4JnvKZHx+QmDmciZo5nomYmx7lm0WiBZrwmI6cvxl4m+mY2ZqimGWaqpimGW4efx8VmSWbIJpFnJKam1bOm8R1zp7FnBWbUZ4un96ZhZrun1Kd7JiVmZmZtp1WnNoZMqqHN0LHRZ1TG+WabpgVmUmaFZrymfictZolntWemZ0lm9WfJZp1mh6bRaalmO8fiZzemr8bcp1unIWa2Z5lmD6dhZ7umEWY5Z4NmuWaKqWVnvWmNZmNn1mbjZj2mE2egZllmd8eJZwNndWb5pkhn9GbOZ8anCmcRhlGm5EdKZqKmvbgpQwekmGYWpiKGtEedx95nw6c+Zj3Hc2Z4Z+5nZaEvmKXHxGdBZokA82Z3p+Nn1GYtZ0umS2YDZq2nJWc5Z+5nfIiFp8XyMWajZrFnc2ewJydmC2enZ6FnZ2bFZtlnsmbtZqun9WfIWVFmxJTApSNmc2aVZ2Nmd2c2ZvdnE2b9Z1ln4WakZtNmK2ZDZltnpMxvZ1ZnlWfzZh9nzWf3Z0VmFadfZ9lmomaXZ6VmW2fECD5n7KlNJz1nFce9ZiqmCWYPppOn9maPZw5mT2alZx1mKUNwgsemxCebptVnRmZCZg9mQOfepnVnA6YdZqHHQ2ZQJtdm3WcxZulmCOdNZqdnAOafZkjm4WbI5stmKOabx4Kqw2c4lK9mdafwZk1mvWbNZmeniOeA59jn/aZdJvumM6elZzNm3uJHZzRmx2aDM7dmIWd3Zljmi2aTZq1mLaamZhdnMOZkZvJmCmYuZyhmrAFjhm5npybuZmuG64ZEUtEZmGYzRnOHNEfzhzini4ZKAUuHXKfmJhMm2mZiAKzmeFNgsMnHznFAR9uHjKcCZojmRWbtJnEnrWdAp21mg2Y/Z4OnGFz6O2DI/OdyJtuHXGbvZ1TmAOdE50LnsSbQRiLnGKYDp3Cng6eIRur9fOYfh8hGAuZS5idm0udVZtJnBKZOJ9hGF6d053XG7aeIR4bdiuZYR0rnjV0C5lTn50cQ5tVnaKfC57TmbWfI510mDOZHJxaGb6fSEFGnuiduZgMnE0ZPx1tnnmbs515mu2c6oD5mXKmbJX9m8cZ2pwBnYsd9x+Tm8OaU5v9n72aq5hOni2cPZ0Dnj2ei5/umy0dTx1dnutvXZn9nhGYQ5kTn8WbE57fGzuY45hrny2au5o9GbucqRhLc04qikB7n6WaY5tTmMud9ZtjmU2bfZ8Dn02czpr1LrPQU53WmPWYnpwjnRGZnZ8TnIebA5xdmYedm523H5uZ7Z2Dmo6eR5kHn0uZe5zLnDAFQ5jHmLua+5mTmbcelw3Dn3WfHpsFmVGe6557nhWfB59HmcuZhp0+nZmaap8/RaCeHFHsY6OY3Zhjn4OeYJnrnquc05/1n0Oai56nnKOeHRqgmn3lJCAHn9uaE5p7nmObB5gLHJeZfZj7m8uek5uXm7MYFQYdmVea3Z8FmWefV50nn2ebe50jnJOfEps+mXyZG5q+mxucuZ9IQPIcpJ6bnH6cuRUgNOmaqZxanmSeWpupn9KfWpxpm0qeaZtxndqczpg6n4QFWJ6XHcicJ5hEm+mcup4ImbqflHTXqlSYepkLnLeaNhiZn6ud15u3n9ebzB8p1Fma8J5Zm4OaOALBnhOfN5tnnNedCZ+0nk6el5obm4aZOZj0n8mdG503HjGdvphtn3ebKZoUmYmziZn3mIoZqZ3OGA+fiZjtAbqmD53+nQ+c251pm/mZ751Co4mZj5npnMGYgZrWRE+euphUnmceGZ5UnUeaA5u0ns+dLZz7muObmZlBmj+1a5oBGTSbj5qqHDucq542mJeZr5vfn52dz5oRGm+aHJlvnHebb5opn0hA6J9Gnu+duJgBJ5GbbZkYmMEDeZrUYJiZ6lJIB1ub/pqfn3GboZ8EnDqehJp4mG0sPc8vmV+ezJ3FnWeZ9Z6vnoSf65yZnBuc459On8+aLhu4m2xBwxu0mEBa2Jy/mEKeRJ5rQ0Bcr5jAXTaeOJ7AWc+ak57SnyWdgF+MkLMJH5mEncifIFtZn88aoF/8QaBdB5i3nMBYYF7LmBuci5hvntKYd58hmjOfb5l3mzGZm5sKHI+c7mBbnqmb952pmkqZH5oPn7CZD56oa5iYHZ/anSAxUFpZnz+d6ZhCnV+cGZjfn7qcckIJm6BfKJ6En7+fr5vAW9eabx5QWsiZMFgGml+av5s3mhBar5+gXd+ahpznmdGbsp6QXzmad54zn0hB9JsznaGYmxl67Hdk3PWznHcbsZthmHGc/J6MnIRReJ/QXfmZppqHG4haj6WSnEmdWZ5AXBYdQFxlnC2eQ5mvnfKf35x/n7We45lmGjSZ8ZwoW/CeX5sXn0BaQ517nbyeApoIXU2eIZ0IWa2dkFj/nWAFjhhQWPea851OH9o2ANRIXCYfs5vOGI2AmJ5znDwW+Zw9ztyeyFjxmxUfGFtUZt4ZK5veGOufK5rMnk+dsF9oWyec5hxgXqheYFnnnq6bi58NmD3S6ZnYXkudIp5Jm1ed8FuwW8GZOFsQWcBYkF5wWWBYK5kZRrhZglRLmKEbc5rrnY6baF3rn0mdOFh/nzhYIRn4WjLCJ6LYW2ubuFoyngRdbJ0EXb+awF94WmBdt5p/mQ4arZy+mZBfCFuQWTceiFizm+GdgAgjbVEfip201EqaWiV3Hv6aOWT3HVhboZ5DbdLP0p9qmhGeB5ivnnhaOFzPnBOe6FqHmseZi5zOnP6CdCFkXOBaUZk3nmeZBF2gXuRZEFxTnKeYw5wknn+aCp/oWCRcGFurGpufM5xQXDCZRGEUnX6YzRwfmSYeH5tXHtBc5J3QXD3KyFjzmZ+cQCdLbdRduFzwXJSZaFqwALBdKFnkbwibT5mwWM+dlFrPnAhfEF3LmoRdPZ8ln3CfiF/6nY+bMFirmfBZJ5vwX7BeOJxwXzuYVFgcmlRYMZqOHa2fNx7/mm2ePxvuNeJDJ0VQXphaW5hzmVuZ7ZtbmC0Z+Zy0WcheHRsDl+MOBCIHnGOc5FyMWXhYspw+m52acFg/n8Babx49HKkY1YRQZIkdHZ1XnWhelFsEXTuet5nTmahYDF4On2xcYQj54aWfo5/lmiedrF47mNGc4JiTnhxf9FrDmj0dYxsKg0cfUxmcWmeZR51JmTua15psW4xZl5w/needYxxGBNxekUC/HS+Z3F4nn5xbR575HNWbr5o8XJBYuFySmAMeL+C6JqxdF5v8m9xYXFivGhxdwFlsWXBbmZ+zHeOc7FhumGefw578XFKe351jmOed9FrnnEWcFFxNGlMYOw+mEh6eN529nwxalFrkWBxYPF97mbeeVp2oWQJec588XMJY257CWURf7FtEX4JY+Fv0WsReIl1QnExerZwxmBhejR4kWtRcwxynNHZAAF+HHO2fzF2qIdEd7ZiAWe8YMFstHduZ4l8iXHub7F3CWaJat5pcXAJZHF1cXh0d+5j9pQjH9ObsW5RYlF3cXxef3F59nDxZ15lcWIOeu5/p0OxYrOa9mexe0l28Wb+b0liHm+Rcx5vTnsedp5+xpJSMglg7nUuYjFu8Wd+cXF+UXjxdbFkCX58ckl/Hn8MaslucWbJb/FjVnznC1Z5sWlJeMltcW+tPbG4XntxfHZ5EXBBbrFmUX/BZ8l+yWqeZPF6um+eZQJ9SX7ucslrCXUpbKFx9mNOf0lgiXlxYYl0cXYeYV5+HT4xgslrSWSpdN5nCX0pbwlyqWAJc+FoCW8+bbFw3mhLKhJ4qWKJdKlw4WOpbslhCXgheh5itm+hdYl1UXEYaRhtMWLGfLI4gWcxYih5IXSYYvFx/GnGZjJi/mj4bD57bmlZGWl+WlGhcMpoEXyKeC52CWKpZ8proWJpZ6FgUXvufFx+oX/+YKF06Wkme8FtqWvJbglrsmbpbolxCWQheYlvEWwhff5xGGOiY4l0YXCBb/5poxhfX758KHRieW57no1cbAFngARJb0FlpnoBYmxtgWoZZgp44myBbDF/YXe4d/F+8Wsuefh3yWXxcYl5Fm2BZnPJQ7UydxlrwXKBZRJ0aW5JeJl04nspfjF+onWBbuJ4MW2qdplh0W+mf4FqiXZJdsl0QWSZdZlvyXG+ZxF05nAZZVF4GWdCbeAaam6GcChkaLw3imFtaXWGZih1ankqc4ZifnUZf2lzzmAoYKhxyKF9kUZsBm6ZcoltKXPpauloaXMRaIl2qWJscVl1dTAeeOJ8UXeZY8lj6XwpaJl3kXbpf5Fk9nK2cll1/n8RZll9onpEbd5zUXwZY3h9iALUZhl/iXs0dW52zoUZZ4xsSWzUc6OC1GvxdnFp4X2paZl/8WFJe6l2KWnJbNRjcRbuaPgIqXmpeGl1qWBZYzloWX5JdJlr4XXxbtp3IxKWeWlDCW3Jd7Fn8XdJYil04GpeefFmuXyZckpuhci1U2l6NmWpclF8uWLZYqF8aXfpcml+6WaebNRzxIU5dwxgnmW5ZglwmXvJfJ5x8W0Oa7lnqXa5di52eWpJQHlzdmh5Z0l1EXK5aylr2WHJcu56eXLgDleGjnKJmLlxHnGeZSlsuXzZfdlleW5Ca6l+iWbZeUl3RRnUmvluVopxaSlpHmbxbClplnLZarl0WWyZdtlsKHOniuRveWRebTlmSWK5fblxsWqpcUloyW9WZml5MW2JcmpxaW6GcNJ56WKRazhg0WVqYRllBGTRZKAJpmdZagF8PmJsdwVgRmPBdDF02XdiYGZl0WhmesFp+XgFbHlmMWfRYnlu6XHJeQlzaHcFbM8BHmIAVMFhhXH5bKl9TmOFYCFvZnq5c3l3JmAZf9loGWxyasAH0mRhZ/5vmRBLO40XiWWGeJhjaXHGczTamH0qcoVg6XmuRVaIRXOYd8Z1ZniqbPJl0XPRcyl+WGfpetl7nme5fJZssdNFZellymXiasV6yX2FY6F+xXhKZkVkcXfZeb5wzm5pZ0JlIB5Zbtlg2XjBb1FpIW1Zc/pzWW1UnIV80W0ZaoVzaH7ZeiVsUWTZZdls2XxFY15uxWtxbcxxxWkJYel+yQolYiTVkXnZaKFx0Wl5bblj2WClZzxopX/pYll4JXW+aUVibmQ5ZiF2mmsacqFaDn8FcW5jRGY5cLFuOXixYTlxkW1afQmHpWAhlTlwBX05dHl3xXX5ezl9+WnFYgVzGnBab+5u7mheemVh+Xh5bYV8oX5lY7l7XnCJeWVz+W3ybWVsuUleb/lrZXlObEVxmXj5azlgJXUFb4VzGmHaeOVMxWu8fvl65WdldyV4QX8lYOVgyWjleKVi+WUAReVp+Y3lbdxq8XdpfelkeXn5a+lpKGKebAV7uWVlcuARb5XFXp56cWAFe2Vw+XqJbuVhZWHlZqlk5WCgVrpylGNlc0lu+WoJbgV1uWj5cQV5NmEVdkVpFXnIqJVxXmp00uVoaXpJcpV7FXqVa057hXvZfPlggXCgH1SI3nm5dCl2ZWYVZAVk+XuVbPl2XmAJHQV43HQlbCp++mu+fTF5qnCXTcVvpXYlapFthmNZfiZukWzRaOAFJXjFdyp5xM2qcqVwxWclduVzlWdscaVqaWSlbOxlVWSfEEZ+bGiqahV3ZXypckVslWCGchFmqWglZf5kJXA5bhh7BXYhbJFpn61VcJh9+mYoZpFjhnEla4Z0SWxldJFyfpqfoqVrJXS5a+V81W6lfeVrRnDJfxVuKXkVbkZhNXMlYwZg+XvFb2V44X01Y9VmKX/Re9V5UXZpb9VibnVFaVVuHms2cDjKOW8xcGV+VnhJZGVrTHE5fLFkE4cWjlZ/+WPledV75WoxdeFv5XkFZzlx5WbVdix1SW0WZFpzZXWVY5FkVWfFZLVpBW35b+l61WgVf/R6dXrhZaEJqX3VcXl7qnLpbdV+5XaVdzlp5WuJZgzMQR/+iuVwdXU1Zfl0dXV1cnl3hXJ1ebx+fH16fiZhVnrxcxVotXXVf2VraWopafFzNWP5ezVufHKcy30Ohpr1ddl6FWl1Z5F3FWT1YnVjdXKCeJdA7DXWdJVz2Xk1axVwWXOVc7lwDXjleA1/9H6pe3VpuX0VYHVyDWXVYkV39WaVdPlnKX/Jd55/qW31Yg1s1XbFejF0BWqNbZlmjXohBlViamJybBltRXDpeDJwelJhfbZhHGfnOpF4hWWEfcpfiwGyadVoxW9Zb4181Vj2pOljxXLFYT5mxXD1d/VsJmRKfLVrNW85celp7jHVEdlu0mLFdNVkaWmNZHV9CmHFbOFr1XyWZeu1mV3Fak1w9yvFaAV4tWYNcspizXPVZtl/VmbNf01uzWSKYc1m9XTNYbFjTW8VY816zXKtm2dRTX7Nb1V/zW1NeXVoLW4Nas15BmT4Ex8bzWItd81qLXSNaHV+sXbSc6F/xX4tY81zjWUxbCphEAIleaxlqne8S0V2xm4lc0FneGdVe1lvzWZNatF3iwytZbCY1Wk1eM1m5WAtey1tDWrVanlvlXJsbgFp2W2tcbJ6LXl5dhV7rXLNfy1+RXfVbaV9yGeNaVVyPnbRZhlwhWjRZIVhpmdBbq1o4ALRa252TWFtYZJu0X6FeyVxhWrqcsFt0XN+fT5mLWXNe5xrhWetafVhDWnEXZ0/IW6FcX5w7WOtYu1r0X4ieu1ibXllcrVpMXZVZrV1gAOibrV5Bm2BYyVmGW4ZfzFsTW9oaRl6Yn0of1V2TW0joZ6efmcZbViOEnmhZU1g4XOtfVZ8eGIRa01oDWdNbBJu4mrGZpllHXEBbL56pX3ieoFzLWMpeY15mW6ua+18CmOZb/5gYoFEPgFknWeBeKFqwB+ZbI1vJWadb+JjEX6daaV/XHcRYUV6WXzIZ0ASCQ4JAgATkARAATR4wACAGMAQ9yMhCcAeXWUAEchqABsAGkRgABlDom6FBZAAgAFgHdM1gBtQDCEFYAUADwADkBOACsAW2HOQEokPJAvgHCh6pBYZbkRu0zUADwABNHUAGIkK4G6sdjRvYJpMfCp84BNwj912drtNj91qbn5/D91zvmmmj91t3n6AAKAb3XY0bwVP3XVAHOATSQk9dnaycUk9bd5/fYk9fCV8EA1nAKAP3Xc9Z4AN7Y/dbll35HU9e91qbmS9e91hVWkdgL1urGFVYXFJPWGsbRaOPWPIc75/KQ/dYipzknZOViAEABhhfOAWpppMdM5wfWhp3712dqxpwqAaTHAdYD1kPXOiam5/PWp9c6Jm5n43Hr1r/nB9Zk5JfXqGfOAEZpLMZX16vWdgFnahtx69dMZnfW59ZRhnfW49YWl84A75WkxlRWb9cLcO/WbmdzOO/XZ2olcevXJyZ31yfXunpAAccmbmZM6cadYAEWAAgAzAAsAUKRqgBpkcEBYSdCAGDMgfQOpFUIW8VxiRI5+gDTR/knQAAax3BG6ACyUJqgRkbch+AAAACV5SfgAe2FugDwAPAB4AAAAdXtAMg34AGkRtlyaDe5AAABpAAAVMIQcJB9JqLGgkekxgAA/MIRpEeIAFGmwAE1pOaH4ABoANAAdQFoNxqYaDZ9JuaG5dZWASnWQACix1GHcEZ9JzXXwocYNy0zpEfqxqcnY4bdMiAAwAHgAS0znTL0AeAAfSf112qGOAHgADQ2tDanJqLG5EcwNrJQaAFwNgg2iDZINugAaDaoNrCAaDboN3EIGDZYNtg26AA4NhoALttwRmSIslFwN6RGCDYoDP8R4AGGF6g3yDdkRvFoyDYCNoI2dADll0I2ESHCNsIQ3IciN/A3ojdsAWI33mG8Nxd1kjZ0Adg2osbYs3BGZQG7a1QB4AGYNgAB5FEEwhAaN2GX3YGzh0w3ZDZdMgQXWAE4NjA3+EbCNiI2ojcyUGI24ja8NhI2Sjbd1so3Ajc4Nrg2QAF4NnQB+DaIAQQ3hDfGAUQ3xDckASQ3u5GkNzo35De6NxQ2GgGT1lQ26cfxkRY3NdZQAGkAvobWNyVBNjelAGg2UadV14qGnADgkPY3ODamrBw2nDeyNlw3hYeINvDAPDfiN2g36DfINpg3WDamN1I2jdctxjI2zCCyNnQAcjaGNggARjaKN8Y2kjcmN1gByjYONkI3+EawNnA3PjcIN7423Db+NsY2ATd8NoE3/DdBNzg3wldwR06R8DdDCAAANHXWYTfgAAABBNAB4TYKN/bRaABoN+OGOTYSNwE34AHuN50z4oaeNhQ3ODfSN/hH5jZkRgQ2hDf0N1Y2xDYkN6RGpDfINmQ2EJC6NsIRODcqN/o3MjcGNvI3hjYKN0Y2GAGKN5E2UjaUN5Q3+EdUN9Q3NDe0NsIRdDZQAfQ3DDeMNmABTDfMNmaGrDYtN2w2GgF2YyE2sDa1N/I3Cjf+NxI2zCFKN1E3pjfdN+w2NTahN702dTd9Nwk3/TfcNlE2QADRNnQBvgH9h6o36hAYAOo3Gje711gAWjZRBdo2lTbkN4U33TYpNsM2vTeyN3I2fTb1Ng02AzbjNhM3WAGLBXBHxTZAARY3ljelNq42NjflNrY3FTZ2Ngs3EzfVNu/W1DesNy02dAGtN202jDZaAB02zDfthyw2BzbdNnQB5+H9hqk3aTfpN9yGmTZZNmI32TZoATk2e4G8N3k3+TceN2iRuzdYAYyB/YYGN0s24TYRNv02JjaNNhoABAH9hhs2mzalNkQ3ZTbbNhU2OjeVN3Y3VTevN0M3pMZTNnND0zaaNnQBszbaNvgBXzfzNl43rzYxN6TGsTb4AZw3cTeMAH43SDfINzw39TZ5N4k34AGBNq83ZzdFN6TGTzZhNss3IzYrNpE2qzYwtw83ezbmNvg3JTZWN1s2bjbIAbY23zYPNkAAlKH9hqC2YLdcN343ELb9N3k30LbJNhoAwKneNli28TbYtyg2OLdQtri2gzbBNhi23jf4Rhc2cJDpNz43mTdZN4g24GE3N7k2iTZwkO42HjcFN/c2wLZ0AQQB/YcZNjomaTeON8i2iADONi424LckAcQ3gLfbN243Ozbot7S3WAABAJi3HDf4tuC38TfYt6M3OLdJNsS2osbPQY83NTdPN7U2FLYIt2g3Lze4tnS2sLZAAFM2kYj/NzM2QAEAtugBcza7NsC27TK9M7p6k9cH118wu9YD1zK26seD1tvWw9eUOurHI9bVcaPWd9er1jyGE9ZY273WbmYr1jyH09bn113nB9aqtjyGi9Y+CevW3IaL1pSg29bL11KHarc8h9n6k9dr1zfWf9bchxvWx9fqx84ASre91jvXarczNqyp69YH1kBHH9f715/Wx9fjhwfXe9en12NHDLmn1hfXNreX1m/WEXDX1ifXhrb717fXwQBytnYB99bj1w/WA9ZOcE/WE9fP1m5nCrev135Gqrfv135HlraiFwfW59b9JnfWcQCX1z/XeJX2tv/WA9aOtiyGKseshp434ACl1uCRfIbtMggBXdfgAFkB/obdMrYBcLXTFboAm+CAAAA="))
|
|
///////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////////////
|
|
/* Utility functions */
|
|
|
|
var storagePrefix = 'KiCad_HTML_BOM__' + pcbdata.metadata.title + '__' +
|
|
pcbdata.metadata.revision + '__#';
|
|
var storage;
|
|
|
|
function initStorage(key) {
|
|
try {
|
|
window.localStorage.getItem("blank");
|
|
storage = window.localStorage;
|
|
} catch (e) {
|
|
// localStorage not available
|
|
}
|
|
if (!storage) {
|
|
try {
|
|
window.sessionStorage.getItem("blank");
|
|
storage = window.sessionStorage;
|
|
} catch (e) {
|
|
// sessionStorage also not available
|
|
}
|
|
}
|
|
}
|
|
|
|
function readStorage(key) {
|
|
if (storage) {
|
|
return storage.getItem(storagePrefix + key);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function writeStorage(key, value) {
|
|
if (storage) {
|
|
storage.setItem(storagePrefix + key, value);
|
|
}
|
|
}
|
|
|
|
function fancyDblClickHandler(el, onsingle, ondouble) {
|
|
return function () {
|
|
if (el.getAttribute("data-dblclick") == null) {
|
|
el.setAttribute("data-dblclick", 1);
|
|
setTimeout(function () {
|
|
if (el.getAttribute("data-dblclick") == 1) {
|
|
onsingle();
|
|
}
|
|
el.removeAttribute("data-dblclick");
|
|
}, 200);
|
|
} else {
|
|
el.removeAttribute("data-dblclick");
|
|
ondouble();
|
|
}
|
|
}
|
|
}
|
|
|
|
function smoothScrollToRow(rowid) {
|
|
document.getElementById(rowid).scrollIntoView({
|
|
behavior: "smooth",
|
|
block: "center",
|
|
inline: "nearest"
|
|
});
|
|
}
|
|
|
|
function focusInputField(input) {
|
|
input.scrollIntoView(false);
|
|
input.focus();
|
|
input.select();
|
|
}
|
|
|
|
function saveBomTable(output) {
|
|
var text = '';
|
|
for (var node of bomhead.childNodes[0].childNodes) {
|
|
if (node.firstChild) {
|
|
var name = node.firstChild.nodeValue ?? "";
|
|
text += (output == 'csv' ? `"${name}"` : name);
|
|
}
|
|
if (node != bomhead.childNodes[0].lastChild) {
|
|
text += (output == 'csv' ? ',' : '\t');
|
|
}
|
|
}
|
|
text += '\n';
|
|
for (var row of bombody.childNodes) {
|
|
for (var cell of row.childNodes) {
|
|
let val = '';
|
|
for (var node of cell.childNodes) {
|
|
if (node.nodeName == "INPUT") {
|
|
if (node.checked) {
|
|
val += '✓';
|
|
}
|
|
} else if ((node.nodeName == "MARK") || (node.nodeName == "A")) {
|
|
val += node.firstChild.nodeValue;
|
|
} else {
|
|
val += node.nodeValue;
|
|
}
|
|
}
|
|
if (output == 'csv') {
|
|
val = val.replace(/\"/g, '\"\"'); // pair of double-quote characters
|
|
if (isNumeric(val)) {
|
|
val = +val; // use number
|
|
} else {
|
|
val = `"${val}"`; // enclosed within double-quote
|
|
}
|
|
}
|
|
text += val;
|
|
if (cell != row.lastChild) {
|
|
text += (output == 'csv' ? ',' : '\t');
|
|
}
|
|
}
|
|
text += '\n';
|
|
}
|
|
|
|
if (output != 'clipboard') {
|
|
// To file: csv or txt
|
|
var blob = new Blob([text], {
|
|
type: `text/${output}`
|
|
});
|
|
saveFile(`${pcbdata.metadata.title}.${output}`, blob);
|
|
} else {
|
|
// To clipboard
|
|
var textArea = document.createElement("textarea");
|
|
textArea.classList.add('clipboard-temp');
|
|
textArea.value = text;
|
|
|
|
document.body.appendChild(textArea);
|
|
textArea.focus();
|
|
textArea.select();
|
|
|
|
try {
|
|
if (document.execCommand('copy')) {
|
|
console.log('Bom copied to clipboard.');
|
|
}
|
|
} catch (err) {
|
|
console.log('Can not copy to clipboard.');
|
|
}
|
|
|
|
document.body.removeChild(textArea);
|
|
}
|
|
}
|
|
|
|
function isNumeric(str) {
|
|
/* https://stackoverflow.com/a/175787 */
|
|
return (typeof str != "string" ? false : !isNaN(str) && !isNaN(parseFloat(str)));
|
|
}
|
|
|
|
function removeGutterNode(node) {
|
|
for (var i = 0; i < node.childNodes.length; i++) {
|
|
if (node.childNodes[i].classList &&
|
|
node.childNodes[i].classList.contains("gutter")) {
|
|
node.removeChild(node.childNodes[i]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
function cleanGutters() {
|
|
removeGutterNode(document.getElementById("bot"));
|
|
removeGutterNode(document.getElementById("canvasdiv"));
|
|
}
|
|
|
|
var units = {
|
|
prefixes: {
|
|
giga: ["G", "g", "giga", "Giga", "GIGA"],
|
|
mega: ["M", "mega", "Mega", "MEGA"],
|
|
kilo: ["K", "k", "kilo", "Kilo", "KILO"],
|
|
milli: ["m", "milli", "Milli", "MILLI"],
|
|
micro: ["U", "u", "micro", "Micro", "MICRO", "μ", "µ"], // different utf8 μ
|
|
nano: ["N", "n", "nano", "Nano", "NANO"],
|
|
pico: ["P", "p", "pico", "Pico", "PICO"],
|
|
},
|
|
unitsShort: ["R", "r", "Ω", "F", "f", "H", "h"],
|
|
unitsLong: [
|
|
"OHM", "Ohm", "ohm", "ohms",
|
|
"FARAD", "Farad", "farad",
|
|
"HENRY", "Henry", "henry"
|
|
],
|
|
getMultiplier: function (s) {
|
|
if (this.prefixes.giga.includes(s)) return 1e9;
|
|
if (this.prefixes.mega.includes(s)) return 1e6;
|
|
if (this.prefixes.kilo.includes(s)) return 1e3;
|
|
if (this.prefixes.milli.includes(s)) return 1e-3;
|
|
if (this.prefixes.micro.includes(s)) return 1e-6;
|
|
if (this.prefixes.nano.includes(s)) return 1e-9;
|
|
if (this.prefixes.pico.includes(s)) return 1e-12;
|
|
return 1;
|
|
},
|
|
valueRegex: null,
|
|
valueAltRegex: null,
|
|
}
|
|
|
|
function initUtils() {
|
|
var allPrefixes = units.prefixes.giga
|
|
.concat(units.prefixes.mega)
|
|
.concat(units.prefixes.kilo)
|
|
.concat(units.prefixes.milli)
|
|
.concat(units.prefixes.micro)
|
|
.concat(units.prefixes.nano)
|
|
.concat(units.prefixes.pico);
|
|
var allUnits = units.unitsShort.concat(units.unitsLong);
|
|
units.valueRegex = new RegExp("^([0-9\.]+)" +
|
|
"\\s*(" + allPrefixes.join("|") + ")?" +
|
|
"(" + allUnits.join("|") + ")?" +
|
|
"(\\b.*)?$", "");
|
|
units.valueAltRegex = new RegExp("^([0-9]*)" +
|
|
"(" + units.unitsShort.join("|") + ")?" +
|
|
"([GgMmKkUuNnPp])?" +
|
|
"([0-9]*)" +
|
|
"(\\b.*)?$", "");
|
|
if (config.fields.includes("Value")) {
|
|
var index = config.fields.indexOf("Value");
|
|
pcbdata.bom["parsedValues"] = {};
|
|
var allList = getBomListByLayer('FB').flat();
|
|
for (var id in pcbdata.bom.fields) {
|
|
var ref_key = allList.find(item => item[1] == Number(id)) || [];
|
|
pcbdata.bom.parsedValues[id] = parseValue(pcbdata.bom.fields[id][index], ref_key[0] || '');
|
|
}
|
|
}
|
|
}
|
|
|
|
function parseValue(val, ref) {
|
|
var inferUnit = (unit, ref) => {
|
|
if (unit) {
|
|
unit = unit.toLowerCase();
|
|
if (unit == 'Ω' || unit == "ohm" || unit == "ohms") {
|
|
unit = 'r';
|
|
}
|
|
return unit[0];
|
|
}
|
|
|
|
var resarr = /^([a-z]+)\d+$/i.exec(ref);
|
|
switch (Array.isArray(resarr) && resarr[1].toLowerCase()) {
|
|
case "c": return 'f';
|
|
case "l": return 'h';
|
|
case "r":
|
|
case "rv": return 'r';
|
|
}
|
|
return null;
|
|
};
|
|
val = val.replace(/,/g, "");
|
|
var match = units.valueRegex.exec(val);
|
|
if (Array.isArray(match)) {
|
|
var unit = inferUnit(match[3], ref);
|
|
var val_i = parseFloat(match[1]);
|
|
if (!unit) return null;
|
|
if (match[2]) {
|
|
val_i = val_i * units.getMultiplier(match[2]);
|
|
}
|
|
return {
|
|
val: val_i,
|
|
unit: unit,
|
|
extra: match[4],
|
|
}
|
|
}
|
|
|
|
match = units.valueAltRegex.exec(val);
|
|
if (Array.isArray(match) && (match[1] || match[4])) {
|
|
var unit = inferUnit(match[2], ref);
|
|
var val_i = parseFloat(match[1] + "." + match[4]);
|
|
if (!unit) return null;
|
|
if (match[3]) {
|
|
val_i = val_i * units.getMultiplier(match[3]);
|
|
}
|
|
return {
|
|
val: val_i,
|
|
unit: unit,
|
|
extra: match[5],
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function valueCompare(a, b, stra, strb) {
|
|
if (a === null && b === null) {
|
|
// Failed to parse both values, compare them as strings.
|
|
if (stra != strb) return stra > strb ? 1 : -1;
|
|
else return 0;
|
|
} else if (a === null) {
|
|
return 1;
|
|
} else if (b === null) {
|
|
return -1;
|
|
} else {
|
|
if (a.unit != b.unit) return a.unit > b.unit ? 1 : -1;
|
|
else if (a.val != b.val) return a.val > b.val ? 1 : -1;
|
|
else if (a.extra != b.extra) return a.extra > b.extra ? 1 : -1;
|
|
else return 0;
|
|
}
|
|
}
|
|
|
|
function validateSaveImgDimension(element) {
|
|
var valid = false;
|
|
var intValue = 0;
|
|
if (/^[1-9]\d*$/.test(element.value)) {
|
|
intValue = parseInt(element.value);
|
|
if (intValue <= 16000) {
|
|
valid = true;
|
|
}
|
|
}
|
|
if (valid) {
|
|
element.classList.remove("invalid");
|
|
} else {
|
|
element.classList.add("invalid");
|
|
}
|
|
return intValue;
|
|
}
|
|
|
|
function saveImage(layer) {
|
|
var width = validateSaveImgDimension(document.getElementById("render-save-width"));
|
|
var height = validateSaveImgDimension(document.getElementById("render-save-height"));
|
|
var bgcolor = null;
|
|
if (!document.getElementById("render-save-transparent").checked) {
|
|
var style = getComputedStyle(topmostdiv);
|
|
bgcolor = style.getPropertyValue("background-color");
|
|
}
|
|
if (!width || !height) return;
|
|
|
|
// Prepare image
|
|
var canvas = document.createElement("canvas");
|
|
var layerdict = {
|
|
transform: {
|
|
x: 0,
|
|
y: 0,
|
|
s: 1,
|
|
panx: 0,
|
|
pany: 0,
|
|
zoom: 1,
|
|
},
|
|
bg: canvas,
|
|
fab: canvas,
|
|
silk: canvas,
|
|
highlight: canvas,
|
|
layer: layer,
|
|
}
|
|
// Do the rendering
|
|
recalcLayerScale(layerdict, width, height);
|
|
prepareLayer(layerdict);
|
|
clearCanvas(canvas, bgcolor);
|
|
drawBackground(layerdict, false);
|
|
drawHighlightsOnLayer(layerdict, false);
|
|
|
|
// Save image
|
|
var imgdata = canvas.toDataURL("image/png");
|
|
|
|
var filename = pcbdata.metadata.title;
|
|
if (pcbdata.metadata.revision) {
|
|
filename += `.${pcbdata.metadata.revision}`;
|
|
}
|
|
filename += `.${layer}.png`;
|
|
saveFile(filename, dataURLtoBlob(imgdata));
|
|
}
|
|
|
|
function saveSettings() {
|
|
var data = {
|
|
type: "InteractiveHtmlBom settings",
|
|
version: 1,
|
|
pcbmetadata: pcbdata.metadata,
|
|
settings: settings,
|
|
}
|
|
var blob = new Blob([JSON.stringify(data, null, 4)], {
|
|
type: "application/json"
|
|
});
|
|
saveFile(`${pcbdata.metadata.title}.settings.json`, blob);
|
|
}
|
|
|
|
function loadSettings() {
|
|
var input = document.createElement("input");
|
|
input.type = "file";
|
|
input.accept = ".settings.json";
|
|
input.onchange = function (e) {
|
|
var file = e.target.files[0];
|
|
var reader = new FileReader();
|
|
reader.onload = readerEvent => {
|
|
var content = readerEvent.target.result;
|
|
var newSettings;
|
|
try {
|
|
newSettings = JSON.parse(content);
|
|
} catch (e) {
|
|
alert("Selected file is not InteractiveHtmlBom settings file.");
|
|
return;
|
|
}
|
|
if (newSettings.type != "InteractiveHtmlBom settings") {
|
|
alert("Selected file is not InteractiveHtmlBom settings file.");
|
|
return;
|
|
}
|
|
var metadataMatches = newSettings.hasOwnProperty("pcbmetadata");
|
|
if (metadataMatches) {
|
|
for (var k in pcbdata.metadata) {
|
|
if (!newSettings.pcbmetadata.hasOwnProperty(k) || newSettings.pcbmetadata[k] != pcbdata.metadata[k]) {
|
|
metadataMatches = false;
|
|
}
|
|
}
|
|
}
|
|
if (!metadataMatches) {
|
|
var currentMetadata = JSON.stringify(pcbdata.metadata, null, 4);
|
|
var fileMetadata = JSON.stringify(newSettings.pcbmetadata, null, 4);
|
|
if (!confirm(
|
|
`Settins file metadata does not match current metadata.\n\n` +
|
|
`Page metadata:\n${currentMetadata}\n\n` +
|
|
`Settings file metadata:\n${fileMetadata}\n\n` +
|
|
`Press OK if you would like to import settings anyway.`)) {
|
|
return;
|
|
}
|
|
}
|
|
overwriteSettings(newSettings.settings);
|
|
}
|
|
reader.readAsText(file, 'UTF-8');
|
|
}
|
|
input.click();
|
|
}
|
|
|
|
function resetSettings() {
|
|
if (!confirm(
|
|
`This will reset all checkbox states and other settings.\n\n` +
|
|
`Press OK if you want to continue.`)) {
|
|
return;
|
|
}
|
|
if (storage) {
|
|
var keys = [];
|
|
for (var i = 0; i < storage.length; i++) {
|
|
var key = storage.key(i);
|
|
if (key.startsWith(storagePrefix)) keys.push(key);
|
|
}
|
|
for (var key of keys) storage.removeItem(key);
|
|
}
|
|
location.reload();
|
|
}
|
|
|
|
function overwriteSettings(newSettings) {
|
|
initDone = false;
|
|
Object.assign(settings, newSettings);
|
|
writeStorage("bomlayout", settings.bomlayout);
|
|
writeStorage("bommode", settings.bommode);
|
|
writeStorage("canvaslayout", settings.canvaslayout);
|
|
writeStorage("bomCheckboxes", settings.checkboxes.join(","));
|
|
document.getElementById("bomCheckboxes").value = settings.checkboxes.join(",");
|
|
for (var checkbox of settings.checkboxes) {
|
|
writeStorage("checkbox_" + checkbox, settings.checkboxStoredRefs[checkbox]);
|
|
}
|
|
writeStorage("markWhenChecked", settings.markWhenChecked);
|
|
padsVisible(settings.renderPads);
|
|
document.getElementById("padsCheckbox").checked = settings.renderPads;
|
|
fabricationVisible(settings.renderFabrication);
|
|
document.getElementById("fabricationCheckbox").checked = settings.renderFabrication;
|
|
silkscreenVisible(settings.renderSilkscreen);
|
|
document.getElementById("silkscreenCheckbox").checked = settings.renderSilkscreen;
|
|
referencesVisible(settings.renderReferences);
|
|
document.getElementById("referencesCheckbox").checked = settings.renderReferences;
|
|
valuesVisible(settings.renderValues);
|
|
document.getElementById("valuesCheckbox").checked = settings.renderValues;
|
|
tracksVisible(settings.renderTracks);
|
|
document.getElementById("tracksCheckbox").checked = settings.renderTracks;
|
|
zonesVisible(settings.renderZones);
|
|
document.getElementById("zonesCheckbox").checked = settings.renderZones;
|
|
dnpOutline(settings.renderDnpOutline);
|
|
document.getElementById("dnpOutlineCheckbox").checked = settings.renderDnpOutline;
|
|
setRedrawOnDrag(settings.redrawOnDrag);
|
|
document.getElementById("dragCheckbox").checked = settings.redrawOnDrag;
|
|
setHighlightRowOnClick(settings.highlightRowOnClick);
|
|
document.getElementById("highlightRowOnClickCheckbox").checked = settings.highlightRowOnClick;
|
|
setDarkMode(settings.darkMode);
|
|
document.getElementById("darkmodeCheckbox").checked = settings.darkMode;
|
|
setHighlightPin1(settings.highlightpin1);
|
|
document.forms.highlightpin1.highlightpin1.value = settings.highlightpin1;
|
|
writeStorage("boardRotation", settings.boardRotation);
|
|
document.getElementById("boardRotation").value = settings.boardRotation / 5;
|
|
document.getElementById("rotationDegree").textContent = settings.boardRotation;
|
|
setOffsetBackRotation(settings.offsetBackRotation);
|
|
document.getElementById("offsetBackRotationCheckbox").checked = settings.offsetBackRotation;
|
|
initDone = true;
|
|
prepCheckboxes();
|
|
changeBomLayout(settings.bomlayout);
|
|
}
|
|
|
|
function saveFile(filename, blob) {
|
|
var link = document.createElement("a");
|
|
var objurl = URL.createObjectURL(blob);
|
|
link.download = filename;
|
|
link.href = objurl;
|
|
link.click();
|
|
}
|
|
|
|
function dataURLtoBlob(dataurl) {
|
|
var arr = dataurl.split(','),
|
|
mime = arr[0].match(/:(.*?);/)[1],
|
|
bstr = atob(arr[1]),
|
|
n = bstr.length,
|
|
u8arr = new Uint8Array(n);
|
|
while (n--) {
|
|
u8arr[n] = bstr.charCodeAt(n);
|
|
}
|
|
return new Blob([u8arr], {
|
|
type: mime
|
|
});
|
|
}
|
|
|
|
var settings = {
|
|
canvaslayout: "FB",
|
|
bomlayout: "left-right",
|
|
bommode: "grouped",
|
|
checkboxes: [],
|
|
checkboxStoredRefs: {},
|
|
darkMode: false,
|
|
highlightpin1: "none",
|
|
redrawOnDrag: true,
|
|
boardRotation: 0,
|
|
offsetBackRotation: false,
|
|
renderPads: true,
|
|
renderReferences: true,
|
|
renderValues: true,
|
|
renderSilkscreen: true,
|
|
renderFabrication: true,
|
|
renderDnpOutline: false,
|
|
renderTracks: true,
|
|
renderZones: true,
|
|
columnOrder: [],
|
|
hiddenColumns: [],
|
|
netColors: {},
|
|
}
|
|
|
|
function initDefaults() {
|
|
settings.bomlayout = readStorage("bomlayout");
|
|
if (settings.bomlayout === null) {
|
|
settings.bomlayout = config.bom_view;
|
|
}
|
|
if (!['bom-only', 'left-right', 'top-bottom'].includes(settings.bomlayout)) {
|
|
settings.bomlayout = config.bom_view;
|
|
}
|
|
settings.bommode = readStorage("bommode");
|
|
if (settings.bommode === null) {
|
|
settings.bommode = "grouped";
|
|
}
|
|
if (settings.bommode == "netlist" && !pcbdata.nets) {
|
|
settings.bommode = "grouped";
|
|
}
|
|
if (!["grouped", "ungrouped", "netlist"].includes(settings.bommode)) {
|
|
settings.bommode = "grouped";
|
|
}
|
|
settings.canvaslayout = readStorage("canvaslayout");
|
|
if (settings.canvaslayout === null) {
|
|
settings.canvaslayout = config.layer_view;
|
|
}
|
|
var bomCheckboxes = readStorage("bomCheckboxes");
|
|
if (bomCheckboxes === null) {
|
|
bomCheckboxes = config.checkboxes;
|
|
}
|
|
settings.checkboxes = bomCheckboxes.split(",").filter((e) => e);
|
|
document.getElementById("bomCheckboxes").value = bomCheckboxes;
|
|
|
|
var highlightpin1 = readStorage("highlightpin1") || config.highlight_pin1;
|
|
if (highlightpin1 === "false") highlightpin1 = "none";
|
|
if (highlightpin1 === "true") highlightpin1 = "all";
|
|
setHighlightPin1(highlightpin1);
|
|
document.forms.highlightpin1.highlightpin1.value = highlightpin1;
|
|
|
|
settings.markWhenChecked = readStorage("markWhenChecked") || "";
|
|
populateMarkWhenCheckedOptions();
|
|
|
|
function initBooleanSetting(storageString, def, elementId, func) {
|
|
var b = readStorage(storageString);
|
|
if (b === null) {
|
|
b = def;
|
|
} else {
|
|
b = (b == "true");
|
|
}
|
|
document.getElementById(elementId).checked = b;
|
|
func(b);
|
|
}
|
|
|
|
initBooleanSetting("padsVisible", config.show_pads, "padsCheckbox", padsVisible);
|
|
initBooleanSetting("fabricationVisible", config.show_fabrication, "fabricationCheckbox", fabricationVisible);
|
|
initBooleanSetting("silkscreenVisible", config.show_silkscreen, "silkscreenCheckbox", silkscreenVisible);
|
|
initBooleanSetting("referencesVisible", true, "referencesCheckbox", referencesVisible);
|
|
initBooleanSetting("valuesVisible", true, "valuesCheckbox", valuesVisible);
|
|
if ("tracks" in pcbdata) {
|
|
initBooleanSetting("tracksVisible", true, "tracksCheckbox", tracksVisible);
|
|
initBooleanSetting("zonesVisible", true, "zonesCheckbox", zonesVisible);
|
|
} else {
|
|
document.getElementById("tracksAndZonesCheckboxes").style.display = "none";
|
|
tracksVisible(false);
|
|
zonesVisible(false);
|
|
}
|
|
initBooleanSetting("dnpOutline", false, "dnpOutlineCheckbox", dnpOutline);
|
|
initBooleanSetting("redrawOnDrag", config.redraw_on_drag, "dragCheckbox", setRedrawOnDrag);
|
|
initBooleanSetting("highlightRowOnClick", false, "highlightRowOnClickCheckbox", setHighlightRowOnClick);
|
|
initBooleanSetting("darkmode", config.dark_mode, "darkmodeCheckbox", setDarkMode);
|
|
|
|
var fields = ["checkboxes", "References"].concat(config.fields).concat(["Quantity"]);
|
|
var hcols = JSON.parse(readStorage("hiddenColumns"));
|
|
if (hcols === null) {
|
|
hcols = [];
|
|
}
|
|
settings.hiddenColumns = hcols.filter(e => fields.includes(e));
|
|
|
|
var cord = JSON.parse(readStorage("columnOrder"));
|
|
if (cord === null) {
|
|
cord = fields;
|
|
} else {
|
|
cord = cord.filter(e => fields.includes(e));
|
|
if (cord.length != fields.length)
|
|
cord = fields;
|
|
}
|
|
settings.columnOrder = cord;
|
|
|
|
settings.boardRotation = readStorage("boardRotation");
|
|
if (settings.boardRotation === null) {
|
|
settings.boardRotation = config.board_rotation * 5;
|
|
} else {
|
|
settings.boardRotation = parseInt(settings.boardRotation);
|
|
}
|
|
document.getElementById("boardRotation").value = settings.boardRotation / 5;
|
|
document.getElementById("rotationDegree").textContent = settings.boardRotation;
|
|
initBooleanSetting("offsetBackRotation", config.offset_back_rotation, "offsetBackRotationCheckbox", setOffsetBackRotation);
|
|
|
|
settings.netColors = JSON.parse(readStorage("netColors")) || {};
|
|
}
|
|
|
|
// Helper classes for user js callbacks.
|
|
|
|
const IBOM_EVENT_TYPES = {
|
|
ALL: "all",
|
|
HIGHLIGHT_EVENT: "highlightEvent",
|
|
CHECKBOX_CHANGE_EVENT: "checkboxChangeEvent",
|
|
BOM_BODY_CHANGE_EVENT: "bomBodyChangeEvent",
|
|
}
|
|
|
|
const EventHandler = {
|
|
callbacks: {},
|
|
init: function () {
|
|
for (eventType of Object.values(IBOM_EVENT_TYPES))
|
|
this.callbacks[eventType] = [];
|
|
},
|
|
registerCallback: function (eventType, callback) {
|
|
this.callbacks[eventType].push(callback);
|
|
},
|
|
emitEvent: function (eventType, eventArgs) {
|
|
event = {
|
|
eventType: eventType,
|
|
args: eventArgs,
|
|
}
|
|
var callback;
|
|
for (callback of this.callbacks[eventType])
|
|
callback(event);
|
|
for (callback of this.callbacks[IBOM_EVENT_TYPES.ALL])
|
|
callback(event);
|
|
}
|
|
}
|
|
EventHandler.init();
|
|
|
|
///////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////////////
|
|
/* PCB rendering code */
|
|
|
|
var emptyContext2d = document.createElement("canvas").getContext("2d");
|
|
|
|
function deg2rad(deg) {
|
|
return deg * Math.PI / 180;
|
|
}
|
|
|
|
function calcFontPoint(linepoint, text, offsetx, offsety, tilt) {
|
|
var point = [
|
|
linepoint[0] * text.width + offsetx,
|
|
linepoint[1] * text.height + offsety
|
|
];
|
|
// This approximates pcbnew behavior with how text tilts depending on horizontal justification
|
|
point[0] -= (linepoint[1] + 0.5 * (1 + text.justify[0])) * text.height * tilt;
|
|
return point;
|
|
}
|
|
|
|
function drawText(ctx, text, color) {
|
|
if ("ref" in text && !settings.renderReferences) return;
|
|
if ("val" in text && !settings.renderValues) return;
|
|
ctx.save();
|
|
ctx.fillStyle = color;
|
|
ctx.strokeStyle = color;
|
|
ctx.lineCap = "round";
|
|
ctx.lineJoin = "round";
|
|
ctx.lineWidth = text.thickness;
|
|
if ("svgpath" in text) {
|
|
ctx.stroke(new Path2D(text.svgpath));
|
|
ctx.restore();
|
|
return;
|
|
}
|
|
if ("polygons" in text) {
|
|
ctx.fill(getPolygonsPath(text));
|
|
ctx.restore();
|
|
return;
|
|
}
|
|
ctx.translate(...text.pos);
|
|
ctx.translate(text.thickness * 0.5, 0);
|
|
var angle = -text.angle;
|
|
if (text.attr.includes("mirrored")) {
|
|
ctx.scale(-1, 1);
|
|
angle = -angle;
|
|
}
|
|
var tilt = 0;
|
|
if (text.attr.includes("italic")) {
|
|
tilt = 0.125;
|
|
}
|
|
var interline = text.height * 1.5 + text.thickness;
|
|
var txt = text.text.split("\n");
|
|
// KiCad ignores last empty line.
|
|
if (txt[txt.length - 1] == '') txt.pop();
|
|
ctx.rotate(deg2rad(angle));
|
|
var offsety = (1 - text.justify[1]) / 2 * text.height; // One line offset
|
|
offsety -= (txt.length - 1) * (text.justify[1] + 1) / 2 * interline; // Multiline offset
|
|
for (var i in txt) {
|
|
var lineWidth = text.thickness + interline / 2 * tilt;
|
|
for (var j = 0; j < txt[i].length; j++) {
|
|
if (txt[i][j] == '\t') {
|
|
var fourSpaces = 4 * pcbdata.font_data[' '].w * text.width;
|
|
lineWidth += fourSpaces - lineWidth % fourSpaces;
|
|
} else {
|
|
if (txt[i][j] == '~') {
|
|
j++;
|
|
if (j == txt[i].length)
|
|
break;
|
|
}
|
|
lineWidth += pcbdata.font_data[txt[i][j]].w * text.width;
|
|
}
|
|
}
|
|
var offsetx = -lineWidth * (text.justify[0] + 1) / 2;
|
|
var inOverbar = false;
|
|
for (var j = 0; j < txt[i].length; j++) {
|
|
if (config.kicad_text_formatting) {
|
|
if (txt[i][j] == '\t') {
|
|
var fourSpaces = 4 * pcbdata.font_data[' '].w * text.width;
|
|
offsetx += fourSpaces - offsetx % fourSpaces;
|
|
continue;
|
|
} else if (txt[i][j] == '~') {
|
|
j++;
|
|
if (j == txt[i].length)
|
|
break;
|
|
if (txt[i][j] != '~') {
|
|
inOverbar = !inOverbar;
|
|
}
|
|
}
|
|
}
|
|
var glyph = pcbdata.font_data[txt[i][j]];
|
|
if (inOverbar) {
|
|
var overbarStart = [offsetx, -text.height * 1.4 + offsety];
|
|
var overbarEnd = [offsetx + text.width * glyph.w, overbarStart[1]];
|
|
|
|
if (!lastHadOverbar) {
|
|
overbarStart[0] += text.height * 1.4 * tilt;
|
|
lastHadOverbar = true;
|
|
}
|
|
ctx.beginPath();
|
|
ctx.moveTo(...overbarStart);
|
|
ctx.lineTo(...overbarEnd);
|
|
ctx.stroke();
|
|
} else {
|
|
lastHadOverbar = false;
|
|
}
|
|
for (var line of glyph.l) {
|
|
ctx.beginPath();
|
|
ctx.moveTo(...calcFontPoint(line[0], text, offsetx, offsety, tilt));
|
|
for (var k = 1; k < line.length; k++) {
|
|
ctx.lineTo(...calcFontPoint(line[k], text, offsetx, offsety, tilt));
|
|
}
|
|
ctx.stroke();
|
|
}
|
|
offsetx += glyph.w * text.width;
|
|
}
|
|
offsety += interline;
|
|
}
|
|
ctx.restore();
|
|
}
|
|
|
|
function drawedge(ctx, scalefactor, edge, color) {
|
|
ctx.strokeStyle = color;
|
|
ctx.fillStyle = color;
|
|
ctx.lineWidth = Math.max(1 / scalefactor, edge.width);
|
|
ctx.lineCap = "round";
|
|
ctx.lineJoin = "round";
|
|
if ("svgpath" in edge) {
|
|
ctx.stroke(new Path2D(edge.svgpath));
|
|
} else {
|
|
ctx.beginPath();
|
|
if (edge.type == "segment") {
|
|
ctx.moveTo(...edge.start);
|
|
ctx.lineTo(...edge.end);
|
|
}
|
|
if (edge.type == "rect") {
|
|
ctx.moveTo(...edge.start);
|
|
ctx.lineTo(edge.start[0], edge.end[1]);
|
|
ctx.lineTo(...edge.end);
|
|
ctx.lineTo(edge.end[0], edge.start[1]);
|
|
ctx.lineTo(...edge.start);
|
|
}
|
|
if (edge.type == "arc") {
|
|
ctx.arc(
|
|
...edge.start,
|
|
edge.radius,
|
|
deg2rad(edge.startangle),
|
|
deg2rad(edge.endangle));
|
|
}
|
|
if (edge.type == "circle") {
|
|
ctx.arc(
|
|
...edge.start,
|
|
edge.radius,
|
|
0, 2 * Math.PI);
|
|
ctx.closePath();
|
|
}
|
|
if (edge.type == "curve") {
|
|
ctx.moveTo(...edge.start);
|
|
ctx.bezierCurveTo(...edge.cpa, ...edge.cpb, ...edge.end);
|
|
}
|
|
if("filled" in edge && edge.filled)
|
|
ctx.fill();
|
|
else
|
|
ctx.stroke();
|
|
}
|
|
}
|
|
|
|
function getChamferedRectPath(size, radius, chamfpos, chamfratio) {
|
|
// chamfpos is a bitmask, left = 1, right = 2, bottom left = 4, bottom right = 8
|
|
var path = new Path2D();
|
|
var width = size[0];
|
|
var height = size[1];
|
|
var x = width * -0.5;
|
|
var y = height * -0.5;
|
|
var chamfOffset = Math.min(width, height) * chamfratio;
|
|
path.moveTo(x, 0);
|
|
if (chamfpos & 4) {
|
|
path.lineTo(x, y + height - chamfOffset);
|
|
path.lineTo(x + chamfOffset, y + height);
|
|
path.lineTo(0, y + height);
|
|
} else {
|
|
path.arcTo(x, y + height, x + width, y + height, radius);
|
|
}
|
|
if (chamfpos & 8) {
|
|
path.lineTo(x + width - chamfOffset, y + height);
|
|
path.lineTo(x + width, y + height - chamfOffset);
|
|
path.lineTo(x + width, 0);
|
|
} else {
|
|
path.arcTo(x + width, y + height, x + width, y, radius);
|
|
}
|
|
if (chamfpos & 2) {
|
|
path.lineTo(x + width, y + chamfOffset);
|
|
path.lineTo(x + width - chamfOffset, y);
|
|
path.lineTo(0, y);
|
|
} else {
|
|
path.arcTo(x + width, y, x, y, radius);
|
|
}
|
|
if (chamfpos & 1) {
|
|
path.lineTo(x + chamfOffset, y);
|
|
path.lineTo(x, y + chamfOffset);
|
|
path.lineTo(x, 0);
|
|
} else {
|
|
path.arcTo(x, y, x, y + height, radius);
|
|
}
|
|
path.closePath();
|
|
return path;
|
|
}
|
|
|
|
function getOblongPath(size) {
|
|
return getChamferedRectPath(size, Math.min(size[0], size[1]) / 2, 0, 0);
|
|
}
|
|
|
|
function getPolygonsPath(shape) {
|
|
if (shape.path2d) {
|
|
return shape.path2d;
|
|
}
|
|
if ("svgpath" in shape) {
|
|
shape.path2d = new Path2D(shape.svgpath);
|
|
} else {
|
|
var path = new Path2D();
|
|
for (var polygon of shape.polygons) {
|
|
path.moveTo(...polygon[0]);
|
|
for (var i = 1; i < polygon.length; i++) {
|
|
path.lineTo(...polygon[i]);
|
|
}
|
|
path.closePath();
|
|
}
|
|
shape.path2d = path;
|
|
}
|
|
return shape.path2d;
|
|
}
|
|
|
|
function drawPolygonShape(ctx, scalefactor, shape, color) {
|
|
ctx.save();
|
|
if (!("svgpath" in shape)) {
|
|
ctx.translate(...shape.pos);
|
|
ctx.rotate(deg2rad(-shape.angle));
|
|
}
|
|
if("filled" in shape && !shape.filled) {
|
|
ctx.strokeStyle = color;
|
|
ctx.lineWidth = Math.max(1 / scalefactor, shape.width);
|
|
ctx.lineCap = "round";
|
|
ctx.lineJoin = "round";
|
|
ctx.stroke(getPolygonsPath(shape));
|
|
} else {
|
|
ctx.fillStyle = color;
|
|
ctx.fill(getPolygonsPath(shape));
|
|
}
|
|
ctx.restore();
|
|
}
|
|
|
|
function drawDrawing(ctx, scalefactor, drawing, color) {
|
|
if (["segment", "arc", "circle", "curve", "rect"].includes(drawing.type)) {
|
|
drawedge(ctx, scalefactor, drawing, color);
|
|
} else if (drawing.type == "polygon") {
|
|
drawPolygonShape(ctx, scalefactor, drawing, color);
|
|
} else {
|
|
drawText(ctx, drawing, color);
|
|
}
|
|
}
|
|
|
|
function getCirclePath(radius) {
|
|
var path = new Path2D();
|
|
path.arc(0, 0, radius, 0, 2 * Math.PI);
|
|
path.closePath();
|
|
return path;
|
|
}
|
|
|
|
function getCachedPadPath(pad) {
|
|
if (!pad.path2d) {
|
|
// if path2d is not set, build one and cache it on pad object
|
|
if (pad.shape == "rect") {
|
|
pad.path2d = new Path2D();
|
|
pad.path2d.rect(...pad.size.map(c => -c * 0.5), ...pad.size);
|
|
} else if (pad.shape == "oval") {
|
|
pad.path2d = getOblongPath(pad.size);
|
|
} else if (pad.shape == "circle") {
|
|
pad.path2d = getCirclePath(pad.size[0] / 2);
|
|
} else if (pad.shape == "roundrect") {
|
|
pad.path2d = getChamferedRectPath(pad.size, pad.radius, 0, 0);
|
|
} else if (pad.shape == "chamfrect") {
|
|
pad.path2d = getChamferedRectPath(pad.size, pad.radius, pad.chamfpos, pad.chamfratio)
|
|
} else if (pad.shape == "custom") {
|
|
pad.path2d = getPolygonsPath(pad);
|
|
}
|
|
}
|
|
return pad.path2d;
|
|
}
|
|
|
|
function drawPad(ctx, pad, color, outline) {
|
|
ctx.save();
|
|
ctx.translate(...pad.pos);
|
|
ctx.rotate(-deg2rad(pad.angle));
|
|
if (pad.offset) {
|
|
ctx.translate(...pad.offset);
|
|
}
|
|
ctx.fillStyle = color;
|
|
ctx.strokeStyle = color;
|
|
var path = getCachedPadPath(pad);
|
|
if (outline) {
|
|
ctx.stroke(path);
|
|
} else {
|
|
ctx.fill(path);
|
|
}
|
|
ctx.restore();
|
|
}
|
|
|
|
function drawPadHole(ctx, pad, padHoleColor) {
|
|
if (pad.type != "th") return;
|
|
ctx.save();
|
|
ctx.translate(...pad.pos);
|
|
ctx.rotate(-deg2rad(pad.angle));
|
|
ctx.fillStyle = padHoleColor;
|
|
if (pad.drillshape == "oblong") {
|
|
ctx.fill(getOblongPath(pad.drillsize));
|
|
} else if (pad.drillshape == "rect") {
|
|
ctx.fill(getChamferedRectPath(pad.drillsize, 0, 0, 0));
|
|
} else {
|
|
ctx.fill(getCirclePath(pad.drillsize[0] / 2));
|
|
}
|
|
ctx.restore();
|
|
}
|
|
|
|
function drawFootprint(ctx, layer, scalefactor, footprint, colors, highlight, outline) {
|
|
if (highlight) {
|
|
// draw bounding box
|
|
if (footprint.layer == layer) {
|
|
ctx.save();
|
|
ctx.globalAlpha = 0.2;
|
|
ctx.translate(...footprint.bbox.pos);
|
|
ctx.rotate(deg2rad(-footprint.bbox.angle));
|
|
ctx.translate(...footprint.bbox.relpos);
|
|
ctx.fillStyle = colors.pad;
|
|
ctx.fillRect(0, 0, ...footprint.bbox.size);
|
|
ctx.globalAlpha = 1;
|
|
ctx.strokeStyle = colors.pad;
|
|
ctx.lineWidth = 3 / scalefactor;
|
|
ctx.strokeRect(0, 0, ...footprint.bbox.size);
|
|
ctx.restore();
|
|
}
|
|
}
|
|
// draw drawings
|
|
for (var drawing of footprint.drawings) {
|
|
if (drawing.layer == layer) {
|
|
drawDrawing(ctx, scalefactor, drawing.drawing, colors.pad);
|
|
}
|
|
}
|
|
ctx.lineWidth = 3 / scalefactor;
|
|
// draw pads
|
|
if (settings.renderPads) {
|
|
for (var pad of footprint.pads) {
|
|
if (pad.layers.includes(layer)) {
|
|
drawPad(ctx, pad, colors.pad, outline);
|
|
if (pad.pin1 &&
|
|
(settings.highlightpin1 == "all" ||
|
|
settings.highlightpin1 == "selected" && highlight)) {
|
|
drawPad(ctx, pad, colors.outline, true);
|
|
}
|
|
}
|
|
}
|
|
for (var pad of footprint.pads) {
|
|
drawPadHole(ctx, pad, colors.padHole);
|
|
}
|
|
}
|
|
}
|
|
|
|
function drawEdgeCuts(canvas, scalefactor) {
|
|
var ctx = canvas.getContext("2d");
|
|
var edgecolor = getComputedStyle(topmostdiv).getPropertyValue('--pcb-edge-color');
|
|
for (var edge of pcbdata.edges) {
|
|
drawDrawing(ctx, scalefactor, edge, edgecolor);
|
|
}
|
|
}
|
|
|
|
function drawFootprints(canvas, layer, scalefactor, highlight) {
|
|
var ctx = canvas.getContext("2d");
|
|
ctx.lineWidth = 3 / scalefactor;
|
|
var style = getComputedStyle(topmostdiv);
|
|
|
|
var colors = {
|
|
pad: style.getPropertyValue('--pad-color'),
|
|
padHole: style.getPropertyValue('--pad-hole-color'),
|
|
outline: style.getPropertyValue('--pin1-outline-color'),
|
|
}
|
|
|
|
for (var i = 0; i < pcbdata.footprints.length; i++) {
|
|
var mod = pcbdata.footprints[i];
|
|
var outline = settings.renderDnpOutline && pcbdata.bom.skipped.includes(i);
|
|
var h = highlightedFootprints.includes(i);
|
|
var d = markedFootprints.has(i);
|
|
if (highlight) {
|
|
if(h && d) {
|
|
colors.pad = style.getPropertyValue('--pad-color-highlight-both');
|
|
colors.outline = style.getPropertyValue('--pin1-outline-color-highlight-both');
|
|
} else if (h) {
|
|
colors.pad = style.getPropertyValue('--pad-color-highlight');
|
|
colors.outline = style.getPropertyValue('--pin1-outline-color-highlight');
|
|
} else if (d) {
|
|
colors.pad = style.getPropertyValue('--pad-color-highlight-marked');
|
|
colors.outline = style.getPropertyValue('--pin1-outline-color-highlight-marked');
|
|
}
|
|
}
|
|
if( h || d || !highlight) {
|
|
drawFootprint(ctx, layer, scalefactor, mod, colors, highlight, outline);
|
|
}
|
|
}
|
|
}
|
|
|
|
function drawBgLayer(layername, canvas, layer, scalefactor, edgeColor, polygonColor, textColor) {
|
|
var ctx = canvas.getContext("2d");
|
|
for (var d of pcbdata.drawings[layername][layer]) {
|
|
if (["segment", "arc", "circle", "curve", "rect"].includes(d.type)) {
|
|
drawedge(ctx, scalefactor, d, edgeColor);
|
|
} else if (d.type == "polygon") {
|
|
drawPolygonShape(ctx, scalefactor, d, polygonColor);
|
|
} else {
|
|
drawText(ctx, d, textColor);
|
|
}
|
|
}
|
|
}
|
|
|
|
function drawTracks(canvas, layer, defaultColor, highlight) {
|
|
ctx = canvas.getContext("2d");
|
|
ctx.lineCap = "round";
|
|
|
|
var hasHole = (track) => (
|
|
'drillsize' in track &&
|
|
track.start[0] == track.end[0] &&
|
|
track.start[1] == track.end[1]);
|
|
|
|
// First draw tracks and tented vias
|
|
for (var track of pcbdata.tracks[layer]) {
|
|
if (highlight && highlightedNet != track.net) continue;
|
|
if (!hasHole(track)) {
|
|
ctx.strokeStyle = highlight ? defaultColor : settings.netColors[track.net] || defaultColor;
|
|
ctx.lineWidth = track.width;
|
|
ctx.beginPath();
|
|
if ('radius' in track) {
|
|
ctx.arc(
|
|
...track.center,
|
|
track.radius,
|
|
deg2rad(track.startangle),
|
|
deg2rad(track.endangle));
|
|
} else {
|
|
ctx.moveTo(...track.start);
|
|
ctx.lineTo(...track.end);
|
|
}
|
|
ctx.stroke();
|
|
}
|
|
}
|
|
// Second pass to draw untented vias
|
|
var style = getComputedStyle(topmostdiv);
|
|
var holeColor = style.getPropertyValue('--pad-hole-color')
|
|
|
|
for (var track of pcbdata.tracks[layer]) {
|
|
if (highlight && highlightedNet != track.net) continue;
|
|
if (hasHole(track)) {
|
|
ctx.strokeStyle = highlight ? defaultColor : settings.netColors[track.net] || defaultColor;
|
|
ctx.lineWidth = track.width;
|
|
ctx.beginPath();
|
|
ctx.moveTo(...track.start);
|
|
ctx.lineTo(...track.end);
|
|
ctx.stroke();
|
|
ctx.strokeStyle = holeColor;
|
|
ctx.lineWidth = track.drillsize;
|
|
ctx.lineTo(...track.end);
|
|
ctx.stroke();
|
|
}
|
|
}
|
|
}
|
|
|
|
function drawZones(canvas, layer, defaultColor, highlight) {
|
|
ctx = canvas.getContext("2d");
|
|
ctx.lineJoin = "round";
|
|
for (var zone of pcbdata.zones[layer]) {
|
|
if (highlight && highlightedNet != zone.net) continue;
|
|
ctx.strokeStyle = highlight ? defaultColor : settings.netColors[zone.net] || defaultColor;
|
|
ctx.fillStyle = highlight ? defaultColor : settings.netColors[zone.net] || defaultColor;
|
|
if (!zone.path2d) {
|
|
zone.path2d = getPolygonsPath(zone);
|
|
}
|
|
ctx.fill(zone.path2d, zone.fillrule || "nonzero");
|
|
if (zone.width > 0) {
|
|
ctx.lineWidth = zone.width;
|
|
ctx.stroke(zone.path2d);
|
|
}
|
|
}
|
|
}
|
|
|
|
function clearCanvas(canvas, color = null) {
|
|
var ctx = canvas.getContext("2d");
|
|
ctx.save();
|
|
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
if (color) {
|
|
ctx.fillStyle = color;
|
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
} else {
|
|
if (!window.matchMedia("print").matches)
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
}
|
|
ctx.restore();
|
|
}
|
|
|
|
function drawNets(canvas, layer, highlight) {
|
|
var style = getComputedStyle(topmostdiv);
|
|
if (settings.renderZones) {
|
|
var zoneColor = style.getPropertyValue(highlight ? '--zone-color-highlight' : '--zone-color');
|
|
drawZones(canvas, layer, zoneColor, highlight);
|
|
}
|
|
if (settings.renderTracks) {
|
|
var trackColor = style.getPropertyValue(highlight ? '--track-color-highlight' : '--track-color');
|
|
drawTracks(canvas, layer, trackColor, highlight);
|
|
}
|
|
if (highlight && settings.renderPads) {
|
|
var padColor = style.getPropertyValue('--pad-color-highlight');
|
|
var padHoleColor = style.getPropertyValue('--pad-hole-color');
|
|
var ctx = canvas.getContext("2d");
|
|
for (var footprint of pcbdata.footprints) {
|
|
// draw pads
|
|
var padDrawn = false;
|
|
for (var pad of footprint.pads) {
|
|
if (highlightedNet != pad.net) continue;
|
|
if (pad.layers.includes(layer)) {
|
|
drawPad(ctx, pad, padColor, false);
|
|
padDrawn = true;
|
|
}
|
|
}
|
|
if (padDrawn) {
|
|
// redraw all pad holes because some pads may overlap
|
|
for (var pad of footprint.pads) {
|
|
drawPadHole(ctx, pad, padHoleColor);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function drawHighlightsOnLayer(canvasdict, clear = true) {
|
|
if (clear) {
|
|
clearCanvas(canvasdict.highlight);
|
|
}
|
|
if (markedFootprints.size > 0 || highlightedFootprints.length > 0) {
|
|
drawFootprints(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);
|
|
drawHighlightsOnLayer(allcanvas.back);
|
|
}
|
|
|
|
function drawBackground(canvasdict, clear = true) {
|
|
if (clear) {
|
|
clearCanvas(canvasdict.bg);
|
|
clearCanvas(canvasdict.fab);
|
|
clearCanvas(canvasdict.silk);
|
|
}
|
|
|
|
drawNets(canvasdict.bg, canvasdict.layer, false);
|
|
drawFootprints(canvasdict.bg, canvasdict.layer,
|
|
canvasdict.transform.s * canvasdict.transform.zoom, false);
|
|
|
|
drawEdgeCuts(canvasdict.bg, canvasdict.transform.s * canvasdict.transform.zoom);
|
|
|
|
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');
|
|
if (settings.renderSilkscreen) {
|
|
drawBgLayer(
|
|
"silkscreen", canvasdict.silk, canvasdict.layer,
|
|
canvasdict.transform.s * canvasdict.transform.zoom,
|
|
edgeColor, polygonColor, textColor);
|
|
}
|
|
edgeColor = style.getPropertyValue('--fabrication-edge-color');
|
|
polygonColor = style.getPropertyValue('--fabrication-polygon-color');
|
|
textColor = style.getPropertyValue('--fabrication-text-color');
|
|
if (settings.renderFabrication) {
|
|
drawBgLayer(
|
|
"fabrication", canvasdict.fab, canvasdict.layer,
|
|
canvasdict.transform.s * canvasdict.transform.zoom,
|
|
edgeColor, polygonColor, textColor);
|
|
}
|
|
}
|
|
|
|
function prepareCanvas(canvas, flip, transform) {
|
|
var ctx = canvas.getContext("2d");
|
|
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
ctx.scale(transform.zoom, transform.zoom);
|
|
ctx.translate(transform.panx, transform.pany);
|
|
if (flip) {
|
|
ctx.scale(-1, 1);
|
|
}
|
|
ctx.translate(transform.x, transform.y);
|
|
ctx.rotate(deg2rad(settings.boardRotation + (flip && settings.offsetBackRotation ? - 180 : 0)));
|
|
ctx.scale(transform.s, transform.s);
|
|
}
|
|
|
|
function prepareLayer(canvasdict) {
|
|
var flip = (canvasdict.layer === "B");
|
|
for (var c of ["bg", "fab", "silk", "highlight"]) {
|
|
prepareCanvas(canvasdict[c], flip, canvasdict.transform);
|
|
}
|
|
}
|
|
|
|
function rotateVector(v, angle) {
|
|
angle = deg2rad(angle);
|
|
return [
|
|
v[0] * Math.cos(angle) - v[1] * Math.sin(angle),
|
|
v[0] * Math.sin(angle) + v[1] * Math.cos(angle)
|
|
];
|
|
}
|
|
|
|
function applyRotation(bbox, flip) {
|
|
var corners = [
|
|
[bbox.minx, bbox.miny],
|
|
[bbox.minx, bbox.maxy],
|
|
[bbox.maxx, bbox.miny],
|
|
[bbox.maxx, bbox.maxy],
|
|
];
|
|
corners = corners.map((v) => rotateVector(v, settings.boardRotation + (flip && settings.offsetBackRotation ? - 180 : 0)));
|
|
return {
|
|
minx: corners.reduce((a, v) => Math.min(a, v[0]), Infinity),
|
|
miny: corners.reduce((a, v) => Math.min(a, v[1]), Infinity),
|
|
maxx: corners.reduce((a, v) => Math.max(a, v[0]), -Infinity),
|
|
maxy: corners.reduce((a, v) => Math.max(a, v[1]), -Infinity),
|
|
}
|
|
}
|
|
|
|
function recalcLayerScale(layerdict, width, height) {
|
|
var flip = (layerdict.layer === "B");
|
|
var bbox = applyRotation(pcbdata.edges_bbox, flip);
|
|
var scalefactor = 0.98 * Math.min(
|
|
width / (bbox.maxx - bbox.minx),
|
|
height / (bbox.maxy - bbox.miny)
|
|
);
|
|
if (scalefactor < 0.1) {
|
|
scalefactor = 1;
|
|
}
|
|
layerdict.transform.s = scalefactor;
|
|
if (flip) {
|
|
layerdict.transform.x = -((bbox.maxx + bbox.minx) * scalefactor + width) * 0.5;
|
|
} else {
|
|
layerdict.transform.x = -((bbox.maxx + bbox.minx) * scalefactor - width) * 0.5;
|
|
}
|
|
layerdict.transform.y = -((bbox.maxy + bbox.miny) * scalefactor - height) * 0.5;
|
|
for (var c of ["bg", "fab", "silk", "highlight"]) {
|
|
canvas = layerdict[c];
|
|
canvas.width = width;
|
|
canvas.height = height;
|
|
canvas.style.width = (width / devicePixelRatio) + "px";
|
|
canvas.style.height = (height / devicePixelRatio) + "px";
|
|
}
|
|
}
|
|
|
|
function redrawCanvas(layerdict) {
|
|
prepareLayer(layerdict);
|
|
drawBackground(layerdict);
|
|
drawHighlightsOnLayer(layerdict);
|
|
}
|
|
|
|
function resizeCanvas(layerdict) {
|
|
var canvasdivid = {
|
|
"F": "frontcanvas",
|
|
"B": "backcanvas"
|
|
} [layerdict.layer];
|
|
var width = document.getElementById(canvasdivid).clientWidth * devicePixelRatio;
|
|
var height = document.getElementById(canvasdivid).clientHeight * devicePixelRatio;
|
|
recalcLayerScale(layerdict, width, height);
|
|
redrawCanvas(layerdict);
|
|
}
|
|
|
|
function resizeAll() {
|
|
resizeCanvas(allcanvas.front);
|
|
resizeCanvas(allcanvas.back);
|
|
}
|
|
|
|
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 modulo(n, mod) {
|
|
return ((n % mod) + mod) % mod;
|
|
}
|
|
|
|
function pointWithinDistanceToArc(x, y, xc, yc, radius, startangle, endangle, d) {
|
|
var dx = x - xc;
|
|
var dy = y - yc;
|
|
var r_sq = dx * dx + dy * dy;
|
|
var rmin = Math.max(0, radius - d);
|
|
var rmax = radius + d;
|
|
|
|
if (r_sq < rmin * rmin || r_sq > rmax * rmax)
|
|
return false;
|
|
|
|
var angle1 = modulo(deg2rad(startangle), 2 * Math.PI);
|
|
var dx1 = xc + radius * Math.cos(angle1) - x;
|
|
var dy1 = yc + radius * Math.sin(angle1) - y;
|
|
if (dx1 * dx1 + dy1 * dy1 <= d * d)
|
|
return true;
|
|
|
|
var angle2 = modulo(deg2rad(endangle), 2 * Math.PI);
|
|
var dx2 = xc + radius * Math.cos(angle2) - x;
|
|
var dy2 = yc + radius * Math.sin(angle2) - y;
|
|
if (dx2 * dx2 + dy2 * dy2 <= d * d)
|
|
return true;
|
|
|
|
var angle = modulo(Math.atan2(dy, dx), 2 * Math.PI);
|
|
if (angle1 > angle2)
|
|
return (angle >= angle2 || angle <= angle1);
|
|
else
|
|
return (angle >= angle1 && angle <= angle2);
|
|
}
|
|
|
|
function pointWithinPad(x, y, pad) {
|
|
var v = [x - pad.pos[0], y - pad.pos[1]];
|
|
v = rotateVector(v, pad.angle);
|
|
if (pad.offset) {
|
|
v[0] -= pad.offset[0];
|
|
v[1] -= pad.offset[1];
|
|
}
|
|
return emptyContext2d.isPointInPath(getCachedPadPath(pad), ...v);
|
|
}
|
|
|
|
function netHitScan(layer, x, y) {
|
|
// Check track segments
|
|
if (settings.renderTracks && pcbdata.tracks) {
|
|
for (var track of pcbdata.tracks[layer]) {
|
|
if ('radius' in track) {
|
|
if (pointWithinDistanceToArc(x, y, ...track.center, track.radius, track.startangle, track.endangle, track.width / 2)) {
|
|
return track.net;
|
|
}
|
|
} else {
|
|
if (pointWithinDistanceToSegment(x, y, ...track.start, ...track.end, track.width / 2)) {
|
|
return track.net;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Check pads
|
|
if (settings.renderPads) {
|
|
for (var footprint of pcbdata.footprints) {
|
|
for (var pad of footprint.pads) {
|
|
if (pad.layers.includes(layer) && pointWithinPad(x, y, pad)) {
|
|
return pad.net;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function pointWithinFootprintBbox(x, y, bbox) {
|
|
var v = [x - bbox.pos[0], y - bbox.pos[1]];
|
|
v = rotateVector(v, bbox.angle);
|
|
return bbox.relpos[0] <= v[0] && v[0] <= bbox.relpos[0] + bbox.size[0] &&
|
|
bbox.relpos[1] <= v[1] && v[1] <= bbox.relpos[1] + bbox.size[1];
|
|
}
|
|
|
|
function bboxHitScan(layer, x, y) {
|
|
var result = [];
|
|
for (var i = 0; i < pcbdata.footprints.length; i++) {
|
|
var footprint = pcbdata.footprints[i];
|
|
if (footprint.layer == layer) {
|
|
if (pointWithinFootprintBbox(x, y, footprint.bbox)) {
|
|
result.push(i);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function handlePointerDown(e, layerdict) {
|
|
if (e.button != 0 && e.button != 1) {
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
if (!e.hasOwnProperty("offsetX")) {
|
|
// The polyfill doesn't set this properly
|
|
e.offsetX = e.pageX - e.currentTarget.offsetLeft;
|
|
e.offsetY = e.pageY - e.currentTarget.offsetTop;
|
|
}
|
|
|
|
layerdict.pointerStates[e.pointerId] = {
|
|
distanceTravelled: 0,
|
|
lastX: e.offsetX,
|
|
lastY: e.offsetY,
|
|
downTime: Date.now(),
|
|
};
|
|
}
|
|
|
|
function handleMouseClick(e, layerdict) {
|
|
if (!e.hasOwnProperty("offsetX")) {
|
|
// The polyfill doesn't set this properly
|
|
e.offsetX = e.pageX - e.currentTarget.offsetLeft;
|
|
e.offsetY = e.pageY - e.currentTarget.offsetTop;
|
|
}
|
|
|
|
var x = e.offsetX;
|
|
var y = e.offsetY;
|
|
var t = layerdict.transform;
|
|
var flip = layerdict.layer === "B";
|
|
if (flip) {
|
|
x = (devicePixelRatio * x / t.zoom - t.panx + t.x) / -t.s;
|
|
} else {
|
|
x = (devicePixelRatio * x / t.zoom - t.panx - t.x) / t.s;
|
|
}
|
|
y = (devicePixelRatio * y / t.zoom - t.y - t.pany) / t.s;
|
|
var v = rotateVector([x, y], -settings.boardRotation + (flip && settings.offsetBackRotation ? - 180 : 0));
|
|
if ("nets" in pcbdata) {
|
|
var net = netHitScan(layerdict.layer, ...v);
|
|
if (net !== highlightedNet) {
|
|
netClicked(net);
|
|
}
|
|
}
|
|
if (highlightedNet === null) {
|
|
var footprints = bboxHitScan(layerdict.layer, ...v);
|
|
if (footprints.length > 0) {
|
|
footprintsClicked(footprints);
|
|
}
|
|
}
|
|
}
|
|
|
|
function handlePointerLeave(e, layerdict) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
if (!settings.redrawOnDrag) {
|
|
redrawCanvas(layerdict);
|
|
}
|
|
|
|
delete layerdict.pointerStates[e.pointerId];
|
|
}
|
|
|
|
function resetTransform(layerdict) {
|
|
layerdict.transform.panx = 0;
|
|
layerdict.transform.pany = 0;
|
|
layerdict.transform.zoom = 1;
|
|
redrawCanvas(layerdict);
|
|
}
|
|
|
|
function handlePointerUp(e, layerdict) {
|
|
if (!e.hasOwnProperty("offsetX")) {
|
|
// The polyfill doesn't set this properly
|
|
e.offsetX = e.pageX - e.currentTarget.offsetLeft;
|
|
e.offsetY = e.pageY - e.currentTarget.offsetTop;
|
|
}
|
|
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
if (e.button == 2) {
|
|
// Reset pan and zoom on right click.
|
|
resetTransform(layerdict);
|
|
layerdict.anotherPointerTapped = false;
|
|
return;
|
|
}
|
|
|
|
// We haven't necessarily had a pointermove event since the interaction started, so make sure we update this now
|
|
var ptr = layerdict.pointerStates[e.pointerId];
|
|
ptr.distanceTravelled += Math.abs(e.offsetX - ptr.lastX) + Math.abs(e.offsetY - ptr.lastY);
|
|
|
|
if (e.button == 0 && ptr.distanceTravelled < 10 && Date.now() - ptr.downTime <= 500) {
|
|
if (Object.keys(layerdict.pointerStates).length == 1) {
|
|
if (layerdict.anotherPointerTapped) {
|
|
// This is the second pointer coming off of a two-finger tap
|
|
resetTransform(layerdict);
|
|
} else {
|
|
// This is just a regular tap
|
|
handleMouseClick(e, layerdict);
|
|
}
|
|
layerdict.anotherPointerTapped = false;
|
|
} else {
|
|
// This is the first finger coming off of what could become a two-finger tap
|
|
layerdict.anotherPointerTapped = true;
|
|
}
|
|
} else {
|
|
if (!settings.redrawOnDrag) {
|
|
redrawCanvas(layerdict);
|
|
}
|
|
layerdict.anotherPointerTapped = false;
|
|
}
|
|
|
|
delete layerdict.pointerStates[e.pointerId];
|
|
}
|
|
|
|
function handlePointerMove(e, layerdict) {
|
|
if (!layerdict.pointerStates.hasOwnProperty(e.pointerId)) {
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
if (!e.hasOwnProperty("offsetX")) {
|
|
// The polyfill doesn't set this properly
|
|
e.offsetX = e.pageX - e.currentTarget.offsetLeft;
|
|
e.offsetY = e.pageY - e.currentTarget.offsetTop;
|
|
}
|
|
|
|
var thisPtr = layerdict.pointerStates[e.pointerId];
|
|
|
|
var dx = e.offsetX - thisPtr.lastX;
|
|
var dy = e.offsetY - thisPtr.lastY;
|
|
|
|
// If this number is low on pointer up, we count the action as a click
|
|
thisPtr.distanceTravelled += Math.abs(dx) + Math.abs(dy);
|
|
|
|
if (Object.keys(layerdict.pointerStates).length == 1) {
|
|
// This is a simple drag
|
|
layerdict.transform.panx += devicePixelRatio * dx / layerdict.transform.zoom;
|
|
layerdict.transform.pany += devicePixelRatio * dy / layerdict.transform.zoom;
|
|
} else if (Object.keys(layerdict.pointerStates).length == 2) {
|
|
var otherPtr = Object.values(layerdict.pointerStates).filter((ptr) => ptr != thisPtr)[0];
|
|
|
|
var oldDist = Math.sqrt(Math.pow(thisPtr.lastX - otherPtr.lastX, 2) + Math.pow(thisPtr.lastY - otherPtr.lastY, 2));
|
|
var newDist = Math.sqrt(Math.pow(e.offsetX - otherPtr.lastX, 2) + Math.pow(e.offsetY - otherPtr.lastY, 2));
|
|
|
|
var scaleFactor = newDist / oldDist;
|
|
|
|
if (scaleFactor != NaN) {
|
|
layerdict.transform.zoom *= scaleFactor;
|
|
|
|
var zoomd = (1 - scaleFactor) / layerdict.transform.zoom;
|
|
layerdict.transform.panx += devicePixelRatio * otherPtr.lastX * zoomd;
|
|
layerdict.transform.pany += devicePixelRatio * otherPtr.lastY * zoomd;
|
|
}
|
|
}
|
|
|
|
thisPtr.lastX = e.offsetX;
|
|
thisPtr.lastY = e.offsetY;
|
|
|
|
if (settings.redrawOnDrag) {
|
|
redrawCanvas(layerdict);
|
|
}
|
|
}
|
|
|
|
function handleMouseWheel(e, layerdict) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
var t = layerdict.transform;
|
|
var wheeldelta = e.deltaY;
|
|
if (e.deltaMode == 1) {
|
|
// FF only, scroll by lines
|
|
wheeldelta *= 30;
|
|
} else if (e.deltaMode == 2) {
|
|
wheeldelta *= 300;
|
|
}
|
|
var m = Math.pow(1.1, -wheeldelta / 40);
|
|
// Limit amount of zoom per tick.
|
|
if (m > 2) {
|
|
m = 2;
|
|
} else if (m < 0.5) {
|
|
m = 0.5;
|
|
}
|
|
t.zoom *= m;
|
|
var zoomd = (1 - m) / t.zoom;
|
|
t.panx += devicePixelRatio * e.offsetX * zoomd;
|
|
t.pany += devicePixelRatio * e.offsetY * zoomd;
|
|
redrawCanvas(layerdict);
|
|
}
|
|
|
|
function addMouseHandlers(div, layerdict) {
|
|
div.addEventListener("pointerdown", function(e) {
|
|
handlePointerDown(e, layerdict);
|
|
});
|
|
div.addEventListener("pointermove", function(e) {
|
|
handlePointerMove(e, layerdict);
|
|
});
|
|
div.addEventListener("pointerup", function(e) {
|
|
handlePointerUp(e, layerdict);
|
|
});
|
|
var pointerleave = function(e) {
|
|
handlePointerLeave(e, layerdict);
|
|
}
|
|
div.addEventListener("pointercancel", pointerleave);
|
|
div.addEventListener("pointerleave", pointerleave);
|
|
div.addEventListener("pointerout", pointerleave);
|
|
|
|
div.onwheel = function(e) {
|
|
handleMouseWheel(e, layerdict);
|
|
}
|
|
for (var element of [div, layerdict.bg, layerdict.fab, layerdict.silk, layerdict.highlight]) {
|
|
element.addEventListener("contextmenu", function(e) {
|
|
e.preventDefault();
|
|
}, false);
|
|
}
|
|
}
|
|
|
|
function setRedrawOnDrag(value) {
|
|
settings.redrawOnDrag = value;
|
|
writeStorage("redrawOnDrag", value);
|
|
}
|
|
|
|
function setBoardRotation(value) {
|
|
settings.boardRotation = value * 5;
|
|
writeStorage("boardRotation", settings.boardRotation);
|
|
document.getElementById("rotationDegree").textContent = settings.boardRotation;
|
|
resizeAll();
|
|
}
|
|
|
|
function setOffsetBackRotation(value) {
|
|
settings.offsetBackRotation = value;
|
|
writeStorage("offsetBackRotation", value);
|
|
resizeAll();
|
|
}
|
|
|
|
function initRender() {
|
|
allcanvas = {
|
|
front: {
|
|
transform: {
|
|
x: 0,
|
|
y: 0,
|
|
s: 1,
|
|
panx: 0,
|
|
pany: 0,
|
|
zoom: 1,
|
|
},
|
|
pointerStates: {},
|
|
anotherPointerTapped: false,
|
|
bg: document.getElementById("F_bg"),
|
|
fab: document.getElementById("F_fab"),
|
|
silk: document.getElementById("F_slk"),
|
|
highlight: document.getElementById("F_hl"),
|
|
layer: "F",
|
|
},
|
|
back: {
|
|
transform: {
|
|
x: 0,
|
|
y: 0,
|
|
s: 1,
|
|
panx: 0,
|
|
pany: 0,
|
|
zoom: 1,
|
|
},
|
|
pointerStates: {},
|
|
anotherPointerTapped: false,
|
|
bg: document.getElementById("B_bg"),
|
|
fab: document.getElementById("B_fab"),
|
|
silk: document.getElementById("B_slk"),
|
|
highlight: document.getElementById("B_hl"),
|
|
layer: "B",
|
|
}
|
|
};
|
|
addMouseHandlers(document.getElementById("frontcanvas"), allcanvas.front);
|
|
addMouseHandlers(document.getElementById("backcanvas"), allcanvas.back);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////////////
|
|
/*
|
|
* Table reordering via Drag'n'Drop
|
|
* Inspired by: https://htmldom.dev/drag-and-drop-table-column
|
|
*/
|
|
|
|
function setBomHandlers() {
|
|
|
|
const bom = document.getElementById('bomtable');
|
|
|
|
let dragName;
|
|
let placeHolderElements;
|
|
let draggingElement;
|
|
let forcePopulation;
|
|
let xOffset;
|
|
let yOffset;
|
|
let wasDragged;
|
|
|
|
const mouseUpHandler = function(e) {
|
|
// Delete dragging element
|
|
draggingElement.remove();
|
|
|
|
// Make BOM selectable again
|
|
bom.style.removeProperty("userSelect");
|
|
|
|
// Remove listeners
|
|
document.removeEventListener('mousemove', mouseMoveHandler);
|
|
document.removeEventListener('mouseup', mouseUpHandler);
|
|
|
|
if (wasDragged) {
|
|
// Redraw whole BOM
|
|
populateBomTable();
|
|
}
|
|
}
|
|
|
|
const mouseMoveHandler = function(e) {
|
|
// Notice the dragging
|
|
wasDragged = true;
|
|
|
|
// Make the dragged element visible
|
|
draggingElement.style.removeProperty("display");
|
|
|
|
// Set elements position to mouse position
|
|
draggingElement.style.left = `${e.screenX - xOffset}px`;
|
|
draggingElement.style.top = `${e.screenY - yOffset}px`;
|
|
|
|
// Forced redrawing of BOM table
|
|
if (forcePopulation) {
|
|
forcePopulation = false;
|
|
// Copy array
|
|
phe = Array.from(placeHolderElements);
|
|
// populate BOM table again
|
|
populateBomHeader(dragName, phe);
|
|
populateBomBody(dragName, phe);
|
|
}
|
|
|
|
// Set up array of hidden columns
|
|
var hiddenColumns = Array.from(settings.hiddenColumns);
|
|
// In the ungrouped mode, quantity don't exist
|
|
if (settings.bommode === "ungrouped")
|
|
hiddenColumns.push("Quantity");
|
|
// If no checkbox fields can be found, we consider them hidden
|
|
if (settings.checkboxes.length == 0)
|
|
hiddenColumns.push("checkboxes");
|
|
|
|
// Get table headers and group them into checkboxes, extrafields and normal headers
|
|
const bh = document.getElementById("bomhead");
|
|
headers = Array.from(bh.querySelectorAll("th"))
|
|
headers.shift() // numCol is not part of the columnOrder
|
|
headerGroups = []
|
|
lastCompoundClass = null;
|
|
for (i = 0; i < settings.columnOrder.length; i++) {
|
|
cElem = settings.columnOrder[i];
|
|
if (hiddenColumns.includes(cElem)) {
|
|
// Hidden columns appear as a dummy element
|
|
headerGroups.push([]);
|
|
continue;
|
|
}
|
|
elem = headers.filter(e => getColumnOrderName(e) === cElem)[0];
|
|
if (elem.classList.contains("bom-checkbox")) {
|
|
if (lastCompoundClass === "bom-checkbox") {
|
|
cbGroup = headerGroups.pop();
|
|
cbGroup.push(elem);
|
|
headerGroups.push(cbGroup);
|
|
} else {
|
|
lastCompoundClass = "bom-checkbox";
|
|
headerGroups.push([elem])
|
|
}
|
|
} else {
|
|
headerGroups.push([elem])
|
|
}
|
|
}
|
|
|
|
// Copy settings.columnOrder
|
|
var columns = Array.from(settings.columnOrder)
|
|
|
|
// Set up array with indices of hidden columns
|
|
var hiddenIndices = hiddenColumns.map(e => settings.columnOrder.indexOf(e));
|
|
var dragIndex = columns.indexOf(dragName);
|
|
var swapIndex = dragIndex;
|
|
var swapDone = false;
|
|
|
|
// Check if the current dragged element is swapable with the left or right element
|
|
if (dragIndex > 0) {
|
|
// Get left headers boundingbox
|
|
swapIndex = dragIndex - 1;
|
|
while (hiddenIndices.includes(swapIndex) && swapIndex > 0)
|
|
swapIndex--;
|
|
if (!hiddenIndices.includes(swapIndex)) {
|
|
box = getBoundingClientRectFromMultiple(headerGroups[swapIndex]);
|
|
if (e.clientX < box.left + window.scrollX + (box.width / 2)) {
|
|
swapElement = columns[dragIndex];
|
|
columns.splice(dragIndex, 1);
|
|
columns.splice(swapIndex, 0, swapElement);
|
|
forcePopulation = true;
|
|
swapDone = true;
|
|
}
|
|
}
|
|
}
|
|
if ((!swapDone) && dragIndex < headerGroups.length - 1) {
|
|
// Get right headers boundingbox
|
|
swapIndex = dragIndex + 1;
|
|
while (hiddenIndices.includes(swapIndex))
|
|
swapIndex++;
|
|
if (swapIndex < headerGroups.length) {
|
|
box = getBoundingClientRectFromMultiple(headerGroups[swapIndex]);
|
|
if (e.clientX > box.left + window.scrollX + (box.width / 2)) {
|
|
swapElement = columns[dragIndex];
|
|
columns.splice(dragIndex, 1);
|
|
columns.splice(swapIndex, 0, swapElement);
|
|
forcePopulation = true;
|
|
swapDone = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Write back change to storage
|
|
if (swapDone) {
|
|
settings.columnOrder = columns
|
|
writeStorage("columnOrder", JSON.stringify(columns));
|
|
}
|
|
|
|
}
|
|
|
|
const mouseDownHandler = function(e) {
|
|
var target = e.target;
|
|
if (target.tagName.toLowerCase() != "td")
|
|
target = target.parentElement;
|
|
|
|
// Used to check if a dragging has ever happened
|
|
wasDragged = false;
|
|
|
|
// Create new element which will be displayed as the dragged column
|
|
draggingElement = document.createElement("div")
|
|
draggingElement.classList.add("dragging");
|
|
draggingElement.style.display = "none";
|
|
draggingElement.style.position = "absolute";
|
|
draggingElement.style.overflow = "hidden";
|
|
|
|
// Get bomhead and bombody elements
|
|
const bh = document.getElementById("bomhead");
|
|
const bb = document.getElementById("bombody");
|
|
|
|
// Get all compound headers for the current column
|
|
var compoundHeaders;
|
|
if (target.classList.contains("bom-checkbox")) {
|
|
compoundHeaders = Array.from(bh.querySelectorAll("th.bom-checkbox"));
|
|
} else {
|
|
compoundHeaders = [target];
|
|
}
|
|
|
|
// Create new table which will display the column
|
|
var newTable = document.createElement("table");
|
|
newTable.classList.add("bom");
|
|
newTable.style.background = "white";
|
|
draggingElement.append(newTable);
|
|
|
|
// Create new header element
|
|
var newHeader = document.createElement("thead");
|
|
newTable.append(newHeader);
|
|
|
|
// Set up array for storing all placeholder elements
|
|
placeHolderElements = [];
|
|
|
|
// Add all compound headers to the new thead element and placeholders
|
|
compoundHeaders.forEach(function(h) {
|
|
clone = cloneElementWithDimensions(h);
|
|
newHeader.append(clone);
|
|
placeHolderElements.push(clone);
|
|
});
|
|
|
|
// Create new body element
|
|
var newBody = document.createElement("tbody");
|
|
newTable.append(newBody);
|
|
|
|
// Get indices for compound headers
|
|
var idxs = compoundHeaders.map(e => getBomTableHeaderIndex(e));
|
|
|
|
// For each row in the BOM body...
|
|
var rows = bb.querySelectorAll("tr");
|
|
rows.forEach(function(row) {
|
|
// ..get the cells for the compound column
|
|
const tds = row.querySelectorAll("td");
|
|
var copytds = idxs.map(i => tds[i]);
|
|
// Add them to the new element and the placeholders
|
|
var newRow = document.createElement("tr");
|
|
copytds.forEach(function(td) {
|
|
clone = cloneElementWithDimensions(td);
|
|
newRow.append(clone);
|
|
placeHolderElements.push(clone);
|
|
});
|
|
newBody.append(newRow);
|
|
});
|
|
|
|
// Compute width for compound header
|
|
var width = compoundHeaders.reduce((acc, x) => acc + x.clientWidth, 0);
|
|
draggingElement.style.width = `${width}px`;
|
|
|
|
// Insert the new dragging element and disable selection on BOM
|
|
bom.insertBefore(draggingElement, null);
|
|
bom.style.userSelect = "none";
|
|
|
|
// Determine the mouse position offset
|
|
xOffset = e.screenX - compoundHeaders.reduce((acc, x) => Math.min(acc, x.offsetLeft), compoundHeaders[0].offsetLeft);
|
|
yOffset = e.screenY - compoundHeaders[0].offsetTop;
|
|
|
|
// Get name for the column in settings.columnOrder
|
|
dragName = getColumnOrderName(target);
|
|
|
|
// Change text and class for placeholder elements
|
|
placeHolderElements = placeHolderElements.map(function(e) {
|
|
newElem = cloneElementWithDimensions(e);
|
|
newElem.textContent = "";
|
|
newElem.classList.add("placeholder");
|
|
return newElem;
|
|
});
|
|
|
|
// On next mouse move, the whole BOM needs to be redrawn to show the placeholders
|
|
forcePopulation = true;
|
|
|
|
// Add listeners for move and up on mouse
|
|
document.addEventListener('mousemove', mouseMoveHandler);
|
|
document.addEventListener('mouseup', mouseUpHandler);
|
|
}
|
|
|
|
// In netlist mode, there is nothing to reorder
|
|
if (settings.bommode === "netlist")
|
|
return;
|
|
|
|
// Add mouseDownHandler to every column except the numCol
|
|
bom.querySelectorAll("th")
|
|
.forEach(function(head) {
|
|
if (!head.classList.contains("numCol")) {
|
|
head.onmousedown = mouseDownHandler;
|
|
}
|
|
});
|
|
|
|
}
|
|
|
|
function getBoundingClientRectFromMultiple(elements) {
|
|
var elems = Array.from(elements);
|
|
|
|
if (elems.length == 0)
|
|
return null;
|
|
|
|
var box = elems.shift()
|
|
.getBoundingClientRect();
|
|
|
|
elems.forEach(function(elem) {
|
|
var elembox = elem.getBoundingClientRect();
|
|
box.left = Math.min(elembox.left, box.left);
|
|
box.top = Math.min(elembox.top, box.top);
|
|
box.width += elembox.width;
|
|
box.height = Math.max(elembox.height, box.height);
|
|
});
|
|
|
|
return box;
|
|
}
|
|
|
|
function cloneElementWithDimensions(elem) {
|
|
var newElem = elem.cloneNode(true);
|
|
newElem.style.height = window.getComputedStyle(elem).height;
|
|
newElem.style.width = window.getComputedStyle(elem).width;
|
|
return newElem;
|
|
}
|
|
|
|
function getBomTableHeaderIndex(elem) {
|
|
const bh = document.getElementById('bomhead');
|
|
const ths = Array.from(bh.querySelectorAll("th"));
|
|
return ths.indexOf(elem);
|
|
}
|
|
|
|
function getColumnOrderName(elem) {
|
|
var cname = elem.getAttribute("col_name");
|
|
if (cname === "bom-checkbox")
|
|
return "checkboxes";
|
|
else
|
|
return cname;
|
|
}
|
|
|
|
function resizableGrid(tablehead) {
|
|
var cols = tablehead.firstElementChild.children;
|
|
var rowWidth = tablehead.offsetWidth;
|
|
|
|
for (var i = 1; i < cols.length; i++) {
|
|
if (cols[i].classList.contains("bom-checkbox"))
|
|
continue;
|
|
cols[i].style.width = ((cols[i].clientWidth - paddingDiff(cols[i])) * 100 / rowWidth) + '%';
|
|
}
|
|
|
|
for (var i = 1; i < cols.length - 1; i++) {
|
|
var div = document.createElement('div');
|
|
div.className = "column-width-handle";
|
|
cols[i].appendChild(div);
|
|
setListeners(div);
|
|
}
|
|
|
|
function setListeners(div) {
|
|
var startX, curCol, nxtCol, curColWidth, nxtColWidth, rowWidth;
|
|
|
|
div.addEventListener('mousedown', function(e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
curCol = e.target.parentElement;
|
|
nxtCol = curCol.nextElementSibling;
|
|
startX = e.pageX;
|
|
|
|
var padding = paddingDiff(curCol);
|
|
|
|
rowWidth = curCol.parentElement.offsetWidth;
|
|
curColWidth = curCol.clientWidth - padding;
|
|
nxtColWidth = nxtCol.clientWidth - padding;
|
|
});
|
|
|
|
document.addEventListener('mousemove', function(e) {
|
|
if (startX) {
|
|
var diffX = e.pageX - startX;
|
|
diffX = -Math.min(-diffX, curColWidth - 20);
|
|
diffX = Math.min(diffX, nxtColWidth - 20);
|
|
|
|
curCol.style.width = ((curColWidth + diffX) * 100 / rowWidth) + '%';
|
|
nxtCol.style.width = ((nxtColWidth - diffX) * 100 / rowWidth) + '%';
|
|
console.log(`${curColWidth + nxtColWidth} ${(curColWidth + diffX) * 100 / rowWidth + (nxtColWidth - diffX) * 100 / rowWidth}`);
|
|
}
|
|
});
|
|
|
|
document.addEventListener('mouseup', function(e) {
|
|
curCol = undefined;
|
|
nxtCol = undefined;
|
|
startX = undefined;
|
|
nxtColWidth = undefined;
|
|
curColWidth = undefined
|
|
});
|
|
}
|
|
|
|
function paddingDiff(col) {
|
|
|
|
if (getStyleVal(col, 'box-sizing') == 'border-box') {
|
|
return 0;
|
|
}
|
|
|
|
var padLeft = getStyleVal(col, 'padding-left');
|
|
var padRight = getStyleVal(col, 'padding-right');
|
|
return (parseInt(padLeft) + parseInt(padRight));
|
|
|
|
}
|
|
|
|
function getStyleVal(elm, css) {
|
|
return (window.getComputedStyle(elm, null).getPropertyValue(css))
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////////////
|
|
/* DOM manipulation and misc code */
|
|
|
|
var bomsplit;
|
|
var canvassplit;
|
|
var initDone = false;
|
|
var bomSortFunction = null;
|
|
var currentSortColumn = null;
|
|
var currentSortOrder = null;
|
|
var currentHighlightedRowId;
|
|
var highlightHandlers = [];
|
|
var footprintIndexToHandler = {};
|
|
var netsToHandler = {};
|
|
var markedFootprints = new Set();
|
|
var highlightedFootprints = [];
|
|
var highlightedNet = null;
|
|
var lastClicked;
|
|
|
|
function dbg(html) {
|
|
dbgdiv.innerHTML = html;
|
|
}
|
|
|
|
function redrawIfInitDone() {
|
|
if (initDone) {
|
|
redrawCanvas(allcanvas.front);
|
|
redrawCanvas(allcanvas.back);
|
|
}
|
|
}
|
|
|
|
function padsVisible(value) {
|
|
writeStorage("padsVisible", value);
|
|
settings.renderPads = value;
|
|
redrawIfInitDone();
|
|
}
|
|
|
|
function referencesVisible(value) {
|
|
writeStorage("referencesVisible", value);
|
|
settings.renderReferences = value;
|
|
redrawIfInitDone();
|
|
}
|
|
|
|
function valuesVisible(value) {
|
|
writeStorage("valuesVisible", value);
|
|
settings.renderValues = value;
|
|
redrawIfInitDone();
|
|
}
|
|
|
|
function tracksVisible(value) {
|
|
writeStorage("tracksVisible", value);
|
|
settings.renderTracks = value;
|
|
redrawIfInitDone();
|
|
}
|
|
|
|
function zonesVisible(value) {
|
|
writeStorage("zonesVisible", value);
|
|
settings.renderZones = value;
|
|
redrawIfInitDone();
|
|
}
|
|
|
|
function dnpOutline(value) {
|
|
writeStorage("dnpOutline", value);
|
|
settings.renderDnpOutline = value;
|
|
redrawIfInitDone();
|
|
}
|
|
|
|
function setDarkMode(value) {
|
|
if (value) {
|
|
topmostdiv.classList.add("dark");
|
|
} else {
|
|
topmostdiv.classList.remove("dark");
|
|
}
|
|
writeStorage("darkmode", value);
|
|
settings.darkMode = value;
|
|
redrawIfInitDone();
|
|
if (initDone) {
|
|
populateBomTable();
|
|
}
|
|
}
|
|
|
|
function setShowBOMColumn(field, value) {
|
|
if (field === "references") {
|
|
var rl = document.getElementById("reflookup");
|
|
rl.disabled = !value;
|
|
if (!value) {
|
|
rl.value = "";
|
|
updateRefLookup("");
|
|
}
|
|
}
|
|
|
|
var n = settings.hiddenColumns.indexOf(field);
|
|
if (value) {
|
|
if (n != -1) {
|
|
settings.hiddenColumns.splice(n, 1);
|
|
}
|
|
} else {
|
|
if (n == -1) {
|
|
settings.hiddenColumns.push(field);
|
|
}
|
|
}
|
|
|
|
writeStorage("hiddenColumns", JSON.stringify(settings.hiddenColumns));
|
|
|
|
if (initDone) {
|
|
populateBomTable();
|
|
}
|
|
|
|
redrawIfInitDone();
|
|
}
|
|
|
|
|
|
function setFullscreen(value) {
|
|
if (value) {
|
|
document.documentElement.requestFullscreen();
|
|
} else {
|
|
document.exitFullscreen();
|
|
}
|
|
}
|
|
|
|
function fabricationVisible(value) {
|
|
writeStorage("fabricationVisible", value);
|
|
settings.renderFabrication = value;
|
|
redrawIfInitDone();
|
|
}
|
|
|
|
function silkscreenVisible(value) {
|
|
writeStorage("silkscreenVisible", value);
|
|
settings.renderSilkscreen = value;
|
|
redrawIfInitDone();
|
|
}
|
|
|
|
function setHighlightPin1(value) {
|
|
writeStorage("highlightpin1", value);
|
|
settings.highlightpin1 = value;
|
|
redrawIfInitDone();
|
|
}
|
|
|
|
function setHighlightRowOnClick(value) {
|
|
settings.highlightRowOnClick = value;
|
|
writeStorage("highlightRowOnClick", value);
|
|
if (initDone) {
|
|
populateBomTable();
|
|
}
|
|
}
|
|
|
|
function getStoredCheckboxRefs(checkbox) {
|
|
function convert(ref) {
|
|
var intref = parseInt(ref);
|
|
if (isNaN(intref)) {
|
|
for (var i = 0; i < pcbdata.footprints.length; i++) {
|
|
if (pcbdata.footprints[i].ref == ref) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
} else {
|
|
return intref;
|
|
}
|
|
}
|
|
if (!(checkbox in settings.checkboxStoredRefs)) {
|
|
var val = readStorage("checkbox_" + checkbox);
|
|
settings.checkboxStoredRefs[checkbox] = val ? val : "";
|
|
}
|
|
if (!settings.checkboxStoredRefs[checkbox]) {
|
|
return new Set();
|
|
} else {
|
|
return new Set(settings.checkboxStoredRefs[checkbox].split(",").map(r => convert(r)).filter(a => a >= 0));
|
|
}
|
|
}
|
|
|
|
function getCheckboxState(checkbox, references) {
|
|
var storedRefsSet = getStoredCheckboxRefs(checkbox);
|
|
var currentRefsSet = new Set(references.map(r => r[1]));
|
|
// Get difference of current - stored
|
|
var difference = new Set(currentRefsSet);
|
|
for (ref of storedRefsSet) {
|
|
difference.delete(ref);
|
|
}
|
|
if (difference.size == 0) {
|
|
// All the current refs are stored
|
|
return "checked";
|
|
} else if (difference.size == currentRefsSet.size) {
|
|
// None of the current refs are stored
|
|
return "unchecked";
|
|
} else {
|
|
// Some of the refs are stored
|
|
return "indeterminate";
|
|
}
|
|
}
|
|
|
|
function setBomCheckboxState(checkbox, element, references) {
|
|
var state = getCheckboxState(checkbox, references);
|
|
element.checked = (state == "checked");
|
|
element.indeterminate = (state == "indeterminate");
|
|
}
|
|
|
|
function createCheckboxHandlers(input, checkbox, references, row) {
|
|
var clickHandler = () => {
|
|
refsSet = getStoredCheckboxRefs(checkbox);
|
|
var markWhenChecked = settings.markWhenChecked == checkbox;
|
|
eventArgs = {
|
|
checkbox: checkbox,
|
|
refs: references,
|
|
}
|
|
if (input.checked) {
|
|
// checkbox ticked
|
|
for (var ref of references) {
|
|
refsSet.add(ref[1]);
|
|
}
|
|
if (markWhenChecked) {
|
|
row.classList.add("checked");
|
|
for (var ref of references) {
|
|
markedFootprints.add(ref[1]);
|
|
}
|
|
drawHighlights();
|
|
}
|
|
eventArgs.state = 'checked';
|
|
} else {
|
|
// checkbox unticked
|
|
for (var ref of references) {
|
|
refsSet.delete(ref[1]);
|
|
}
|
|
if (markWhenChecked) {
|
|
row.classList.remove("checked");
|
|
for (var ref of references) {
|
|
markedFootprints.delete(ref[1]);
|
|
}
|
|
drawHighlights();
|
|
}
|
|
eventArgs.state = 'unchecked';
|
|
}
|
|
settings.checkboxStoredRefs[checkbox] = [...refsSet].join(",");
|
|
writeStorage("checkbox_" + checkbox, settings.checkboxStoredRefs[checkbox]);
|
|
updateCheckboxStats(checkbox);
|
|
EventHandler.emitEvent(IBOM_EVENT_TYPES.CHECKBOX_CHANGE_EVENT, eventArgs);
|
|
}
|
|
|
|
return [
|
|
(e) => {
|
|
clickHandler();
|
|
},
|
|
(e) => {
|
|
e.preventDefault();
|
|
if (row.onmousemove) row.onmousemove();
|
|
},
|
|
(e) => {
|
|
e.preventDefault();
|
|
input.checked = !input.checked;
|
|
input.indeterminate = false;
|
|
clickHandler();
|
|
}
|
|
];
|
|
}
|
|
|
|
function clearHighlightedFootprints() {
|
|
if (currentHighlightedRowId) {
|
|
document.getElementById(currentHighlightedRowId).classList.remove("highlighted");
|
|
currentHighlightedRowId = null;
|
|
highlightedFootprints = [];
|
|
highlightedNet = null;
|
|
}
|
|
}
|
|
|
|
function createRowHighlightHandler(rowid, refs, net) {
|
|
return function () {
|
|
if (currentHighlightedRowId) {
|
|
if (currentHighlightedRowId == rowid) {
|
|
return;
|
|
}
|
|
document.getElementById(currentHighlightedRowId).classList.remove("highlighted");
|
|
}
|
|
document.getElementById(rowid).classList.add("highlighted");
|
|
currentHighlightedRowId = rowid;
|
|
highlightedFootprints = refs ? refs.map(r => r[1]) : [];
|
|
highlightedNet = net;
|
|
drawHighlights();
|
|
EventHandler.emitEvent(
|
|
IBOM_EVENT_TYPES.HIGHLIGHT_EVENT, {
|
|
rowid: rowid,
|
|
refs: refs,
|
|
net: net
|
|
});
|
|
}
|
|
}
|
|
|
|
function updateNetColors() {
|
|
writeStorage("netColors", JSON.stringify(settings.netColors));
|
|
redrawIfInitDone();
|
|
}
|
|
|
|
function netColorChangeHandler(net) {
|
|
return (event) => {
|
|
settings.netColors[net] = event.target.value;
|
|
updateNetColors();
|
|
}
|
|
}
|
|
|
|
function netColorRightClick(net) {
|
|
return (event) => {
|
|
if (event.button == 2) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
|
|
var style = getComputedStyle(topmostdiv);
|
|
var defaultNetColor = style.getPropertyValue('--track-color').trim();
|
|
event.target.value = defaultNetColor;
|
|
delete settings.netColors[net];
|
|
updateNetColors();
|
|
}
|
|
}
|
|
}
|
|
|
|
function entryMatches(entry) {
|
|
if (settings.bommode == "netlist") {
|
|
// entry is just a net name
|
|
return entry.toLowerCase().indexOf(filter) >= 0;
|
|
}
|
|
// check refs
|
|
if (!settings.hiddenColumns.includes("References")) {
|
|
for (var ref of entry) {
|
|
if (ref[0].toLowerCase().indexOf(filter) >= 0) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
// check fields
|
|
for (var i in config.fields) {
|
|
var f = config.fields[i];
|
|
if (!settings.hiddenColumns.includes(f)) {
|
|
for (var ref of entry) {
|
|
if (String(pcbdata.bom.fields[ref[1]][i]).toLowerCase().indexOf(filter) >= 0) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function findRefInEntry(entry) {
|
|
return entry.filter(r => r[0].toLowerCase() == reflookup);
|
|
}
|
|
|
|
function highlightFilter(s) {
|
|
if (!filter) {
|
|
return s;
|
|
}
|
|
var parts = s.toLowerCase().split(filter);
|
|
if (parts.length == 1) {
|
|
return s;
|
|
}
|
|
var r = "";
|
|
var pos = 0;
|
|
for (var i in parts) {
|
|
if (i > 0) {
|
|
r += '<mark class="highlight">' +
|
|
s.substring(pos, pos + filter.length) +
|
|
'</mark>';
|
|
pos += filter.length;
|
|
}
|
|
r += s.substring(pos, pos + parts[i].length);
|
|
pos += parts[i].length;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
function getBomListByLayer(layer) {
|
|
switch (layer) {
|
|
case 'F': return pcbdata.bom.F.slice();
|
|
case 'B': return pcbdata.bom.B.slice();
|
|
case 'FB': return pcbdata.bom.both.slice();
|
|
}
|
|
return [];
|
|
}
|
|
|
|
function getSelectedBomList() {
|
|
if (settings.bommode == "netlist") {
|
|
return pcbdata.nets.slice();
|
|
}
|
|
var out = getBomListByLayer(settings.canvaslayout);
|
|
|
|
if (settings.bommode == "ungrouped") {
|
|
// expand bom table
|
|
var expandedTable = [];
|
|
for (var bomentry of out) {
|
|
for (var ref of bomentry) {
|
|
expandedTable.push([ref]);
|
|
}
|
|
}
|
|
return expandedTable;
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
function checkboxSetUnsetAllHandler(checkboxname) {
|
|
return function () {
|
|
var checkboxnum = 0;
|
|
while (checkboxnum < settings.checkboxes.length &&
|
|
settings.checkboxes[checkboxnum].toLowerCase() != checkboxname.toLowerCase()) {
|
|
checkboxnum++;
|
|
}
|
|
if (checkboxnum >= settings.checkboxes.length) {
|
|
return;
|
|
}
|
|
var allset = true;
|
|
var checkbox;
|
|
var row;
|
|
for (row of bombody.childNodes) {
|
|
checkbox = row.childNodes[checkboxnum + 1].childNodes[0];
|
|
if (!checkbox.checked || checkbox.indeterminate) {
|
|
allset = false;
|
|
break;
|
|
}
|
|
}
|
|
for (row of bombody.childNodes) {
|
|
checkbox = row.childNodes[checkboxnum + 1].childNodes[0];
|
|
checkbox.checked = !allset;
|
|
checkbox.indeterminate = false;
|
|
checkbox.onchange();
|
|
}
|
|
}
|
|
}
|
|
|
|
function createColumnHeader(name, cls, comparator, is_checkbox = false) {
|
|
var th = document.createElement("TH");
|
|
th.innerHTML = name;
|
|
th.classList.add(cls);
|
|
if (is_checkbox)
|
|
th.setAttribute("col_name", "bom-checkbox");
|
|
else
|
|
th.setAttribute("col_name", name);
|
|
var span = document.createElement("SPAN");
|
|
span.classList.add("sortmark");
|
|
span.classList.add("none");
|
|
th.appendChild(span);
|
|
var spacer = document.createElement("div");
|
|
spacer.className = "column-spacer";
|
|
th.appendChild(spacer);
|
|
spacer.onclick = function () {
|
|
if (currentSortColumn && th !== currentSortColumn) {
|
|
// Currently sorted by another column
|
|
currentSortColumn.childNodes[1].classList.remove(currentSortOrder);
|
|
currentSortColumn.childNodes[1].classList.add("none");
|
|
currentSortColumn = null;
|
|
currentSortOrder = null;
|
|
}
|
|
if (currentSortColumn && th === currentSortColumn) {
|
|
// Already sorted by this column
|
|
if (currentSortOrder == "asc") {
|
|
// Sort by this column, descending order
|
|
bomSortFunction = function (a, b) {
|
|
return -comparator(a, b);
|
|
}
|
|
currentSortColumn.childNodes[1].classList.remove("asc");
|
|
currentSortColumn.childNodes[1].classList.add("desc");
|
|
currentSortOrder = "desc";
|
|
} else {
|
|
// Unsort
|
|
bomSortFunction = null;
|
|
currentSortColumn.childNodes[1].classList.remove("desc");
|
|
currentSortColumn.childNodes[1].classList.add("none");
|
|
currentSortColumn = null;
|
|
currentSortOrder = null;
|
|
}
|
|
} else {
|
|
// Sort by this column, ascending order
|
|
bomSortFunction = comparator;
|
|
currentSortColumn = th;
|
|
currentSortColumn.childNodes[1].classList.remove("none");
|
|
currentSortColumn.childNodes[1].classList.add("asc");
|
|
currentSortOrder = "asc";
|
|
}
|
|
populateBomBody();
|
|
}
|
|
if (is_checkbox) {
|
|
spacer.onclick = fancyDblClickHandler(
|
|
spacer, spacer.onclick, checkboxSetUnsetAllHandler(name));
|
|
}
|
|
return th;
|
|
}
|
|
|
|
function populateBomHeader(placeHolderColumn = null, placeHolderElements = null) {
|
|
while (bomhead.firstChild) {
|
|
bomhead.removeChild(bomhead.firstChild);
|
|
}
|
|
var tr = document.createElement("TR");
|
|
var th = document.createElement("TH");
|
|
th.classList.add("numCol");
|
|
|
|
var vismenu = document.createElement("div");
|
|
vismenu.id = "vismenu";
|
|
vismenu.classList.add("menu");
|
|
|
|
var visbutton = document.createElement("div");
|
|
visbutton.classList.add("visbtn");
|
|
visbutton.classList.add("hideonprint");
|
|
|
|
var viscontent = document.createElement("div");
|
|
viscontent.classList.add("menu-content");
|
|
viscontent.id = "vismenu-content";
|
|
|
|
settings.columnOrder.forEach(column => {
|
|
if (typeof column !== "string")
|
|
return;
|
|
|
|
// Skip empty columns
|
|
if (column === "checkboxes" && settings.checkboxes.length == 0)
|
|
return;
|
|
else if (column === "Quantity" && settings.bommode == "ungrouped")
|
|
return;
|
|
|
|
var label = document.createElement("label");
|
|
label.classList.add("menu-label");
|
|
|
|
var input = document.createElement("input");
|
|
input.classList.add("visibility_checkbox");
|
|
input.type = "checkbox";
|
|
input.onchange = function (e) {
|
|
setShowBOMColumn(column, e.target.checked)
|
|
};
|
|
input.checked = !(settings.hiddenColumns.includes(column));
|
|
|
|
label.appendChild(input);
|
|
if (column.length > 0)
|
|
label.append(column[0].toUpperCase() + column.slice(1));
|
|
|
|
viscontent.appendChild(label);
|
|
});
|
|
|
|
viscontent.childNodes[0].classList.add("menu-label-top");
|
|
|
|
vismenu.appendChild(visbutton);
|
|
if (settings.bommode != "netlist") {
|
|
vismenu.appendChild(viscontent);
|
|
th.appendChild(vismenu);
|
|
}
|
|
tr.appendChild(th);
|
|
|
|
var checkboxCompareClosure = function (checkbox) {
|
|
return (a, b) => {
|
|
var stateA = getCheckboxState(checkbox, a);
|
|
var stateB = getCheckboxState(checkbox, b);
|
|
if (stateA > stateB) return -1;
|
|
if (stateA < stateB) return 1;
|
|
return 0;
|
|
}
|
|
}
|
|
var stringFieldCompareClosure = function (fieldIndex) {
|
|
return (a, b) => {
|
|
var fa = pcbdata.bom.fields[a[0][1]][fieldIndex];
|
|
var fb = pcbdata.bom.fields[b[0][1]][fieldIndex];
|
|
if (fa != fb) return fa > fb ? 1 : -1;
|
|
else return 0;
|
|
}
|
|
}
|
|
var referenceRegex = /(?<prefix>[^0-9]+)(?<number>[0-9]+)/;
|
|
var compareRefs = (a, b) => {
|
|
var ra = referenceRegex.exec(a);
|
|
var rb = referenceRegex.exec(b);
|
|
if (ra === null || rb === null) {
|
|
if (a != b) return a > b ? 1 : -1;
|
|
return 0;
|
|
} else {
|
|
if (ra.groups.prefix != rb.groups.prefix) {
|
|
return ra.groups.prefix > rb.groups.prefix ? 1 : -1;
|
|
}
|
|
if (ra.groups.number != rb.groups.number) {
|
|
return parseInt(ra.groups.number) > parseInt(rb.groups.number) ? 1 : -1;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
if (settings.bommode == "netlist") {
|
|
tr.appendChild(createColumnHeader("Net name", "bom-netname", (a, b) => {
|
|
if (a > b) return -1;
|
|
if (a < b) return 1;
|
|
return 0;
|
|
}));
|
|
tr.appendChild(createColumnHeader("Color", "bom-color", (a, b) => {
|
|
return 0;
|
|
}));
|
|
} else {
|
|
// Filter hidden columns
|
|
var columns = settings.columnOrder.filter(e => !settings.hiddenColumns.includes(e));
|
|
var valueIndex = config.fields.indexOf("Value");
|
|
var footprintIndex = config.fields.indexOf("Footprint");
|
|
columns.forEach((column) => {
|
|
if (column === placeHolderColumn) {
|
|
var n = 1;
|
|
if (column === "checkboxes")
|
|
n = settings.checkboxes.length;
|
|
for (i = 0; i < n; i++) {
|
|
td = placeHolderElements.shift();
|
|
tr.appendChild(td);
|
|
}
|
|
return;
|
|
} else if (column === "checkboxes") {
|
|
for (var checkbox of settings.checkboxes) {
|
|
th = createColumnHeader(
|
|
checkbox, "bom-checkbox", checkboxCompareClosure(checkbox), true);
|
|
tr.appendChild(th);
|
|
}
|
|
} else if (column === "References") {
|
|
tr.appendChild(createColumnHeader("References", "references", (a, b) => {
|
|
var i = 0;
|
|
while (i < a.length && i < b.length) {
|
|
if (a[i][0] != b[i][0]) return compareRefs(a[i][0], b[i][0]);
|
|
i++;
|
|
}
|
|
return a.length - b.length;
|
|
}));
|
|
} else if (column === "Value") {
|
|
tr.appendChild(createColumnHeader("Value", "value", (a, b) => {
|
|
var ra = a[0][1], rb = b[0][1];
|
|
return valueCompare(
|
|
pcbdata.bom.parsedValues[ra], pcbdata.bom.parsedValues[rb],
|
|
pcbdata.bom.fields[ra][valueIndex], pcbdata.bom.fields[rb][valueIndex]);
|
|
}));
|
|
return;
|
|
} else if (column === "Footprint") {
|
|
tr.appendChild(createColumnHeader(
|
|
"Footprint", "footprint", stringFieldCompareClosure(footprintIndex)));
|
|
} else if (column === "Quantity" && settings.bommode == "grouped") {
|
|
tr.appendChild(createColumnHeader("Quantity", "quantity", (a, b) => {
|
|
return a.length - b.length;
|
|
}));
|
|
} else {
|
|
// Other fields
|
|
var i = config.fields.indexOf(column);
|
|
if (i < 0)
|
|
return;
|
|
tr.appendChild(createColumnHeader(
|
|
column, `field${i + 1}`, stringFieldCompareClosure(i)));
|
|
}
|
|
});
|
|
}
|
|
bomhead.appendChild(tr);
|
|
}
|
|
|
|
function populateBomBody(placeholderColumn = null, placeHolderElements = null) {
|
|
const urlRegex = /^(https?:\/\/[^\s\/$.?#][^\s]*|file:\/\/([a-zA-Z]:|\/)[^\x00]+)$/;
|
|
while (bom.firstChild) {
|
|
bom.removeChild(bom.firstChild);
|
|
}
|
|
highlightHandlers = [];
|
|
footprintIndexToHandler = {};
|
|
netsToHandler = {};
|
|
currentHighlightedRowId = null;
|
|
var first = true;
|
|
var style = getComputedStyle(topmostdiv);
|
|
var defaultNetColor = style.getPropertyValue('--track-color').trim();
|
|
|
|
bomtable = getSelectedBomList();
|
|
|
|
if (bomSortFunction) {
|
|
bomtable = bomtable.sort(bomSortFunction);
|
|
}
|
|
for (var i in bomtable) {
|
|
var bomentry = bomtable[i];
|
|
if (filter && !entryMatches(bomentry)) {
|
|
continue;
|
|
}
|
|
var references = null;
|
|
var netname = null;
|
|
var tr = document.createElement("TR");
|
|
var td = document.createElement("TD");
|
|
var rownum = +i + 1;
|
|
tr.id = "bomrow" + rownum;
|
|
td.textContent = rownum;
|
|
tr.appendChild(td);
|
|
if (settings.bommode == "netlist") {
|
|
netname = bomentry;
|
|
td = document.createElement("TD");
|
|
td.innerHTML = highlightFilter(netname ? netname : "<no net>");
|
|
tr.appendChild(td);
|
|
var color = settings.netColors[netname] || defaultNetColor;
|
|
td = document.createElement("TD");
|
|
var colorBox = document.createElement("INPUT");
|
|
colorBox.type = "color";
|
|
colorBox.value = color;
|
|
colorBox.onchange = netColorChangeHandler(netname);
|
|
colorBox.onmouseup = netColorRightClick(netname);
|
|
colorBox.oncontextmenu = (e) => e.preventDefault();
|
|
td.appendChild(colorBox);
|
|
td.classList.add("color-column");
|
|
tr.appendChild(td);
|
|
} else {
|
|
if (reflookup) {
|
|
references = findRefInEntry(bomentry);
|
|
if (references.length == 0) {
|
|
continue;
|
|
}
|
|
} else {
|
|
references = bomentry;
|
|
}
|
|
// Filter hidden columns
|
|
var columns = settings.columnOrder.filter(e => !settings.hiddenColumns.includes(e));
|
|
columns.forEach((column) => {
|
|
if (column === placeholderColumn) {
|
|
var n = 1;
|
|
if (column === "checkboxes")
|
|
n = settings.checkboxes.length;
|
|
for (i = 0; i < n; i++) {
|
|
td = placeHolderElements.shift();
|
|
tr.appendChild(td);
|
|
}
|
|
return;
|
|
} else if (column === "checkboxes") {
|
|
for (var checkbox of settings.checkboxes) {
|
|
if (checkbox) {
|
|
td = document.createElement("TD");
|
|
var input = document.createElement("input");
|
|
input.type = "checkbox";
|
|
[input.onchange, td.ontouchstart, td.ontouchend] = createCheckboxHandlers(input, checkbox, references, tr);
|
|
setBomCheckboxState(checkbox, input, references);
|
|
if (input.checked && settings.markWhenChecked == checkbox) {
|
|
tr.classList.add("checked");
|
|
}
|
|
td.appendChild(input);
|
|
tr.appendChild(td);
|
|
}
|
|
}
|
|
} else if (column === "References") {
|
|
td = document.createElement("TD");
|
|
td.innerHTML = highlightFilter(references.map(r => r[0]).join(", "));
|
|
tr.appendChild(td);
|
|
} else if (column === "Quantity" && settings.bommode == "grouped") {
|
|
// Quantity
|
|
td = document.createElement("TD");
|
|
td.textContent = references.length;
|
|
tr.appendChild(td);
|
|
} else {
|
|
// All the other fields
|
|
var field_index = config.fields.indexOf(column)
|
|
if (field_index < 0)
|
|
return;
|
|
var valueSet = new Set();
|
|
references.map(r => r[1]).forEach((id) => valueSet.add(pcbdata.bom.fields[id][field_index]));
|
|
td = document.createElement("TD");
|
|
var output = new Array();
|
|
for (let item of valueSet) {
|
|
const visible = highlightFilter(String(item));
|
|
if (typeof item === 'string' && item.match(urlRegex)) {
|
|
output.push(`<a href="${item}" target="_blank">${visible}</a>`);
|
|
} else {
|
|
output.push(visible);
|
|
}
|
|
}
|
|
td.innerHTML = output.join(", ");
|
|
tr.appendChild(td);
|
|
}
|
|
});
|
|
}
|
|
bom.appendChild(tr);
|
|
var handler = createRowHighlightHandler(tr.id, references, netname);
|
|
if (settings.highlightRowOnClick) {
|
|
tr.onmousedown = handler;
|
|
} else {
|
|
tr.onmousemove = handler;
|
|
}
|
|
highlightHandlers.push({
|
|
id: tr.id,
|
|
handler: handler,
|
|
});
|
|
if (references !== null) {
|
|
for (var refIndex of references.map(r => r[1])) {
|
|
footprintIndexToHandler[refIndex] = handler;
|
|
}
|
|
}
|
|
if (netname !== null) {
|
|
netsToHandler[netname] = handler;
|
|
}
|
|
if ((filter || reflookup) && first) {
|
|
handler();
|
|
first = false;
|
|
}
|
|
}
|
|
EventHandler.emitEvent(
|
|
IBOM_EVENT_TYPES.BOM_BODY_CHANGE_EVENT, {
|
|
filter: filter,
|
|
reflookup: reflookup,
|
|
checkboxes: settings.checkboxes,
|
|
bommode: settings.bommode,
|
|
});
|
|
}
|
|
|
|
function highlightPreviousRow() {
|
|
if (!currentHighlightedRowId) {
|
|
highlightHandlers[highlightHandlers.length - 1].handler();
|
|
} else {
|
|
if (highlightHandlers.length > 1 &&
|
|
highlightHandlers[0].id == currentHighlightedRowId) {
|
|
highlightHandlers[highlightHandlers.length - 1].handler();
|
|
} else {
|
|
for (var i = 0; i < highlightHandlers.length - 1; i++) {
|
|
if (highlightHandlers[i + 1].id == currentHighlightedRowId) {
|
|
highlightHandlers[i].handler();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
smoothScrollToRow(currentHighlightedRowId);
|
|
}
|
|
|
|
function highlightNextRow() {
|
|
if (!currentHighlightedRowId) {
|
|
highlightHandlers[0].handler();
|
|
} else {
|
|
if (highlightHandlers.length > 1 &&
|
|
highlightHandlers[highlightHandlers.length - 1].id == currentHighlightedRowId) {
|
|
highlightHandlers[0].handler();
|
|
} else {
|
|
for (var i = 1; i < highlightHandlers.length; i++) {
|
|
if (highlightHandlers[i - 1].id == currentHighlightedRowId) {
|
|
highlightHandlers[i].handler();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
smoothScrollToRow(currentHighlightedRowId);
|
|
}
|
|
|
|
function populateBomTable() {
|
|
populateBomHeader();
|
|
populateBomBody();
|
|
setBomHandlers();
|
|
resizableGrid(bomhead);
|
|
}
|
|
|
|
function footprintsClicked(footprintIndexes) {
|
|
var lastClickedIndex = footprintIndexes.indexOf(lastClicked);
|
|
for (var i = 1; i <= footprintIndexes.length; i++) {
|
|
var refIndex = footprintIndexes[(lastClickedIndex + i) % footprintIndexes.length];
|
|
if (refIndex in footprintIndexToHandler) {
|
|
lastClicked = refIndex;
|
|
footprintIndexToHandler[refIndex]();
|
|
smoothScrollToRow(currentHighlightedRowId);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
function netClicked(net) {
|
|
if (net in netsToHandler) {
|
|
netsToHandler[net]();
|
|
smoothScrollToRow(currentHighlightedRowId);
|
|
} else {
|
|
clearHighlightedFootprints();
|
|
highlightedNet = net;
|
|
drawHighlights();
|
|
}
|
|
}
|
|
|
|
function updateFilter(input) {
|
|
filter = input.toLowerCase();
|
|
populateBomTable();
|
|
}
|
|
|
|
function updateRefLookup(input) {
|
|
reflookup = input.toLowerCase();
|
|
populateBomTable();
|
|
}
|
|
|
|
function changeCanvasLayout(layout) {
|
|
document.getElementById("fl-btn").classList.remove("depressed");
|
|
document.getElementById("fb-btn").classList.remove("depressed");
|
|
document.getElementById("bl-btn").classList.remove("depressed");
|
|
switch (layout) {
|
|
case 'F':
|
|
document.getElementById("fl-btn").classList.add("depressed");
|
|
if (settings.bomlayout != "bom-only") {
|
|
canvassplit.collapse(1);
|
|
}
|
|
break;
|
|
case 'B':
|
|
document.getElementById("bl-btn").classList.add("depressed");
|
|
if (settings.bomlayout != "bom-only") {
|
|
canvassplit.collapse(0);
|
|
}
|
|
break;
|
|
default:
|
|
document.getElementById("fb-btn").classList.add("depressed");
|
|
if (settings.bomlayout != "bom-only") {
|
|
canvassplit.setSizes([50, 50]);
|
|
}
|
|
}
|
|
settings.canvaslayout = layout;
|
|
writeStorage("canvaslayout", layout);
|
|
resizeAll();
|
|
changeBomMode(settings.bommode);
|
|
}
|
|
|
|
function populateMetadata() {
|
|
document.getElementById("title").innerHTML = pcbdata.metadata.title;
|
|
document.getElementById("revision").innerHTML = "Rev: " + pcbdata.metadata.revision;
|
|
document.getElementById("company").innerHTML = pcbdata.metadata.company;
|
|
document.getElementById("filedate").innerHTML = pcbdata.metadata.date;
|
|
if (pcbdata.metadata.title != "") {
|
|
document.title = pcbdata.metadata.title + " BOM";
|
|
}
|
|
// Calculate board stats
|
|
var fp_f = 0,
|
|
fp_b = 0,
|
|
pads_f = 0,
|
|
pads_b = 0,
|
|
pads_th = 0;
|
|
for (var i = 0; i < pcbdata.footprints.length; i++) {
|
|
if (pcbdata.bom.skipped.includes(i)) continue;
|
|
var mod = pcbdata.footprints[i];
|
|
if (mod.layer == "F") {
|
|
fp_f++;
|
|
} else {
|
|
fp_b++;
|
|
}
|
|
for (var pad of mod.pads) {
|
|
if (pad.type == "th") {
|
|
pads_th++;
|
|
} else {
|
|
if (pad.layers.includes("F")) {
|
|
pads_f++;
|
|
}
|
|
if (pad.layers.includes("B")) {
|
|
pads_b++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
document.getElementById("stats-components-front").innerHTML = fp_f;
|
|
document.getElementById("stats-components-back").innerHTML = fp_b;
|
|
document.getElementById("stats-components-total").innerHTML = fp_f + fp_b;
|
|
document.getElementById("stats-groups-front").innerHTML = pcbdata.bom.F.length;
|
|
document.getElementById("stats-groups-back").innerHTML = pcbdata.bom.B.length;
|
|
document.getElementById("stats-groups-total").innerHTML = pcbdata.bom.both.length;
|
|
document.getElementById("stats-smd-pads-front").innerHTML = pads_f;
|
|
document.getElementById("stats-smd-pads-back").innerHTML = pads_b;
|
|
document.getElementById("stats-smd-pads-total").innerHTML = pads_f + pads_b;
|
|
document.getElementById("stats-th-pads").innerHTML = pads_th;
|
|
// Update version string
|
|
document.getElementById("github-link").innerHTML = "InteractiveHtmlBom " +
|
|
/^v\d+\.\d+/.exec(pcbdata.ibom_version)[0];
|
|
}
|
|
|
|
function changeBomLayout(layout) {
|
|
document.getElementById("bom-btn").classList.remove("depressed");
|
|
document.getElementById("lr-btn").classList.remove("depressed");
|
|
document.getElementById("tb-btn").classList.remove("depressed");
|
|
switch (layout) {
|
|
case 'bom-only':
|
|
document.getElementById("bom-btn").classList.add("depressed");
|
|
if (bomsplit) {
|
|
bomsplit.destroy();
|
|
bomsplit = null;
|
|
canvassplit.destroy();
|
|
canvassplit = null;
|
|
}
|
|
document.getElementById("frontcanvas").style.display = "none";
|
|
document.getElementById("backcanvas").style.display = "none";
|
|
document.getElementById("topmostdiv").style.height = "";
|
|
document.getElementById("topmostdiv").style.display = "block";
|
|
break;
|
|
case 'top-bottom':
|
|
document.getElementById("tb-btn").classList.add("depressed");
|
|
document.getElementById("frontcanvas").style.display = "";
|
|
document.getElementById("backcanvas").style.display = "";
|
|
document.getElementById("topmostdiv").style.height = "100%";
|
|
document.getElementById("topmostdiv").style.display = "flex";
|
|
document.getElementById("bomdiv").classList.remove("split-horizontal");
|
|
document.getElementById("canvasdiv").classList.remove("split-horizontal");
|
|
document.getElementById("frontcanvas").classList.add("split-horizontal");
|
|
document.getElementById("backcanvas").classList.add("split-horizontal");
|
|
if (bomsplit) {
|
|
bomsplit.destroy();
|
|
bomsplit = null;
|
|
canvassplit.destroy();
|
|
canvassplit = null;
|
|
}
|
|
bomsplit = Split(['#bomdiv', '#canvasdiv'], {
|
|
sizes: [50, 50],
|
|
onDragEnd: resizeAll,
|
|
direction: "vertical",
|
|
gutterSize: 5
|
|
});
|
|
canvassplit = Split(['#frontcanvas', '#backcanvas'], {
|
|
sizes: [50, 50],
|
|
gutterSize: 5,
|
|
onDragEnd: resizeAll
|
|
});
|
|
break;
|
|
case 'left-right':
|
|
document.getElementById("lr-btn").classList.add("depressed");
|
|
document.getElementById("frontcanvas").style.display = "";
|
|
document.getElementById("backcanvas").style.display = "";
|
|
document.getElementById("topmostdiv").style.height = "100%";
|
|
document.getElementById("topmostdiv").style.display = "flex";
|
|
document.getElementById("bomdiv").classList.add("split-horizontal");
|
|
document.getElementById("canvasdiv").classList.add("split-horizontal");
|
|
document.getElementById("frontcanvas").classList.remove("split-horizontal");
|
|
document.getElementById("backcanvas").classList.remove("split-horizontal");
|
|
if (bomsplit) {
|
|
bomsplit.destroy();
|
|
bomsplit = null;
|
|
canvassplit.destroy();
|
|
canvassplit = null;
|
|
}
|
|
bomsplit = Split(['#bomdiv', '#canvasdiv'], {
|
|
sizes: [50, 50],
|
|
onDragEnd: resizeAll,
|
|
gutterSize: 5
|
|
});
|
|
canvassplit = Split(['#frontcanvas', '#backcanvas'], {
|
|
sizes: [50, 50],
|
|
gutterSize: 5,
|
|
direction: "vertical",
|
|
onDragEnd: resizeAll
|
|
});
|
|
}
|
|
settings.bomlayout = layout;
|
|
writeStorage("bomlayout", layout);
|
|
changeCanvasLayout(settings.canvaslayout);
|
|
}
|
|
|
|
function changeBomMode(mode) {
|
|
document.getElementById("bom-grouped-btn").classList.remove("depressed");
|
|
document.getElementById("bom-ungrouped-btn").classList.remove("depressed");
|
|
document.getElementById("bom-netlist-btn").classList.remove("depressed");
|
|
var chkbxs = document.getElementsByClassName("visibility_checkbox");
|
|
|
|
switch (mode) {
|
|
case 'grouped':
|
|
document.getElementById("bom-grouped-btn").classList.add("depressed");
|
|
for (var i = 0; i < chkbxs.length; i++) {
|
|
chkbxs[i].disabled = false;
|
|
}
|
|
break;
|
|
case 'ungrouped':
|
|
document.getElementById("bom-ungrouped-btn").classList.add("depressed");
|
|
for (var i = 0; i < chkbxs.length; i++) {
|
|
chkbxs[i].disabled = false;
|
|
}
|
|
break;
|
|
case 'netlist':
|
|
document.getElementById("bom-netlist-btn").classList.add("depressed");
|
|
for (var i = 0; i < chkbxs.length; i++) {
|
|
chkbxs[i].disabled = true;
|
|
}
|
|
}
|
|
|
|
writeStorage("bommode", mode);
|
|
if (mode != settings.bommode) {
|
|
settings.bommode = mode;
|
|
bomSortFunction = null;
|
|
currentSortColumn = null;
|
|
currentSortOrder = null;
|
|
clearHighlightedFootprints();
|
|
}
|
|
populateBomTable();
|
|
}
|
|
|
|
function focusFilterField() {
|
|
focusInputField(document.getElementById("filter"));
|
|
}
|
|
|
|
function focusRefLookupField() {
|
|
focusInputField(document.getElementById("reflookup"));
|
|
}
|
|
|
|
function toggleBomCheckbox(bomrowid, checkboxnum) {
|
|
if (!bomrowid || checkboxnum > settings.checkboxes.length) {
|
|
return;
|
|
}
|
|
var bomrow = document.getElementById(bomrowid);
|
|
var childNum = checkboxnum + settings.columnOrder.indexOf("checkboxes");
|
|
var checkbox = bomrow.childNodes[childNum].childNodes[0];
|
|
checkbox.checked = !checkbox.checked;
|
|
checkbox.indeterminate = false;
|
|
checkbox.onchange();
|
|
}
|
|
|
|
function checkBomCheckbox(bomrowid, checkboxname) {
|
|
var checkboxnum = 0;
|
|
while (checkboxnum < settings.checkboxes.length &&
|
|
settings.checkboxes[checkboxnum].toLowerCase() != checkboxname.toLowerCase()) {
|
|
checkboxnum++;
|
|
}
|
|
if (!bomrowid || checkboxnum >= settings.checkboxes.length) {
|
|
return;
|
|
}
|
|
var bomrow = document.getElementById(bomrowid);
|
|
var childNum = checkboxnum + 1 + settings.columnOrder.indexOf("checkboxes");
|
|
var checkbox = bomrow.childNodes[childNum].childNodes[0];
|
|
checkbox.checked = true;
|
|
checkbox.indeterminate = false;
|
|
checkbox.onchange();
|
|
}
|
|
|
|
function setBomCheckboxes(value) {
|
|
writeStorage("bomCheckboxes", value);
|
|
settings.checkboxes = value.split(",").map((e) => e.trim()).filter((e) => e);
|
|
prepCheckboxes();
|
|
populateMarkWhenCheckedOptions();
|
|
setMarkWhenChecked(settings.markWhenChecked);
|
|
}
|
|
|
|
function setMarkWhenChecked(value) {
|
|
writeStorage("markWhenChecked", value);
|
|
settings.markWhenChecked = value;
|
|
markedFootprints.clear();
|
|
for (var ref of (value ? getStoredCheckboxRefs(value) : [])) {
|
|
markedFootprints.add(ref);
|
|
}
|
|
populateBomTable();
|
|
drawHighlights();
|
|
}
|
|
|
|
function prepCheckboxes() {
|
|
var table = document.getElementById("checkbox-stats");
|
|
while (table.childElementCount > 1) {
|
|
table.removeChild(table.lastChild);
|
|
}
|
|
if (settings.checkboxes.length) {
|
|
table.style.display = "";
|
|
} else {
|
|
table.style.display = "none";
|
|
}
|
|
for (var checkbox of settings.checkboxes) {
|
|
var tr = document.createElement("TR");
|
|
var td = document.createElement("TD");
|
|
td.innerHTML = checkbox;
|
|
tr.appendChild(td);
|
|
td = document.createElement("TD");
|
|
td.id = "checkbox-stats-" + checkbox;
|
|
var progressbar = document.createElement("div");
|
|
progressbar.classList.add("bar");
|
|
td.appendChild(progressbar);
|
|
var text = document.createElement("div");
|
|
text.classList.add("text");
|
|
td.appendChild(text);
|
|
tr.appendChild(td);
|
|
table.appendChild(tr);
|
|
updateCheckboxStats(checkbox);
|
|
}
|
|
}
|
|
|
|
function populateMarkWhenCheckedOptions() {
|
|
var container = document.getElementById("markWhenCheckedContainer");
|
|
|
|
if (settings.checkboxes.length == 0) {
|
|
container.parentElement.style.display = "none";
|
|
return;
|
|
}
|
|
|
|
container.innerHTML = '';
|
|
container.parentElement.style.display = "inline-block";
|
|
|
|
function createOption(name, displayName) {
|
|
var id = "markWhenChecked-" + name;
|
|
|
|
var div = document.createElement("div");
|
|
div.classList.add("radio-container");
|
|
|
|
var input = document.createElement("input");
|
|
input.type = "radio";
|
|
input.name = "markWhenChecked";
|
|
input.value = name;
|
|
input.id = id;
|
|
input.onchange = () => setMarkWhenChecked(name);
|
|
div.appendChild(input);
|
|
|
|
// Preserve the selected element when the checkboxes change
|
|
if (name == settings.markWhenChecked) {
|
|
input.checked = true;
|
|
}
|
|
|
|
var label = document.createElement("label");
|
|
label.innerHTML = displayName;
|
|
label.htmlFor = id;
|
|
div.appendChild(label);
|
|
|
|
container.appendChild(div);
|
|
}
|
|
createOption("", "None");
|
|
for (var checkbox of settings.checkboxes) {
|
|
createOption(checkbox, checkbox);
|
|
}
|
|
}
|
|
|
|
function updateCheckboxStats(checkbox) {
|
|
var checked = getStoredCheckboxRefs(checkbox).size;
|
|
var total = pcbdata.footprints.length - pcbdata.bom.skipped.length;
|
|
var percent = checked * 100.0 / total;
|
|
var td = document.getElementById("checkbox-stats-" + checkbox);
|
|
td.firstChild.style.width = percent + "%";
|
|
td.lastChild.innerHTML = checked + "/" + total + " (" + Math.round(percent) + "%)";
|
|
}
|
|
|
|
function constrain(number, min, max) {
|
|
return Math.min(Math.max(parseInt(number), min), max);
|
|
}
|
|
|
|
document.onkeydown = function (e) {
|
|
switch (e.key) {
|
|
case "n":
|
|
if (document.activeElement.type == "text") {
|
|
return;
|
|
}
|
|
if (currentHighlightedRowId !== null) {
|
|
checkBomCheckbox(currentHighlightedRowId, "placed");
|
|
highlightNextRow();
|
|
e.preventDefault();
|
|
}
|
|
break;
|
|
case "ArrowUp":
|
|
highlightPreviousRow();
|
|
e.preventDefault();
|
|
break;
|
|
case "ArrowDown":
|
|
highlightNextRow();
|
|
e.preventDefault();
|
|
break;
|
|
case "ArrowLeft":
|
|
case "ArrowRight":
|
|
if (document.activeElement.type != "text") {
|
|
e.preventDefault();
|
|
let boardRotationElement = document.getElementById("boardRotation")
|
|
settings.boardRotation = parseInt(boardRotationElement.value); // degrees / 5
|
|
if (e.key == "ArrowLeft") {
|
|
settings.boardRotation += 3; // 15 degrees
|
|
}
|
|
else {
|
|
settings.boardRotation -= 3;
|
|
}
|
|
settings.boardRotation = constrain(settings.boardRotation, boardRotationElement.min, boardRotationElement.max);
|
|
boardRotationElement.value = settings.boardRotation
|
|
setBoardRotation(settings.boardRotation);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (e.altKey) {
|
|
switch (e.key) {
|
|
case "f":
|
|
focusFilterField();
|
|
e.preventDefault();
|
|
break;
|
|
case "r":
|
|
focusRefLookupField();
|
|
e.preventDefault();
|
|
break;
|
|
case "z":
|
|
changeBomLayout("bom-only");
|
|
e.preventDefault();
|
|
break;
|
|
case "x":
|
|
changeBomLayout("left-right");
|
|
e.preventDefault();
|
|
break;
|
|
case "c":
|
|
changeBomLayout("top-bottom");
|
|
e.preventDefault();
|
|
break;
|
|
case "v":
|
|
changeCanvasLayout("F");
|
|
e.preventDefault();
|
|
break;
|
|
case "b":
|
|
changeCanvasLayout("FB");
|
|
e.preventDefault();
|
|
break;
|
|
case "n":
|
|
changeCanvasLayout("B");
|
|
e.preventDefault();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (e.key >= '1' && e.key <= '9') {
|
|
toggleBomCheckbox(currentHighlightedRowId, parseInt(e.key));
|
|
e.preventDefault();
|
|
}
|
|
}
|
|
}
|
|
|
|
function hideNetlistButton() {
|
|
document.getElementById("bom-ungrouped-btn").classList.remove("middle-button");
|
|
document.getElementById("bom-ungrouped-btn").classList.add("right-most-button");
|
|
document.getElementById("bom-netlist-btn").style.display = "none";
|
|
}
|
|
|
|
function topToggle() {
|
|
var top = document.getElementById("top");
|
|
var toptoggle = document.getElementById("toptoggle");
|
|
if (top.style.display === "none") {
|
|
top.style.display = "flex";
|
|
toptoggle.classList.remove("flipped");
|
|
} else {
|
|
top.style.display = "none";
|
|
toptoggle.classList.add("flipped");
|
|
}
|
|
}
|
|
|
|
window.onload = function (e) {
|
|
initRender();
|
|
initStorage();
|
|
initDefaults();
|
|
initUtils();
|
|
cleanGutters();
|
|
populateMetadata();
|
|
dbgdiv = document.getElementById("dbg");
|
|
bom = document.getElementById("bombody");
|
|
bomhead = document.getElementById("bomhead");
|
|
filter = "";
|
|
reflookup = "";
|
|
if (!("nets" in pcbdata)) {
|
|
hideNetlistButton();
|
|
}
|
|
initDone = true;
|
|
setBomCheckboxes(document.getElementById("bomCheckboxes").value);
|
|
// Triggers render
|
|
changeBomLayout(settings.bomlayout);
|
|
|
|
// Users may leave fullscreen without touching the checkbox. Uncheck.
|
|
document.addEventListener('fullscreenchange', () => {
|
|
if (!document.fullscreenElement)
|
|
document.getElementById('fullscreenCheckbox').checked = false;
|
|
});
|
|
}
|
|
|
|
window.onresize = resizeAll;
|
|
window.matchMedia("print").addListener(resizeAll);
|
|
|
|
///////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////////////
|
|
</script>
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div id="topmostdiv" class="topmostdiv">
|
|
<div id="top">
|
|
<div id="fileinfodiv">
|
|
<table class="fileinfo">
|
|
<tbody>
|
|
<tr>
|
|
<td id="title" class="title" style="width: 70%">
|
|
Title
|
|
</td>
|
|
<td id="revision" class="title" style="width: 30%">
|
|
Revision
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td id="company">
|
|
Company
|
|
</td>
|
|
<td id="filedate">
|
|
Date
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div id="bomcontrols">
|
|
<div class="hideonprint menu">
|
|
<button class="menubtn"></button>
|
|
<div class="menu-content">
|
|
<label class="menu-label menu-label-top" style="width: calc(50% - 18px)">
|
|
<input id="darkmodeCheckbox" type="checkbox" onchange="setDarkMode(this.checked)">
|
|
Dark mode
|
|
</label><!-- This comment eats space! All of it!
|
|
--><label class="menu-label menu-label-top" style="width: calc(50% - 17px); border-left: 0;">
|
|
<input id="fullscreenCheckbox" type="checkbox" onchange="setFullscreen(this.checked)">
|
|
Full Screen
|
|
</label>
|
|
<label class="menu-label" style="width: calc(50% - 18px)">
|
|
<input id="fabricationCheckbox" type="checkbox" checked onchange="fabricationVisible(this.checked)">
|
|
Fab layer
|
|
</label><!-- This comment eats space! All of it!
|
|
--><label class="menu-label" style="width: calc(50% - 17px); border-left: 0;">
|
|
<input id="silkscreenCheckbox" type="checkbox" checked onchange="silkscreenVisible(this.checked)">
|
|
Silkscreen
|
|
</label>
|
|
<label class="menu-label" style="width: calc(50% - 18px)">
|
|
<input id="referencesCheckbox" type="checkbox" checked onchange="referencesVisible(this.checked)">
|
|
References
|
|
</label><!-- This comment eats space! All of it!
|
|
--><label class="menu-label" style="width: calc(50% - 17px); border-left: 0;">
|
|
<input id="valuesCheckbox" type="checkbox" checked onchange="valuesVisible(this.checked)">
|
|
Values
|
|
</label>
|
|
<div id="tracksAndZonesCheckboxes">
|
|
<label class="menu-label" style="width: calc(50% - 18px)">
|
|
<input id="tracksCheckbox" type="checkbox" checked onchange="tracksVisible(this.checked)">
|
|
Tracks
|
|
</label><!-- This comment eats space! All of it!
|
|
--><label class="menu-label" style="width: calc(50% - 17px); border-left: 0;">
|
|
<input id="zonesCheckbox" type="checkbox" checked onchange="zonesVisible(this.checked)">
|
|
Zones
|
|
</label>
|
|
</div>
|
|
<label class="menu-label" style="width: calc(50% - 18px)">
|
|
<input id="padsCheckbox" type="checkbox" checked onchange="padsVisible(this.checked)">
|
|
Pads
|
|
</label><!-- This comment eats space! All of it!
|
|
--><label class="menu-label" style="width: calc(50% - 17px); border-left: 0;">
|
|
<input id="dnpOutlineCheckbox" type="checkbox" checked onchange="dnpOutline(this.checked)">
|
|
DNP outlined
|
|
</label>
|
|
<label class="menu-label">
|
|
<input id="highlightRowOnClickCheckbox" type="checkbox" checked onchange="setHighlightRowOnClick(this.checked)">
|
|
Highlight row on click
|
|
</label>
|
|
<label class="menu-label">
|
|
<input id="dragCheckbox" type="checkbox" checked onchange="setRedrawOnDrag(this.checked)">
|
|
Continuous redraw on drag
|
|
</label>
|
|
<label class="menu-label">
|
|
Highlight first pin
|
|
<form id="highlightpin1">
|
|
<div class="flexbox">
|
|
<label>
|
|
<input type="radio" name="highlightpin1" value="none" onchange="setHighlightPin1('none')">
|
|
None
|
|
</label>
|
|
<label>
|
|
<input type="radio" name="highlightpin1" value="all" onchange="setHighlightPin1('all')">
|
|
All
|
|
</label>
|
|
<label>
|
|
<input type="radio" name="highlightpin1" value="selected" onchange="setHighlightPin1('selected')">
|
|
Selected
|
|
</label>
|
|
</div>
|
|
</form>
|
|
</label>
|
|
<label class="menu-label">
|
|
<span>Board rotation</span>
|
|
<span style="float: right"><span id="rotationDegree">0</span>°</span>
|
|
<input id="boardRotation" type="range" min="-36" max="36" value="0" class="slider" oninput="setBoardRotation(this.value)">
|
|
</label>
|
|
<label class="menu-label">
|
|
<input id="offsetBackRotationCheckbox" type="checkbox" onchange="setOffsetBackRotation(this.checked)">
|
|
Offset back rotation
|
|
</label>
|
|
<label class="menu-label">
|
|
<div style="margin-left: 5px">Bom checkboxes</div>
|
|
<input id="bomCheckboxes" class="menu-textbox" type=text
|
|
oninput="setBomCheckboxes(this.value)">
|
|
</label>
|
|
<label class="menu-label">
|
|
<div style="margin-left: 5px">Mark when checked</div>
|
|
<div id="markWhenCheckedContainer"></div>
|
|
</label>
|
|
<label class="menu-label">
|
|
<span class="shameless-plug">
|
|
<span>Created using</span>
|
|
<a id="github-link" target="blank" href="https://github.com/openscopeproject/InteractiveHtmlBom">InteractiveHtmlBom</a>
|
|
<a target="blank" title="Mouse and keyboard help" href="https://github.com/openscopeproject/InteractiveHtmlBom/wiki/Usage#bom-page-mouse-actions" style="text-decoration: none;"><label class="help-link">?</label></a>
|
|
</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="button-container hideonprint">
|
|
<button id="fl-btn" class="left-most-button" onclick="changeCanvasLayout('F')"
|
|
title="Front only">F
|
|
</button>
|
|
<button id="fb-btn" class="middle-button" onclick="changeCanvasLayout('FB')"
|
|
title="Front and Back">FB
|
|
</button>
|
|
<button id="bl-btn" class="right-most-button" onclick="changeCanvasLayout('B')"
|
|
title="Back only">B
|
|
</button>
|
|
</div>
|
|
<div class="button-container hideonprint">
|
|
<button id="bom-btn" class="left-most-button" onclick="changeBomLayout('bom-only')"
|
|
title="BOM only"></button>
|
|
<button id="lr-btn" class="middle-button" onclick="changeBomLayout('left-right')"
|
|
title="BOM left, drawings right"></button>
|
|
<button id="tb-btn" class="right-most-button" onclick="changeBomLayout('top-bottom')"
|
|
title="BOM top, drawings bot"></button>
|
|
</div>
|
|
<div class="button-container hideonprint">
|
|
<button id="bom-grouped-btn" class="left-most-button" onclick="changeBomMode('grouped')"
|
|
title="Grouped BOM"></button>
|
|
<button id="bom-ungrouped-btn" class="middle-button" onclick="changeBomMode('ungrouped')"
|
|
title="Ungrouped BOM"></button>
|
|
<button id="bom-netlist-btn" class="right-most-button" onclick="changeBomMode('netlist')"
|
|
title="Netlist"></button>
|
|
</div>
|
|
<div class="hideonprint menu">
|
|
<button class="statsbtn"></button>
|
|
<div class="menu-content">
|
|
<table class="stats">
|
|
<tbody>
|
|
<tr>
|
|
<td width="40%">Board stats</td>
|
|
<td>Front</td>
|
|
<td>Back</td>
|
|
<td>Total</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Components</td>
|
|
<td id="stats-components-front">~</td>
|
|
<td id="stats-components-back">~</td>
|
|
<td id="stats-components-total">~</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Groups</td>
|
|
<td id="stats-groups-front">~</td>
|
|
<td id="stats-groups-back">~</td>
|
|
<td id="stats-groups-total">~</td>
|
|
</tr>
|
|
<tr>
|
|
<td>SMD pads</td>
|
|
<td id="stats-smd-pads-front">~</td>
|
|
<td id="stats-smd-pads-back">~</td>
|
|
<td id="stats-smd-pads-total">~</td>
|
|
</tr>
|
|
<tr>
|
|
<td>TH pads</td>
|
|
<td colspan=3 id="stats-th-pads">~</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<table class="stats">
|
|
<col width="40%"/><col />
|
|
<tbody id="checkbox-stats">
|
|
<tr>
|
|
<td colspan=2 style="border-top: 0">Checkboxes</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="hideonprint menu">
|
|
<button class="iobtn"></button>
|
|
<div class="menu-content">
|
|
<div class="menu-label menu-label-top">
|
|
<div style="margin-left: 5px;">Save board image</div>
|
|
<div class="flexbox">
|
|
<input id="render-save-width" class="menu-textbox" type="text" value="1000" placeholder="Width"
|
|
style="flex-grow: 1; width: 50px;" oninput="validateSaveImgDimension(this)">
|
|
<span>X</span>
|
|
<input id="render-save-height" class="menu-textbox" type="text" value="1000" placeholder="Height"
|
|
style="flex-grow: 1; width: 50px;" oninput="validateSaveImgDimension(this)">
|
|
</div>
|
|
<label>
|
|
<input id="render-save-transparent" type="checkbox">
|
|
Transparent background
|
|
</label>
|
|
<div class="flexbox">
|
|
<button class="savebtn" onclick="saveImage('F')">Front</button>
|
|
<button class="savebtn" onclick="saveImage('B')">Back</button>
|
|
</div>
|
|
</div>
|
|
<div class="menu-label">
|
|
<span style="margin-left: 5px;">Config and checkbox state</span>
|
|
<div class="flexbox">
|
|
<button class="savebtn" onclick="saveSettings()">Export</button>
|
|
<button class="savebtn" onclick="loadSettings()">Import</button>
|
|
<button class="savebtn" onclick="resetSettings()">Reset</button>
|
|
</div>
|
|
</div>
|
|
<div class="menu-label">
|
|
<span style="margin-left: 5px;">Save bom table as</span>
|
|
<div class="flexbox">
|
|
<button class="savebtn" onclick="saveBomTable('csv')">csv</button>
|
|
<button class="savebtn" onclick="saveBomTable('txt')">txt</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="topdivider">
|
|
<div class="hideonprint">
|
|
<div id="toptoggle" onclick="topToggle()">︽</div>
|
|
</div>
|
|
</div>
|
|
<div id="bot" class="split" style="flex: 1 1">
|
|
<div id="bomdiv" class="split split-horizontal">
|
|
<div style="width: 100%">
|
|
<input id="reflookup" class="textbox searchbox reflookup hideonprint" type="text" placeholder="Ref lookup"
|
|
oninput="updateRefLookup(this.value)">
|
|
<input id="filter" class="textbox searchbox filter hideonprint" type="text" placeholder="Filter"
|
|
oninput="updateFilter(this.value)">
|
|
<div class="button-container hideonprint" style="float: left; margin: 0;">
|
|
<button id="copy" title="Copy bom table to clipboard"
|
|
onclick="saveBomTable('clipboard')"></button>
|
|
</div>
|
|
</div>
|
|
<div id="dbg"></div>
|
|
<table class="bom" id="bomtable">
|
|
<thead id="bomhead">
|
|
</thead>
|
|
<tbody id="bombody">
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div id="canvasdiv" class="split split-horizontal">
|
|
<div id="frontcanvas" class="split" touch-action="none" style="overflow: hidden">
|
|
<div style="position: relative; width: 100%; height: 100%;">
|
|
<canvas id="F_bg" style="position: absolute; left: 0; top: 0; z-index: 0;"></canvas>
|
|
<canvas id="F_fab" style="position: absolute; left: 0; top: 0; z-index: 1;"></canvas>
|
|
<canvas id="F_slk" style="position: absolute; left: 0; top: 0; z-index: 2;"></canvas>
|
|
<canvas id="F_hl" style="position: absolute; left: 0; top: 0; z-index: 3;"></canvas>
|
|
</div>
|
|
</div>
|
|
<div id="backcanvas" class="split" touch-action="none" style="overflow: hidden">
|
|
<div style="position: relative; width: 100%; height: 100%;">
|
|
<canvas id="B_bg" style="position: absolute; left: 0; top: 0; z-index: 0;"></canvas>
|
|
<canvas id="B_fab" style="position: absolute; left: 0; top: 0; z-index: 1;"></canvas>
|
|
<canvas id="B_slk" style="position: absolute; left: 0; top: 0; z-index: 2;"></canvas>
|
|
<canvas id="B_hl" style="position: absolute; left: 0; top: 0; z-index: 3;"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</body>
|
|
|
|
</html>
|