2025-02-17 18:54:45 +01:00

4670 lines
267 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;
}
#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;
}
/* #bomhead {
position: sticky;
top: 0px;
z-index: 1;
} */
</style>
<script type="text/javascript" >
///////////////////////////////////////////////
/*
Split.js - v1.3.5
MIT License
https://github.com/nathancahill/Split.js
*/
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.Split=t()}(this,function(){"use strict";var e=window,t=e.document,n="addEventListener",i="removeEventListener",r="getBoundingClientRect",s=function(){return!1},o=e.attachEvent&&!e[n],a=["","-webkit-","-moz-","-o-"].filter(function(e){var n=t.createElement("div");return n.style.cssText="width:"+e+"calc(9px)",!!n.style.length}).shift()+"calc",l=function(e){return"string"==typeof e||e instanceof String?t.querySelector(e):e};return function(u,c){function z(e,t,n){var i=A(y,t,n);Object.keys(i).forEach(function(t){return e.style[t]=i[t]})}function h(e,t){var n=B(y,t);Object.keys(n).forEach(function(t){return e.style[t]=n[t]})}function f(e){var t=E[this.a],n=E[this.b],i=t.size+n.size;t.size=e/this.size*i,n.size=i-e/this.size*i,z(t.element,t.size,this.aGutterSize),z(n.element,n.size,this.bGutterSize)}function m(e){var t;this.dragging&&((t="touches"in e?e.touches[0][b]-this.start:e[b]-this.start)<=E[this.a].minSize+M+this.aGutterSize?t=E[this.a].minSize+this.aGutterSize:t>=this.size-(E[this.b].minSize+M+this.bGutterSize)&&(t=this.size-(E[this.b].minSize+this.bGutterSize)),f.call(this,t),c.onDrag&&c.onDrag())}function g(){var e=E[this.a].element,t=E[this.b].element;this.size=e[r]()[y]+t[r]()[y]+this.aGutterSize+this.bGutterSize,this.start=e[r]()[G]}function d(){var t=this,n=E[t.a].element,r=E[t.b].element;t.dragging&&c.onDragEnd&&c.onDragEnd(),t.dragging=!1,e[i]("mouseup",t.stop),e[i]("touchend",t.stop),e[i]("touchcancel",t.stop),t.parent[i]("mousemove",t.move),t.parent[i]("touchmove",t.move),delete t.stop,delete t.move,n[i]("selectstart",s),n[i]("dragstart",s),r[i]("selectstart",s),r[i]("dragstart",s),n.style.userSelect="",n.style.webkitUserSelect="",n.style.MozUserSelect="",n.style.pointerEvents="",r.style.userSelect="",r.style.webkitUserSelect="",r.style.MozUserSelect="",r.style.pointerEvents="",t.gutter.style.cursor="",t.parent.style.cursor=""}function S(t){var i=this,r=E[i.a].element,o=E[i.b].element;!i.dragging&&c.onDragStart&&c.onDragStart(),t.preventDefault(),i.dragging=!0,i.move=m.bind(i),i.stop=d.bind(i),e[n]("mouseup",i.stop),e[n]("touchend",i.stop),e[n]("touchcancel",i.stop),i.parent[n]("mousemove",i.move),i.parent[n]("touchmove",i.move),r[n]("selectstart",s),r[n]("dragstart",s),o[n]("selectstart",s),o[n]("dragstart",s),r.style.userSelect="none",r.style.webkitUserSelect="none",r.style.MozUserSelect="none",r.style.pointerEvents="none",o.style.userSelect="none",o.style.webkitUserSelect="none",o.style.MozUserSelect="none",o.style.pointerEvents="none",i.gutter.style.cursor=j,i.parent.style.cursor=j,g.call(i)}function v(e){e.forEach(function(t,n){if(n>0){var i=F[n-1],r=E[i.a],s=E[i.b];r.size=e[n-1],s.size=t,z(r.element,r.size,i.aGutterSize),z(s.element,s.size,i.bGutterSize)}})}function p(){F.forEach(function(e){e.parent.removeChild(e.gutter),E[e.a].element.style[y]="",E[e.b].element.style[y]=""})}void 0===c&&(c={});var y,b,G,E,w=l(u[0]).parentNode,D=e.getComputedStyle(w).flexDirection,U=c.sizes||u.map(function(){return 100/u.length}),k=void 0!==c.minSize?c.minSize:100,x=Array.isArray(k)?k:u.map(function(){return k}),L=void 0!==c.gutterSize?c.gutterSize:10,M=void 0!==c.snapOffset?c.snapOffset:30,O=c.direction||"horizontal",j=c.cursor||("horizontal"===O?"ew-resize":"ns-resize"),C=c.gutter||function(e,n){var i=t.createElement("div");return i.className="gutter gutter-"+n,i},A=c.elementStyle||function(e,t,n){var i={};return"string"==typeof t||t instanceof String?i[e]=t:i[e]=o?t+"%":a+"("+t+"% - "+n+"px)",i},B=c.gutterStyle||function(e,t){return n={},n[e]=t+"px",n;var n};"horizontal"===O?(y="width","clientWidth",b="clientX",G="left","paddingLeft"):"vertical"===O&&(y="height","clientHeight",b="clientY",G="top","paddingTop");var F=[];return E=u.map(function(e,t){var i,s={element:l(e),size:U[t],minSize:x[t]};if(t>0&&(i={a:t-1,b:t,dragging:!1,isFirst:1===t,isLast:t===u.length-1,direction:O,parent:w},i.aGutterSize=L,i.bGutterSize=L,i.isFirst&&(i.aGutterSize=L/2),i.isLast&&(i.bGutterSize=L/2),"row-reverse"===D||"column-reverse"===D)){var a=i.a;i.a=i.b,i.b=a}if(!o&&t>0){var c=C(t,O);h(c,L),c[n]("mousedown",S.bind(i)),c[n]("touchstart",S.bind(i)),w.insertBefore(c,s.element),i.gutter=c}0===t||t===u.length-1?z(s.element,s.size,L/2):z(s.element,s.size,L);var f=s.element[r]()[y];return f<s.minSize&&(s.minSize=f),t>0&&F.push(i),s}),o?{setSizes:v,destroy:p}:{setSizes:v,getSizes:function(){return E.map(function(e){return e.size})},collapse:function(e){if(e===F.length){var t=F[e-1];g.call(t),o||f.call(t,t.size-t.bGutterSize)}else{var n=F[e];g.call(n),o||f.call(n,n.aGutterSize)}},destroy:p}}});
///////////////////////////////////////////////
///////////////////////////////////////////////
// Copyright (c) 2013 Pieroxy <pieroxy@pieroxy.net>
// This work is free. You can redistribute it and/or modify it
// under the terms of the WTFPL, Version 2
// For more information see LICENSE.txt or http://www.wtfpl.net/
//
// For more information, the home page:
// http://pieroxy.net/blog/pages/lz-string/testing.html
//
// LZ-based compression algorithm, version 1.4.4
var LZString=function(){var o=String.fromCharCode,i={};var n={decompressFromBase64:function(o){return null==o?"":""==o?null:n._decompress(o.length,32,function(n){return function(o,n){if(!i[o]){i[o]={};for(var t=0;t<o.length;t++)i[o][o.charAt(t)]=t}return i[o][n]}("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",o.charAt(n))})},_decompress:function(i,n,t){var r,e,a,s,p,u,l,f=[],c=4,d=4,h=3,v="",g=[],m={val:t(0),position:n,index:1};for(r=0;r<3;r+=1)f[r]=r;for(a=0,p=Math.pow(2,2),u=1;u!=p;)s=m.val&m.position,m.position>>=1,0==m.position&&(m.position=n,m.val=t(m.index++)),a|=(s>0?1:0)*u,u<<=1;switch(a){case 0:for(a=0,p=Math.pow(2,8),u=1;u!=p;)s=m.val&m.position,m.position>>=1,0==m.position&&(m.position=n,m.val=t(m.index++)),a|=(s>0?1:0)*u,u<<=1;l=o(a);break;case 1:for(a=0,p=Math.pow(2,16),u=1;u!=p;)s=m.val&m.position,m.position>>=1,0==m.position&&(m.position=n,m.val=t(m.index++)),a|=(s>0?1:0)*u,u<<=1;l=o(a);break;case 2:return""}for(f[3]=l,e=l,g.push(l);;){if(m.index>i)return"";for(a=0,p=Math.pow(2,h),u=1;u!=p;)s=m.val&m.position,m.position>>=1,0==m.position&&(m.position=n,m.val=t(m.index++)),a|=(s>0?1:0)*u,u<<=1;switch(l=a){case 0:for(a=0,p=Math.pow(2,8),u=1;u!=p;)s=m.val&m.position,m.position>>=1,0==m.position&&(m.position=n,m.val=t(m.index++)),a|=(s>0?1:0)*u,u<<=1;f[d++]=o(a),l=d-1,c--;break;case 1:for(a=0,p=Math.pow(2,16),u=1;u!=p;)s=m.val&m.position,m.position>>=1,0==m.position&&(m.position=n,m.val=t(m.index++)),a|=(s>0?1:0)*u,u<<=1;f[d++]=o(a),l=d-1,c--;break;case 2:return g.join("")}if(0==c&&(c=Math.pow(2,h),h++),f[l])v=f[l];else{if(l!==d)return null;v=e+e.charAt(0)}g.push(v),f[d++]=e+v.charAt(0),e=v,0==--c&&(c=Math.pow(2,h),h++)}}};return n}();"function"==typeof define&&define.amd?define(function(){return LZString}):"undefined"!=typeof module&&null!=module?module.exports=LZString:"undefined"!=typeof angular&&null!=angular&&angular.module("LZString",[]).factory("LZString",function(){return LZString});
///////////////////////////////////////////////
///////////////////////////////////////////////
/*!
* PEP v0.4.3 | https://github.com/jquery/PEP
* Copyright jQuery Foundation and other contributors | http://jquery.org/license
*/
!function(a,b){"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):a.PointerEventsPolyfill=b()}(this,function(){"use strict";function a(a,b){b=b||Object.create(null);var c=document.createEvent("Event");c.initEvent(a,b.bubbles||!1,b.cancelable||!1);
for(var d,e=2;e<m.length;e++)d=m[e],c[d]=b[d]||n[e];c.buttons=b.buttons||0;
var f=0;return f=b.pressure&&c.buttons?b.pressure:c.buttons?.5:0,c.x=c.clientX,c.y=c.clientY,c.pointerId=b.pointerId||0,c.width=b.width||0,c.height=b.height||0,c.pressure=f,c.tiltX=b.tiltX||0,c.tiltY=b.tiltY||0,c.twist=b.twist||0,c.tangentialPressure=b.tangentialPressure||0,c.pointerType=b.pointerType||"",c.hwTimestamp=b.hwTimestamp||0,c.isPrimary=b.isPrimary||!1,c}function b(){this.array=[],this.size=0}function c(a,b,c,d){this.addCallback=a.bind(d),this.removeCallback=b.bind(d),this.changedCallback=c.bind(d),A&&(this.observer=new A(this.mutationWatcher.bind(this)))}function d(a){return"body /shadow-deep/ "+e(a)}function e(a){return'[touch-action="'+a+'"]'}function f(a){return"{ -ms-touch-action: "+a+"; touch-action: "+a+"; }"}function g(){if(F){D.forEach(function(a){String(a)===a?(E+=e(a)+f(a)+"\n",G&&(E+=d(a)+f(a)+"\n")):(E+=a.selectors.map(e)+f(a.rule)+"\n",G&&(E+=a.selectors.map(d)+f(a.rule)+"\n"))});var a=document.createElement("style");a.textContent=E,document.head.appendChild(a)}}function h(){if(!window.PointerEvent){if(window.PointerEvent=a,window.navigator.msPointerEnabled){var b=window.navigator.msMaxTouchPoints;Object.defineProperty(window.navigator,"maxTouchPoints",{value:b,enumerable:!0}),u.registerSource("ms",_)}else Object.defineProperty(window.navigator,"maxTouchPoints",{value:0,enumerable:!0}),u.registerSource("mouse",N),void 0!==window.ontouchstart&&u.registerSource("touch",V);u.register(document)}}function i(a){if(!u.pointermap.has(a)){var b=new Error("InvalidPointerId");throw b.name="InvalidPointerId",b}}function j(a){for(var b=a.parentNode;b&&b!==a.ownerDocument;)b=b.parentNode;if(!b){var c=new Error("InvalidStateError");throw c.name="InvalidStateError",c}}function k(a){var b=u.pointermap.get(a);return 0!==b.buttons}function l(){window.Element&&!Element.prototype.setPointerCapture&&Object.defineProperties(Element.prototype,{setPointerCapture:{value:W},releasePointerCapture:{value:X},hasPointerCapture:{value:Y}})}
var m=["bubbles","cancelable","view","detail","screenX","screenY","clientX","clientY","ctrlKey","altKey","shiftKey","metaKey","button","relatedTarget","pageX","pageY"],n=[!1,!1,null,null,0,0,0,0,!1,!1,!1,!1,0,null,0,0],o=window.Map&&window.Map.prototype.forEach,p=o?Map:b;b.prototype={set:function(a,b){return void 0===b?this["delete"](a):(this.has(a)||this.size++,void(this.array[a]=b))},has:function(a){return void 0!==this.array[a]},"delete":function(a){this.has(a)&&(delete this.array[a],this.size--)},get:function(a){return this.array[a]},clear:function(){this.array.length=0,this.size=0},forEach:function(a,b){return this.array.forEach(function(c,d){a.call(b,c,d,this)},this)}};var q=["bubbles","cancelable","view","detail","screenX","screenY","clientX","clientY","ctrlKey","altKey","shiftKey","metaKey","button","relatedTarget","buttons","pointerId","width","height","pressure","tiltX","tiltY","pointerType","hwTimestamp","isPrimary","type","target","currentTarget","which","pageX","pageY","timeStamp"],r=[!1,!1,null,null,0,0,0,0,!1,!1,!1,!1,0,null,0,0,0,0,0,0,0,"",0,!1,"",null,null,0,0,0,0],s={pointerover:1,pointerout:1,pointerenter:1,pointerleave:1},t="undefined"!=typeof SVGElementInstance,u={pointermap:new p,eventMap:Object.create(null),captureInfo:Object.create(null),eventSources:Object.create(null),eventSourceList:[],registerSource:function(a,b){var c=b,d=c.events;d&&(d.forEach(function(a){c[a]&&(this.eventMap[a]=c[a].bind(c))},this),this.eventSources[a]=c,this.eventSourceList.push(c))},register:function(a){for(var b,c=this.eventSourceList.length,d=0;d<c&&(b=this.eventSourceList[d]);d++)
b.register.call(b,a)},unregister:function(a){for(var b,c=this.eventSourceList.length,d=0;d<c&&(b=this.eventSourceList[d]);d++)
b.unregister.call(b,a)},contains:function(a,b){try{return a.contains(b)}catch(c){return!1}},down:function(a){a.bubbles=!0,this.fireEvent("pointerdown",a)},move:function(a){a.bubbles=!0,this.fireEvent("pointermove",a)},up:function(a){a.bubbles=!0,this.fireEvent("pointerup",a)},enter:function(a){a.bubbles=!1,this.fireEvent("pointerenter",a)},leave:function(a){a.bubbles=!1,this.fireEvent("pointerleave",a)},over:function(a){a.bubbles=!0,this.fireEvent("pointerover",a)},out:function(a){a.bubbles=!0,this.fireEvent("pointerout",a)},cancel:function(a){a.bubbles=!0,this.fireEvent("pointercancel",a)},leaveOut:function(a){this.out(a),this.propagate(a,this.leave,!1)},enterOver:function(a){this.over(a),this.propagate(a,this.enter,!0)},eventHandler:function(a){if(!a._handledByPE){var b=a.type,c=this.eventMap&&this.eventMap[b];c&&c(a),a._handledByPE=!0}},listen:function(a,b){b.forEach(function(b){this.addEvent(a,b)},this)},unlisten:function(a,b){b.forEach(function(b){this.removeEvent(a,b)},this)},addEvent:function(a,b){a.addEventListener(b,this.boundHandler)},removeEvent:function(a,b){a.removeEventListener(b,this.boundHandler)},makeEvent:function(b,c){this.captureInfo[c.pointerId]&&(c.relatedTarget=null);var d=new a(b,c);return c.preventDefault&&(d.preventDefault=c.preventDefault),d._target=d._target||c.target,d},fireEvent:function(a,b){var c=this.makeEvent(a,b);return this.dispatchEvent(c)},cloneEvent:function(a){for(var b,c=Object.create(null),d=0;d<q.length;d++)b=q[d],c[b]=a[b]||r[d],!t||"target"!==b&&"relatedTarget"!==b||c[b]instanceof SVGElementInstance&&(c[b]=c[b].correspondingUseElement);return a.preventDefault&&(c.preventDefault=function(){a.preventDefault()}),c},getTarget:function(a){var b=this.captureInfo[a.pointerId];return b?a._target!==b&&a.type in s?void 0:b:a._target},propagate:function(a,b,c){for(var d=a.target,e=[];d!==document&&!d.contains(a.relatedTarget);) if(e.push(d),d=d.parentNode,!d)return;c&&e.reverse(),e.forEach(function(c){a.target=c,b.call(this,a)},this)},setCapture:function(b,c,d){this.captureInfo[b]&&this.releaseCapture(b,d),this.captureInfo[b]=c,this.implicitRelease=this.releaseCapture.bind(this,b,d),document.addEventListener("pointerup",this.implicitRelease),document.addEventListener("pointercancel",this.implicitRelease);var e=new a("gotpointercapture");e.pointerId=b,e._target=c,d||this.asyncDispatchEvent(e)},releaseCapture:function(b,c){var d=this.captureInfo[b];if(d){this.captureInfo[b]=void 0,document.removeEventListener("pointerup",this.implicitRelease),document.removeEventListener("pointercancel",this.implicitRelease);var e=new a("lostpointercapture");e.pointerId=b,e._target=d,c||this.asyncDispatchEvent(e)}},dispatchEvent:/*scope.external.dispatchEvent || */function(a){var b=this.getTarget(a);if(b)return b.dispatchEvent(a)},asyncDispatchEvent:function(a){requestAnimationFrame(this.dispatchEvent.bind(this,a))}};u.boundHandler=u.eventHandler.bind(u);var v={shadow:function(a){if(a)return a.shadowRoot||a.webkitShadowRoot},canTarget:function(a){return a&&Boolean(a.elementFromPoint)},targetingShadow:function(a){var b=this.shadow(a);if(this.canTarget(b))return b},olderShadow:function(a){var b=a.olderShadowRoot;if(!b){var c=a.querySelector("shadow");c&&(b=c.olderShadowRoot)}return b},allShadows:function(a){for(var b=[],c=this.shadow(a);c;)b.push(c),c=this.olderShadow(c);return b},searchRoot:function(a,b,c){if(a){var d,e,f=a.elementFromPoint(b,c);for(e=this.targetingShadow(f);e;){if(d=e.elementFromPoint(b,c)){var g=this.targetingShadow(d);return this.searchRoot(g,b,c)||d} e=this.olderShadow(e)} return f}},owner:function(a){
for(var b=a;b.parentNode;)b=b.parentNode;
return b.nodeType!==Node.DOCUMENT_NODE&&b.nodeType!==Node.DOCUMENT_FRAGMENT_NODE&&(b=document),b},findTarget:function(a){var b=a.clientX,c=a.clientY,d=this.owner(a.target);
return d.elementFromPoint(b,c)||(d=document),this.searchRoot(d,b,c)}},w=Array.prototype.forEach.call.bind(Array.prototype.forEach),x=Array.prototype.map.call.bind(Array.prototype.map),y=Array.prototype.slice.call.bind(Array.prototype.slice),z=Array.prototype.filter.call.bind(Array.prototype.filter),A=window.MutationObserver||window.WebKitMutationObserver,B="[touch-action]",C={subtree:!0,childList:!0,attributes:!0,attributeOldValue:!0,attributeFilter:["touch-action"]};c.prototype={watchSubtree:function(a){
//
this.observer&&v.canTarget(a)&&this.observer.observe(a,C)},enableOnSubtree:function(a){this.watchSubtree(a),a===document&&"complete"!==document.readyState?this.installOnLoad():this.installNewSubtree(a)},installNewSubtree:function(a){w(this.findElements(a),this.addElement,this)},findElements:function(a){return a.querySelectorAll?a.querySelectorAll(B):[]},removeElement:function(a){this.removeCallback(a)},addElement:function(a){this.addCallback(a)},elementChanged:function(a,b){this.changedCallback(a,b)},concatLists:function(a,b){return a.concat(y(b))},
installOnLoad:function(){document.addEventListener("readystatechange",function(){"complete"===document.readyState&&this.installNewSubtree(document)}.bind(this))},isElement:function(a){return a.nodeType===Node.ELEMENT_NODE},flattenMutationTree:function(a){
var b=x(a,this.findElements,this);
return b.push(z(a,this.isElement)),b.reduce(this.concatLists,[])},mutationWatcher:function(a){a.forEach(this.mutationHandler,this)},mutationHandler:function(a){if("childList"===a.type){var b=this.flattenMutationTree(a.addedNodes);b.forEach(this.addElement,this);var c=this.flattenMutationTree(a.removedNodes);c.forEach(this.removeElement,this)}else"attributes"===a.type&&this.elementChanged(a.target,a.oldValue)}};var D=["none","auto","pan-x","pan-y",{rule:"pan-x pan-y",selectors:["pan-x pan-y","pan-y pan-x"]}],E="",F=window.PointerEvent||window.MSPointerEvent,G=!window.ShadowDOMPolyfill&&document.head.createShadowRoot,H=u.pointermap,I=25,J=[1,4,2,8,16],K=!1;try{K=1===new MouseEvent("test",{buttons:1}).buttons}catch(L){}
var M,N={POINTER_ID:1,POINTER_TYPE:"mouse",events:["mousedown","mousemove","mouseup","mouseover","mouseout"],register:function(a){u.listen(a,this.events)},unregister:function(a){u.unlisten(a,this.events)},lastTouches:[],
isEventSimulatedFromTouch:function(a){for(var b,c=this.lastTouches,d=a.clientX,e=a.clientY,f=0,g=c.length;f<g&&(b=c[f]);f++){
var h=Math.abs(d-b.x),i=Math.abs(e-b.y);if(h<=I&&i<=I)return!0}},prepareEvent:function(a){var b=u.cloneEvent(a),c=b.preventDefault;return b.preventDefault=function(){a.preventDefault(),c()},b.pointerId=this.POINTER_ID,b.isPrimary=!0,b.pointerType=this.POINTER_TYPE,b},prepareButtonsForMove:function(a,b){var c=H.get(this.POINTER_ID);
0!==b.which&&c?a.buttons=c.buttons:a.buttons=0,b.buttons=a.buttons},mousedown:function(a){if(!this.isEventSimulatedFromTouch(a)){var b=H.get(this.POINTER_ID),c=this.prepareEvent(a);K||(c.buttons=J[c.button],b&&(c.buttons|=b.buttons),a.buttons=c.buttons),H.set(this.POINTER_ID,a),b&&0!==b.buttons?u.move(c):u.down(c)}},mousemove:function(a){if(!this.isEventSimulatedFromTouch(a)){var b=this.prepareEvent(a);K||this.prepareButtonsForMove(b,a),b.button=-1,H.set(this.POINTER_ID,a),u.move(b)}},mouseup:function(a){if(!this.isEventSimulatedFromTouch(a)){var b=H.get(this.POINTER_ID),c=this.prepareEvent(a);if(!K){var d=J[c.button];
c.buttons=b?b.buttons&~d:0,a.buttons=c.buttons}H.set(this.POINTER_ID,a),
c.buttons&=~J[c.button],0===c.buttons?u.up(c):u.move(c)}},mouseover:function(a){if(!this.isEventSimulatedFromTouch(a)){var b=this.prepareEvent(a);K||this.prepareButtonsForMove(b,a),b.button=-1,H.set(this.POINTER_ID,a),u.enterOver(b)}},mouseout:function(a){if(!this.isEventSimulatedFromTouch(a)){var b=this.prepareEvent(a);K||this.prepareButtonsForMove(b,a),b.button=-1,u.leaveOut(b)}},cancel:function(a){var b=this.prepareEvent(a);u.cancel(b),this.deactivateMouse()},deactivateMouse:function(){H["delete"](this.POINTER_ID)}},O=u.captureInfo,P=v.findTarget.bind(v),Q=v.allShadows.bind(v),R=u.pointermap,S=2500,T=200,U="touch-action",V={events:["touchstart","touchmove","touchend","touchcancel"],register:function(a){M.enableOnSubtree(a)},unregister:function(){},elementAdded:function(a){var b=a.getAttribute(U),c=this.touchActionToScrollType(b);c&&(a._scrollType=c,u.listen(a,this.events),
Q(a).forEach(function(a){a._scrollType=c,u.listen(a,this.events)},this))},elementRemoved:function(a){a._scrollType=void 0,u.unlisten(a,this.events),
Q(a).forEach(function(a){a._scrollType=void 0,u.unlisten(a,this.events)},this)},elementChanged:function(a,b){var c=a.getAttribute(U),d=this.touchActionToScrollType(c),e=this.touchActionToScrollType(b);
d&&e?(a._scrollType=d,Q(a).forEach(function(a){a._scrollType=d},this)):e?this.elementRemoved(a):d&&this.elementAdded(a)},scrollTypes:{EMITTER:"none",XSCROLLER:"pan-x",YSCROLLER:"pan-y",SCROLLER:/^(?:pan-x pan-y)|(?:pan-y pan-x)|auto$/},touchActionToScrollType:function(a){var b=a,c=this.scrollTypes;return"none"===b?"none":b===c.XSCROLLER?"X":b===c.YSCROLLER?"Y":c.SCROLLER.exec(b)?"XY":void 0},POINTER_TYPE:"touch",firstTouch:null,isPrimaryTouch:function(a){return this.firstTouch===a.identifier},setPrimaryTouch:function(a){
(0===R.size||1===R.size&&R.has(1))&&(this.firstTouch=a.identifier,this.firstXY={X:a.clientX,Y:a.clientY},this.scrolling=!1,this.cancelResetClickCount())},removePrimaryPointer:function(a){a.isPrimary&&(this.firstTouch=null,this.firstXY=null,this.resetClickCount())},clickCount:0,resetId:null,resetClickCount:function(){var a=function(){this.clickCount=0,this.resetId=null}.bind(this);this.resetId=setTimeout(a,T)},cancelResetClickCount:function(){this.resetId&&clearTimeout(this.resetId)},typeToButtons:function(a){var b=0;return"touchstart"!==a&&"touchmove"!==a||(b=1),b},touchToPointer:function(a){var b=this.currentTouchEvent,c=u.cloneEvent(a),d=c.pointerId=a.identifier+2;c.target=O[d]||P(c),c.bubbles=!0,c.cancelable=!0,c.detail=this.clickCount,c.button=0,c.buttons=this.typeToButtons(b.type),c.width=2*(a.radiusX||a.webkitRadiusX||0),c.height=2*(a.radiusY||a.webkitRadiusY||0),c.pressure=a.force||a.webkitForce||.5,c.isPrimary=this.isPrimaryTouch(a),c.pointerType=this.POINTER_TYPE,
c.altKey=b.altKey,c.ctrlKey=b.ctrlKey,c.metaKey=b.metaKey,c.shiftKey=b.shiftKey;
var e=this;return c.preventDefault=function(){e.scrolling=!1,e.firstXY=null,b.preventDefault()},c},processTouches:function(a,b){var c=a.changedTouches;this.currentTouchEvent=a;for(var d,e=0;e<c.length;e++)d=c[e],b.call(this,this.touchToPointer(d))},
shouldScroll:function(a){if(this.firstXY){var b,c=a.currentTarget._scrollType;if("none"===c)
b=!1;else if("XY"===c)
b=!0;else{var d=a.changedTouches[0],e=c,f="Y"===c?"X":"Y",g=Math.abs(d["client"+e]-this.firstXY[e]),h=Math.abs(d["client"+f]-this.firstXY[f]);
b=g>=h}return this.firstXY=null,b}},findTouch:function(a,b){for(var c,d=0,e=a.length;d<e&&(c=a[d]);d++)if(c.identifier===b)return!0},
vacuumTouches:function(a){var b=a.touches;
if(R.size>=b.length){var c=[];R.forEach(function(a,d){
if(1!==d&&!this.findTouch(b,d-2)){var e=a.out;c.push(e)}},this),c.forEach(this.cancelOut,this)}},touchstart:function(a){this.vacuumTouches(a),this.setPrimaryTouch(a.changedTouches[0]),this.dedupSynthMouse(a),this.scrolling||(this.clickCount++,this.processTouches(a,this.overDown))},overDown:function(a){R.set(a.pointerId,{target:a.target,out:a,outTarget:a.target}),u.enterOver(a),u.down(a)},touchmove:function(a){this.scrolling||(this.shouldScroll(a)?(this.scrolling=!0,this.touchcancel(a)):(a.preventDefault(),this.processTouches(a,this.moveOverOut)))},moveOverOut:function(a){var b=a,c=R.get(b.pointerId);
if(c){var d=c.out,e=c.outTarget;u.move(b),d&&e!==b.target&&(d.relatedTarget=b.target,b.relatedTarget=e,
d.target=e,b.target?(u.leaveOut(d),u.enterOver(b)):(
b.target=e,b.relatedTarget=null,this.cancelOut(b))),c.out=b,c.outTarget=b.target}},touchend:function(a){this.dedupSynthMouse(a),this.processTouches(a,this.upOut)},upOut:function(a){this.scrolling||(u.up(a),u.leaveOut(a)),this.cleanUpPointer(a)},touchcancel:function(a){this.processTouches(a,this.cancelOut)},cancelOut:function(a){u.cancel(a),u.leaveOut(a),this.cleanUpPointer(a)},cleanUpPointer:function(a){R["delete"](a.pointerId),this.removePrimaryPointer(a)},
dedupSynthMouse:function(a){var b=N.lastTouches,c=a.changedTouches[0];
if(this.isPrimaryTouch(c)){
var d={x:c.clientX,y:c.clientY};b.push(d);var e=function(a,b){var c=a.indexOf(b);c>-1&&a.splice(c,1)}.bind(null,b,d);setTimeout(e,S)}}};M=new c(V.elementAdded,V.elementRemoved,V.elementChanged,V);var W,X,Y,Z=u.pointermap,$=window.MSPointerEvent&&"number"==typeof window.MSPointerEvent.MSPOINTER_TYPE_MOUSE,_={events:["MSPointerDown","MSPointerMove","MSPointerUp","MSPointerOut","MSPointerOver","MSPointerCancel","MSGotPointerCapture","MSLostPointerCapture"],register:function(a){u.listen(a,this.events)},unregister:function(a){u.unlisten(a,this.events)},POINTER_TYPES:["","unavailable","touch","pen","mouse"],prepareEvent:function(a){var b=a;return $&&(b=u.cloneEvent(a),b.pointerType=this.POINTER_TYPES[a.pointerType]),b},cleanup:function(a){Z["delete"](a)},MSPointerDown:function(a){Z.set(a.pointerId,a);var b=this.prepareEvent(a);u.down(b)},MSPointerMove:function(a){var b=this.prepareEvent(a);u.move(b)},MSPointerUp:function(a){var b=this.prepareEvent(a);u.up(b),this.cleanup(a.pointerId)},MSPointerOut:function(a){var b=this.prepareEvent(a);u.leaveOut(b)},MSPointerOver:function(a){var b=this.prepareEvent(a);u.enterOver(b)},MSPointerCancel:function(a){var b=this.prepareEvent(a);u.cancel(b),this.cleanup(a.pointerId)},MSLostPointerCapture:function(a){var b=u.makeEvent("lostpointercapture",a);u.dispatchEvent(b)},MSGotPointerCapture:function(a){var b=u.makeEvent("gotpointercapture",a);u.dispatchEvent(b)}},aa=window.navigator;aa.msPointerEnabled?(W=function(a){i(a),j(this),k(a)&&(u.setCapture(a,this,!0),this.msSetPointerCapture(a))},X=function(a){i(a),u.releaseCapture(a,!0),this.msReleasePointerCapture(a)}):(W=function(a){i(a),j(this),k(a)&&u.setCapture(a,this)},X=function(a){i(a),u.releaseCapture(a)}),Y=function(a){return!!u.captureInfo[a]},g(),h(),l();var ba={dispatcher:u,Installer:c,PointerEvent:a,PointerMap:p,targetFinding:v};return ba});
///////////////////////////////////////////////
///////////////////////////////////////////////
var config = {"dark_mode": false, "show_pads": true, "show_fabrication": false, "show_silkscreen": true, "highlight_pin1": "none", "redraw_on_drag": true, "board_rotation": 0, "checkboxes": "Sourced,Placed", "bom_view": "left-right", "layer_view": "FB", "offset_back_rotation": false, "kicad_text_formatting": true, "fields": ["Value", "Footprint"]}
///////////////////////////////////////////////
///////////////////////////////////////////////
var pcbdata = JSON.parse(LZString.decompressFromBase64("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hPMNc41ziPJAAUjzpIAk81kpb3Ok8kdzZPLo8zKBGPODc5TyWPPg8tTy+wA48xCAuPO083jy43Jw8mFErfmCAQzyM3JM8szzdIAk8lhIrPJo8+KA5PNdc19yHPJrc5zzG3PY8jTyPPK086fIePKw8nzz+PL882YFAvOM8kTzTPLE88jyfjGCGEDzaPIrchTyq3Mc84YAVPJc8pLyEDUIHVLyGIHS83TzMvP08/zzjflAAYTyf3NE8kG1QvIo8lc4IvN9uWzzyvMaeOCBoPKc8uDzEvKQ85LyGvM0ALzyMvMnctrycvIxALrzZgF/cwrz1HEICKTzIvOG8iDzYwDi85jzJvLY86bz6vKFKOby0vJ08kAA9PIE8+IBcvO/ctbyevL5cvrzkqVs8CwBqPKG8q34RvNi8xTyqvL7ABLzjvPU807zUPO48y7zrvOy8wTyVvKM8+7zdAHW83ryAPMaErl43vOs80DyovLs8irzHACU86rz/vNc8+A1heTO8tDyLvO88xbybvIC8yHygvPy8kLz4fL7GQbyZPM+8vbyzwAO8ibzVPLq8vHzgfPm8lrzifPB827yyfLy87ryCvLh88Tz+vMGYGnybPLp8+TzRvMZ8rHyjvJx8ltzZvIJ8przQfNa8knyOvP1cqHzgvI28iTyVDBF8lHzdvPF877zKvPi86XyWfOOgNnzCfIW83zyR3IM8nnzofNh8p7yqfJfkErz3vNp8w0AvvMg8n7zDfOZ8k7zWfM88s3yOfIt8lHyrfNyAVbyYfMe861zNvKWYx3zkfLK8+nyx8gx837zVgGx843yUPJ98hXyifP98pNy7vPV8gXyivOdAZ0ptfOj8vXy3fIN8w7zPfMB873zGvNvAZryrvKV8rnzSfKD8tXz8vItc/ny7fJhtUdyc4DRSEDz+1zR8iXz3fKZAFABDSPO8pcAO3MHctbVw3Mx83TzEAGOAEQgoACBAIdynfJHcpMplYBjcmvzLfPa8zPzG/NYAXNzs/OS1Xas8GG185YcOOBj8sbzx/Ku8gfz5fKZAYfyh3JP8lABJ/On82fzR/O7c+fyUfMX8s7IwfNX85bz6/PJ8vnym/Mp81vzmKFhIJHzHXMWAbvz9fLj8pcB+/IBtQfyL/IyAf1yH/PG84YAb/Kn8o4B7/MDcp/y5D0QNPJo3/ID8tfzrfJM8n/zCvJ38y5g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"))
///////////////////////////////////////////////
///////////////////////////////////////////////
/* 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) {
text += (output == 'csv' ? `"${node.firstChild.nodeValue}"` : node.firstChild.nodeValue);
}
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,
}
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"] = {};
for (var id in pcbdata.bom.fields) {
pcbdata.bom.parsedValues[id] = parseValue(pcbdata.bom.fields[id][index])
}
}
}
function parseValue(val, ref) {
var inferUnit = (unit, ref) => {
if (unit) {
unit = unit.toLowerCase();
if (unit == 'Ω' || unit == "ohm" || unit == "ohms") {
unit = 'r';
}
unit = unit[0];
} else {
ref = /^([a-z]+)\d+$/i.exec(ref);
if (ref) {
ref = ref[1].toLowerCase();
if (ref == "c") unit = 'f';
else if (ref == "l") unit = 'h';
else if (ref == "r" || ref == "rv") unit = 'r';
else unit = null;
}
}
return unit;
};
val = val.replace(/,/g, "");
var match = units.valueRegex.exec(val);
var unit;
if (match) {
val = parseFloat(match[1]);
if (match[2]) {
val = val * units.getMultiplier(match[2]);
}
unit = inferUnit(match[3], ref);
if (!unit) return null;
else return {
val: val,
unit: unit,
extra: match[4],
}
}
match = units.valueAltRegex.exec(val);
if (match && (match[1] || match[4])) {
val = parseFloat(match[1] + "." + match[4]);
if (match[3]) {
val = val * units.getMultiplier(match[3]);
}
unit = inferUnit(match[2], ref);
if (!unit) return null;
else return {
val: val,
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;
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("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 {
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 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 createCheckboxChangeHandler(checkbox, references, row) {
return function () {
refsSet = getStoredCheckboxRefs(checkbox);
var markWhenChecked = settings.markWhenChecked == checkbox;
eventArgs = {
checkbox: checkbox,
refs: references,
}
if (this.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);
}
}
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 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] != b[i]) 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();
if (settings.bommode == "netlist") {
bomtable = pcbdata.nets.slice();
} else {
switch (settings.canvaslayout) {
case 'F':
bomtable = pcbdata.bom.F.slice();
break;
case 'FB':
bomtable = pcbdata.bom.both.slice();
break;
case 'B':
bomtable = pcbdata.bom.B.slice();
break;
}
if (settings.bommode == "ungrouped") {
// expand bom table
expandedTable = []
for (var bomentry of bomtable) {
for (var ref of bomentry) {
expandedTable.push([ref]);
}
}
bomtable = expandedTable;
}
}
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 = createCheckboxChangeHandler(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);
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 checkbox = bomrow.childNodes[checkboxnum].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 checkbox = bomrow.childNodes[checkboxnum + 1].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) {
initUtils();
initRender();
initStorage();
initDefaults();
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);
///////////////////////////////////////////////
///////////////////////////////////////////////
// EventHandler.registerCallback(IBOM_EVENT_TYPES.BOM_BODY_CHANGE_EVENT, () => {
// for(var tr of bom.childNodes) {
// tr.onclick = tr.onmousemove;
// tr.onmousemove = null;
// };
// });
///////////////////////////////////////////////
</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="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>