1
0
HyperNet/src/electrical/v2/DAC/bom/ibom.html

4710 lines
266 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": "F", "offset_back_rotation": false, "kicad_text_formatting": true, "fields": ["Value", "Footprint"]}
///////////////////////////////////////////////
///////////////////////////////////////////////
var pcbdata = JSON.parse(LZString.decompressFromBase64("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lLyZMVkd6fZGGSiLjoCQyVnaWWKZulkwtLtZLVnQmW4Z7VlSWflZiJkDmcAZw5lWWeqZZVkqWX4O7OnjENIIFDo6SfVZwenpWRFZ2AA3WeaZQxmGWZoZxll/ZPKZslmPmUVZTRlqmRiZtllYmfZZIQCnGZ6Z+JlUGT6Z6OnIJCAA9BleWbNZGjIvtgUCF1L1FAFZ9FnbFAhZrTBrWbTpjBhlaXL6EpnRLtFZpwCxWbDWBqGCmcz6vdCTFPmZ4wDA2dtZkVlAWQZZ91lQ2R1Z6UD9mR8Zg5kYWbMZH1lcNBOZ31mzWW6kQ6iTNlOSBpmFGWcoOlkVaZlZ4NnC2VUZWhlVADJZgbhyWXaZz5l9We9ZyNkumXZZpBno2biZo1kkWT6Zvpk46R5Z5JlTmfJItmD27HRZIQCxmV524IA5oMxZxWnjfKwA43ybGSzZ1gAd6bWkw5Dc6v7ZrJkqAKwAG6APGTrZzgC7AAQAAQC7AAiAhtk6GRUAtln5lM4ZSdkp2WnZTgDZ2ZeUchnIEHHZWMgvWWkZJVmL6VIAGHaa6eVZ2pkfmW7Z9x7dGQSQrAAEkAnZYll52anZ6dldWc9ZktmvWS+ZLelvmcpZFVmkgLIIzdksmSEArdnYAO3ZpRlC2V3ZBdlEgGZZUtkWWTLZtdkj2VF4g1lo2acAGNlOWcRZ4WkO2e5ZbAAE2TNZPFmwQC+k0OK1eJ7ZWWnDzMFZeyD27HIZyWGpmT9IIdk8meIZh1mSGefZ3aQqQCIwtNlpALHZ7JkOGVoC89krmfnZPdmidBiARdlAgLnZoDnd2YXZltk52UmZckBlaZMUPVmm2bvZGek12Uvpp9ndFOJQ3aTSUAUZIJkAOXJAHdkwOWwAydlwOUvZr3iQOQg5xdlxGRQ5i9lQOWsZxDkqAPMAaDnS2UjZRIC12X8Z1bhf2TBkl9mhWZZAZdkD6e0CIDnkOWA58DkQOVnZtDnQOfQ5EjlEgImAiDmFGcg5gDlsOSbZHDn9WSWAWDl12V9ZPDnRcDpglsgOYIQ5MdmogOEApDlyOZQ5GdlQKAo5+HZ0OdsZDDngOYo5xdlIOSw5qDnqOavZnDnaOXo5g4CfshfZRjndGaxgqZmTgOY59jnyOVY5NDkgAE45sjmhOZY5MjnMOV/45dn92ZXZMtlaOWwA3Dlb2dbZO9m22VjZLlnOAOjp80BTWS7Zs1lIKN3kjByLWfSZVNkdmTTZJdn02eyZjNlh6aIZb9mZmZVZJTkf/je4gNl82Y1ZINm76XEZd1l62dDZWIBWObAAxtnoWR45mjljmXLZ9dmqWS05k3jM5nxCHTma2QgZPTkWmTKZuVmxgEM5IzkI2aiZ4zk2WZbZqNmZOZYAu9l22QfZrlnRaVQAhTmhmZcZF7CT7pas5TmBWTlpIVmT2acAYVlbWcoZVWlNOdxZ/xkXPIm8fmpq2UHpQllXWcA5WxkQ2SLZ1RmPWTaZ3VnuOcVZKTkTOQdpUzkK2Vc5YaI/OXvuF1n82W85wLm62XsZ1pmw2UbZ8Nkr2dC5nDm7OZE5VtnumY5Zxzk8qs4AJCgAAKIAACJBmcfZ5Fk4OTUB8x5UgB7ZtJlLWVOc4IBAIDzZSZl+gEE59TkiWZxZHzkf2cEZcOLtgeCegNkC4r6od2liOa1ZElkPWXlZEiwbOXi5A9lm2UPZ1lkb2dM5oJ5YYLxgD9mpWXfyZWkiOaCAollkOXK5kNlguYq5zsK92Q+ZSJmquRg5vxkZOaS5I1k5OWNZrlkkKGRZ01ls2bR2ImqPQjue19nnmQ85zJl/OTHZoBBsWa/Z+1nv2azZlFnIJohSB4R4hLzZBqRouY4ZGLnSmW1ZotmPWa9AOLmHAJs5+LmI2Ts5mrkIuUUBeEDyAsNw8bn6udEIizkg2fpZqbnyuem5eVmZucq5trnJOYS5zpnEufs5TrnN6eS5RJnSQBc5hNmVWa8iuawKCHc5lNmBuUt8gjmhueFZAtmIGaHZXrlK0fxMFnpW6k85+ewAuUuZidkoGas5CrlymY25FdkKWQRZpVmTObo5CxmjeAO5layFcH/ZcBlJuYPp1bnruWm5Frlbuda5cNlNubu5VdlOmY65w1mduS659tmnOdqAvblMub0ym6L6llQW5NkcuYyZQbnnuc85G1nsma85ybkzuR3p4clreEB54HnLuZW5U7nXudlZtbl3udi527lJOc+5MLk6OaPZTspfCAh5h46ouV05qHmyuX05WLkmWRC5fdmFWbm52znm2ThZKNl4WTbZBFlduT6ZmYAEAIgALwAFaQVpgQAQAGCArRwiAEWANLnnOc7Zlzmgnsgoo7ppaey59Jnp8lwa8ZljAH30SHlFBFMQkaz2oI4s4blcNAdZWTl7OSx5unlkuZ+5JznOANQZ9Ln42Yy5s7mqpJ4EGNTxGsO5XtltYbGZ7KZIeQAwZMCuIOmZwrlRuezplew+amxxwbm2Gb2m8BndOWh5ZrmgufrZiErL2Xa5ilkEGQW53jmXTlo6dmiXHsw5AXnv6Us5wXmUeVaZ/+mQuaM5BLk7ObF5SPhaOl9U0dn+eYm5lkCruZ3ZN7kYeWF5IOgRec25uXlHuX14N05xtJyQSHmvIg2ZRrk8AMs5ILn9OR1Z1XlZeVs5b1nqufMZf7lNTolEnzTNeUl5JXnteTvpaXmWmWs5mBm0eew5YzmMee+Zo3hVHE15RXmRGcl5pXmpeRR5s3mbufN5Nrk7ub1Z9rlOmfV5Z3iJkOt5txl9UFvpQXm7eRu5dbmn6Yd5OHnHeVF5p3nDeQ14BFgI9Bt58hlbeVN5iBm3WXt5D3kHeY+5R3noOa95b5l5eQkQpHSg9Fd5v3lleaa56XlzeZl5C3lQuXm5y3l5eUwUl3lLua15N3lTuZ15mLkZeXFyNXm4eS25Z3kV7FsYWPl+eZt5k3nw+b05gPmYecj5T3l0eZF5e7m/GWT5gCT4ur55LXnXeYF5ePkzefd5DPlE+X159HkDeecZ7Pkd7JpUMPnY+Tz5KXm3eSm5FXnmuVV52HnM+bV56Pni+Zj5PnmJeS45cPk7efL56HmK+QM5vXko+dl5aPmDea0ZR1lQ+doaXPkTeW15tPkrObe5SvkPubi5T7kveaz5b3mWeR955lrHSt95OPm8+cWZd3kO+Yb5yvmLeTl5avnvef14mnCa+T75MvnbeXL5APkC+Y75Etkq+ST5dXnh+Wt5Ufmw+TT5uvnx+YH5PXnB+aj5DHlm+dg5HvnneKN5CXnR+Tr5cflrufr5oXlB+U752bkquar5RfkreQ15SUwZ+dL5lfl8+QH5lXl1+Un5Ifmm+ecZb7mseYZ5RFnY2a5ZAZkeuUU5jdkk1tWOmYT+ud7ZjFkJmd0ZKZnYAGmZuvmwea7ZM/k0jHmZ+rkLmfQAdvnAWWuZVZlgWboCEFntmVeZHBnn+YhZ8FkdmYCi3ZmtmX2ZxPmu+S+5w9mfWQR5/ITZmdymQtZIeZUof5kH+fKAq5kVmcf5B8YItKeZrYC7maw00FkXmZz40FlgBYXsAbk3mRf50AW3mUC0+fkm+YX5YvnveZ+ZCOpzmbv5f/kIGYBZevkgAIAFoFkgBaf5c+lIWTAFcFlX+bAFMP4oBV2ZdAUP+ahZwvks+S/51lmtua6ZQ1nD+c65o/m5OdsAkWmMAL+5HvmpkcQa5+STFPP5y1m3+atZNTkTudB5QLkb+aK5wgZd7Iywkrkoeei5Ofk9+WLZNHlM+f35GAXReW/5DdkufF4mYgWqBZdZITldeVR5MNloBf15g9mD+cx5XAUGeTwFzlmuuc4Avplb/uJ5fbmbeOBMavZ7ePP5ftncGX7Zy/knYEHZwPhz2XtZ2nmRuWHZkBlIsD4F33kboGXZQDmiOUQFDjmSOf5kETlROaa5KQU2OUo5dNn06Yk5yfnP+TC52jkxeeL5CaqhcngyLdkAObPZVbmyuVkF1gUi+bYF+gUHue/5VnkxBS72e3hyGdPZ1QXkeckFYTn1+S4AObmsBWvZsLny2RwFJLnvuRQZRnkUufwFeNkn2R75Jfgvvq2cpzB2eVlpkgWPOVT5JWmQeWG5nJlCuRG5zTl69g+4V77LBUu5DVnCWQk0Jrl0+Qn5AzlPWToFBfmi+U0FcLmHue95x758wIecWDykeWcFxrndadX5IXndeeC5WbkDBY35Kfno+UP5jgUfubwFLgX8BUFAQgVweQEoRwVYPBIFo7k3cOO5GtyTuei5CgWLGQvmknLtmKYFl7lJBRoFBvlaBQCFwzlAhYUFhLklBeH5om7YhTGCuIVkeeoFPwWI+ft51HnEhYMFTfl2BXp5DgWHOdk5EIVfua4F4gAwhYTp5wAOMBPZwHn0mf4FvtnCYN95gdl8AKEFNQXhBTVp+wXqgO8CPmB6uetZvwDx2WEFLVl1Bf0F6QW2OdE5pZl9BcS5OQUx2XkFlNS6BfcFxhnFBQYFWrlKhdfAKoXfeV0FrDmahT8F2oV9+XcFjQWBGRSFHvlChdvArLkOhVUFToVyhVqFhoVP+WD5bvmZGevZ1oVelKCFXIVseVMFGOlmeXMF0bmn+Lj8g7grBQG5yzDNmdU5vLm1OQhA7nl7BZ85964D4vbJLeI/+UIAagUNOd35hIWPWfUFQwXkhVGFsXkgtkFyZIYbBRrZZgXZ+QyF9PlheeLZoYUaOSCF9gXb2bGFI/nOBbyFUIX8hR4FzwXJaWdsPCgIhbJ59zmgeWO5S7kvOexZMHkeeVEFORkHiPn0M4U8uerZQNl0hcm5BIW1+USFtYVshQ8FowXs+fWGJfTbhbSFnwUDGZ2FVwXHhf0FJIUu+WGFbAUDWQOFBzlHOfGFONn8IAKFormlJhhQ5VTphQyZvwBZhTuFdNm+iHmFCBkQgI05BYUiuZiFAEUkiMKZ5bkVhagChAWHhX8FeVknhcCFzflehXB5iEVwCFFwZYWdObeFOADoRfeFufk1hU+FrIU4ReyFbbn6eUOFTgX72dMFbADo6R+RE4Ue+duBobxHZOT4iIWZhZk4gjmQRa4k+YURBYqFyEBsYt3keIILOe2FVfnleTX5mEXrOdRFpIWvhXh5eEWMGRJFAtHGOZJ0JEWAuQk0+Pk1udWFWEVKRS+FfYXN+WMF7bkTBZjZPIXGefwFMkB/hZiFAplsDAMUfEWMWWB5MgWohXIFSQUYhSg0SgVjeeBFb+n7hUC5GEWWBZ1ZboXoBRaFr/nNBYYFhHlDdNmQN4W6RRCZRAWMhUD5zIXYRWSFuXkxhV+F1kUsRSAA6OmT+RJ5IATS1KU5dSCsGXOFI7n8RRMggkUJOQK5CTQwRe85cEWeee0ZRUUf/ml4JwXlhTJFU7nkRXJFvwUhRT2FLAWnhZ6FDYXs+f7wk+R6nFpFiAI6RcwmXUUI+V2F1wVpRSpFLbmZRdyFI4U2RaxFQQEcReHZNdgt/Hv+pUUU2V7ZlTlgRVVFDNmU1E6CdUXyhTp564UfmVtF5gk4hrzZqEUJNNNFlwWURUZFYUU2BWq5+7mPBS0F6UyV/FCgM6R3RR1FToKPRfb5mgVURa9FDQXvRQ65H4UduZMF2UURaZx53Hm8efx5gnkaiMJ5VLmzBRZ5cHlaaCCytFIyhPP51qTAsly5BhjUstj5k4SH8OqFVfILYFp5CoUOWZwFg4VZRStFOUXUGe4FDLmeuXB5VnJWwa5EfgV87NwZa/kbBYIZbdmQRFTFF0XCBdTkL/5AmRsFoJmBhT0FwUWE+cEFxkWg+aZFH0Xnhe95xoE5bjcZ0vnFGVLF9IXdRclFgvlyxWDFdYWp+SLF3MWyCuEZGsUNmYkFiUUyxUj58Jnyxc95C0VGxfhFJsWC5i2F3PmaxZbFd4U6xbNFPXkshcpFisVs+SrFG/KScvkZV3nuxeYFBPk2xfrFvYVLeWZF7Pnp4SLBZsUSxVEZWsUHhRRFIMWvGXbFBQUOxWH5wgVBxdcZR6TMOWHFzoVexQ+FUlkK+NHFofmxxYHFBrn1SuLFbsUWxeHFBkVHhWXFvsUmRTHFdEW0xZ+Fy0XMRUSZ/AD2RSg0VuStITiFReR7RasFSIXSBTmFsgUrhYK5sEWiRYWFjuLAkPCF/kUXuYFF5wXfBSXFz0X3uQbFA0WRRZ9F0UV1YgSwS8XxRTK5SUXexf8F80X+xa+5UMWWRXvZY/nOABNZ/cXeueahgHa7RSB5rkWLhRsFy4VCxZEF8wWbhfZ0L8XHxcXFM0WlxXlZ2gUg+fbFl8W7xcrF8wVZCfn0ACVtRSu5QCVPRenFW8UVxQP5kMUchXTF3cV3xdsA+TmJhRjFU5nA4amFhtx8RaBFAkVLhbmFwkXr+WuFHvlxQuoK18F/RShFAMWVhafFICWKRdvFtEVnhfC5sXl0JcIKrsX/RXiFoID6RQr5zcUvRWglegVXxZglXcVxhbDFP4VieSzFU/mL7smxKBym9qQl1NnLxRB5QkU1RYlF3kWtYZ1ZKcZaWUwlgiWexcAlm8VfaRfF7cVcJU8FnEUewBlawHzSRcYlLx7WxUyFBtmZxeaFHoUQ+UtFMiUMxUSZ0QCPxRTSqM6HBr851nyjxRmF78XIhRQlU8XfxWJFWtLsAci5GiXIecwlQUVpxYZFqCX9RZwlg0VRRTaFVeH1cPElgCVBhSkloiVpJcb5b0UneZ4l18XcBeCFPiU42U7ZCiUFRfRxd+C+UWPkaiVVOQklYGDHRSJF1MXwReYRX5RtOebKAiWrxUIl/PlmJSZZFiWVxUrF3CXDRbqZiW4dBUYlgyUdecMlKCXmJW4l7oUQxZIl9EWchfTFPcXjWWoA/iVzcQB55fnARWsFbkWTxR5F08VeRTQlcHm+RYclCCX3RVbFhSUKRVh5KyXhRR4lGrlDRSrFI1zt+a2Fe4WkRQIEziUpRVYFzyWlJeD57AVeJcOF2yWnOexFdSWeBZ4RqbDTyscFooXzheElE8XrWVElYQW6JaBILfzDxd8liCUFJRvFSyWpRUCl4MVlJW8lWSWFuZ4RL/zwpe8F+rm4pdLFDyW9RWAlzvkKxZYl6yWdxdDFVkXVJa5Z+Tn5RTCl1uwvpm05nMVlRftFXcDqJUdFdTknRSwlGKWJeOhUlUq4FA4l8yXTeVWFRSXLJRwl6UXLeWpFs1kypS1FLXgDJb8lwiXyRb1FYyXoJayl4wWVJTDFnKX3xd8AeyX25DeOYqpskEcl48VxBVsFaIUwtGdFUqU2pZfGt3iMxB8FCUU8AEDFFgWyxTcF4CVZxZAlpKV7xdklEP62pU2B8qo+pVNFemT/JXrFQaVMpRAlLKXlJVIl7KW3xXwFbAC+mfglrMVTmZLx96Tr5IzE8/m32TzFhREBOaD0z9lvsNEl88UjHraQicae8G7FKDmNxbA5jDk6hdI5RoV2OQaFsTmdpdA5Ljk3BlLF7iVrJaOZXjlxxYSc+DnvqN6l/aXNpUglMTltpVI52QVdpQAFhoUZBdOlqjnMpeMl1dlpOcX54dkFpfw5AQaCOaY5sfl0pd1FroVpBR2lGQUWOfOlq6XKOa45ajkvJcOl2FlWhWSlsXnnHDcGlAAHpRQlR6V/ecF5Z6XUOReleoWZBSulgGVrpSQ5G6XGpSOl26Ut+UyShaWfpRsFgTmr+cE5s6XdpfOl56WLpfqFy6U9pTelRDkJOWaFqyUkperpXjlgpUxFOCVsAPDFPHl8eQEAAnlCeUWAD8UbRfmlC4AVOniE8/np8oO44YAMmfqm33nDzAhwR6VbSPCgPQWh2cRlVSUQpc4A5GWIxVRlyMVkAAAAgqnSVLnWpRgW1UwmeiEl5OkXsYJGCFkn6qw+nQUy4FMMZWmDJPQWU7lupWuFQmXmpSJluCXQhfRl7RkaMiXGqiVCpWPFFUXZhetZWiUSpfIFlyWMGeK8IUSm9rqlvqVOJfSlgaVGpRIlUCWTJe95KeicZjOQ8qW/JYslqSUqpeIlEUWgpRUlYIUmZaRlUWmZANalY8kq0RbaI8VvxcFZJyWopWclNaXdJci8c3oC0dNxsaXIZRHFLiWhRTFlryWy2eGl5KW9MvSITYElZTSldyUmJcglUWWEpaql2cVmRcZlHKWmZaxFzMXmeXmlORlCmOGkPEUOpfZlbSWUJdolCyX1RXPFBWXFuCNly+6eZXMleqWRZcqloyVEpYbF6qXvJfMFi2VHceNF+eyTRR2F+KXtZa4lnWWhpe+F6aU3xex54/k8pc8FWobESPBuLGViENwZz463GQnAd0DJ/P+ZqAKGZQ1Fl0XhuA9lv2Dwbsw5DfyYQHGla2WPJSZZAIW6hTnZV6WOOSBlt6XTlHTA96XApeGFT6VQZRqllVmkAuuQL+m3paDltXiAxfGlLoUhhf+l6GVAZVhlCOVEOUjlGgJDpQRlqTkgANw56vlBkkDlB2V/gAzZ4OW1BSTlEPgw5UulC9nw5caFthnU5a0CtOUgpYRlUGUY+czlbZC45UQ5+OUc5b0FPaVoZUw5cOWSOdhl/9lC5SjlxKWi5fTljOXh+ZIoj2Ws5ZhA7OUEBUTlp6Vc5fKAPOUYZXzlKuWU5WrlZWnC5fhlWuVcOTul7Ol65b0IBuWy5cblv6Vm5c4AFuXk5delNuWC5XblGuVbZUX5o6UfJTGg+uVXeR7lINn+pZhlqGWk5Urlc6X85c45iOVB5eBlAWXo5QzlzuWiuY5FbuVR5UblMeUm5X7l4DmK5XE5yuVk5S456uXp5bFlYuVZ5dBligSA5VLl7uUF5Z1FReXl5eE5AGWw5Unl1uUC5ZEZVeUppZulloXi5ReF1HCR5dL50eWt5V7lCuUJ5WXl3eUV5anl7Jn25Q+ldOVO5fXlEsZ74Hnl4+Ut5YTlU+Xx5dzlneW85a2lyeV9pQvlyOXV5dVl2uXZ5TxZFnhj5UnFE+U75Zzl0+X75WTl7eVxOZXlaeUD5RBlmeU65fMFN+Wb5Xfl2+UAWW3lc+Ud5S/lIBVv5aflNOUO5WjlteU/5UdZhGi35dz59+VAFbvlJeUz5b2lxeU95SnlVOUf5SGlqaXf5Vflo3gIFf/lSBWAFWhFwBUoZWgVz+WJ5ZQVWBUn5TgVi+XB5TvFBBVr5c6+1aQMnsDlLjnIFeQVqBWpBegVl6XgFRgV7+WMFeflj6WwFUx5V2Vmpb1lSWXo6eOF0KWThZt0xCWvxRU5IqWtJWKlUEUg2b9lc2WNRTxZp7ynhkI8B2VthY4lq/kUFeVlAKWDOZtlzBU1ZdAllFl6Fb/+jCW7hUdlheUQ5YallhUZJWmlGyVYJd4lfWW5RX3FFmWVWawkXZIRtuWhMnmhJSBFoqUUJU5lzCa7We6lHHhpmlzZKgVtRU4VU7lg2Sdl62VnZVVlYhV7aZjlS0Yk0Gma2krhZd5loNnNWb5lkcV9RSUlmuUwFRbZnhXSJeClSWXUGUfZg2WKJSoOupCUavIxyhUxmTjsAQVg5Uu5jkSUgFLqzCZaFV0lOhV/cReWoTSG3I/ZsTQqQHLlCaVheVa552X4FdYVQWXzBW7MIcaGcIYlhRmlIJtZMxWlFRVl8xWZFSvla+UYfrs6M5ATFUmZWxUMgEIAOxVpFZDl7ZkLFYPlEPkXhSQcaxWriUu5FxXTFZ7lSqW3FZVs/mU15dUVbKXXZd+FrlliZZRl1GVMADJlXwDyZaYmW+oJJoil9Fnr5Es06mUzAhsVxWkntIEsumX7mE7MBmVM6YJl8WWMRcJlMhWNFUmFjBkeqQKlHRXlRWQllUWRFdVFzmV6RbPFwxX/ZbJJBkyCSdLlMTTJFf75rCUjJRkV6SVqpbhFO2UUmaSV9smtRd8l7JUsJbMVc0VuFbyVHcWmpQll0hVZpVFp3kCpZbnlrrQR2splKhULhREln8XOpZ5FOiWuZYoFnPCKtKqVpWV4paYlBKWApfcVX+VLFdYlsIVEeSqVbUnGlSelppWnZZVlPJVdZdKVFkVSFZmlkIVkZVx5FGVIxWZ4UmUMAEWAVLlyZf4V3QDQlQ+SXzzz+apln5LNmRplCSX0RDpl7Jl6Zab2p0U4lUZleJVbJYSVA2XElfqV8CT2yQXQ42WUlQ5lEEU0lYMV6ZV/ZcIFSwQZShjghhXtRcYVseVNxd8V5RW3BcvljuX4efvFOjL5lZ7JrJXaRS1lZEWmFU2VrhUWlRnll2U1FRmlN2X3xbmlzRXg1lvARg6NNO/8apVIpdllH8VIeV/FTVmzZQyVJfnmGL2gU8bLZbuFtKVM2SUVNxUMpa3FohWHFTkVnaTaeJXqzQFX4PklU7lCMeKVj4UjlX8VEhXjlYCVsiXj+f6ZRJUEJVmZJNapgt/5XMV0UoeZPrxyGSv5vMVd+edFP8Xh2Z/5at7f+b+ZhZn/+UnZIFnABZfmtZkUBTQF1AUtmdf59/mIWbhVKFm/FRflIwXLFTBV/5XH3Dv5u4V7+d9ldJW1BShVG5mYaluZhuVnmdAFF/mHmZAFWFXhgOAFbFVSBeuAFhUoBY/5rpUXZeb5m/kRmdaYuAWUVfgFzhW0VUf59FUw6gnGZ/nYVbQFsFltmYwFeFWqVQRVkpVulRgl75WelZOVZmW1JU0V9SU8uk8UY3GzAEWVERValVEV1CWVlZjFnB5LZSiVbJX9lf95uxXmFS2VwaUi5VUVxFXWlYTpJ2yHWmGyhRVIVSIlzZWEVVkVb5UAlbpVQJWWpT+VQ2U8WQV82zb2pZll6pXIpU6laKWaFRWV2hWMlcW4cVXzqarIZYWHlSgVXxWnlSFVF5X8lZIZ2VVHcTGlzWVJJQ9Fg5VBVUVVmlVCVWFV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KWXitZk1xDUUAAI18jVSNRAAOrVUuTw1LeogANU1NLmRaWCAeNXQtRAAW2n/Nfx1ajVl4OU1AABqW2lY1Vw1uzVSAKnVOjXsdeB1nHXGtXMZcTU5tS+1nHXWtXMZUmXYKBI1BiAiALGZ3KrSNU01PBnHgJwZzTW4dv6ZxAAkmfMAqkBNtaB1pnXptdp1u7U3tXB1R7XmNde1hzUHtUx1EHVsAKyA/7WbtTR1/nVsACVAXbURdd+1CXUgAHxAaul7ILB1cXUcdWl14iDJtcF1zHVSAKoAaum+dfF1UTV+aSWA5ezS1U7Vo0By1bnVztWRaUrVRdWRaarVe9WRaRrVb9VnOZvV7XXmZav5EdWXNXHZXtXRaSbVs9UCBebVDtVW1bvVNtWgNdFpadXDdeA1C3Wu1XV1E1ke1SHV3tWb1ZVAsdVV1YHV0WnB1cN1YdV8ABHVUdWg2VfVs3WTWZSAB3VJ1ZmUs3Wp1UHZ7XVWpdHVp9XLlLlFJtXrdQXVbdk11SXVdXXo6eXVP3VV1YqgldV11bPV+TmN1a3VLdX51W3VJhVP1XMZ+TlO1c7V6Om91Qj1g3UMgIPVfiXR1QvVoDVsRbvVIPWKAGnVIDUvdbjZBwAg9R1VjWCL1bnVCdX5OavVHdWgNRvVUQAE9c/VO9WpmV7VB9Vx2c91jPUn1TD1+9W31Wd1L3UvNbfV7PWw9Q/VUQBc9b6Zr9WANR/VRdWO2QcAP9WgNX/Vm9XrdUA10dUM9XMZvpngNTbV3mno2X5p3rjbNfAAaNX+AIWAfmlceZWZ8AA8NdtpRHZ1gNsAKCj0PDcAv2hAAAA="))
///////////////////////////////////////////////
///////////////////////////////////////////////
/* 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 : "&lt;no net&gt;");
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&nbsp;" +
/^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>&#176;</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>