This commit is contained in:
@@ -289,76 +289,47 @@ button, input, select {
|
|||||||
.rack-grid {
|
.rack-grid {
|
||||||
position: relative;
|
position: relative;
|
||||||
border-radius: 28px;
|
border-radius: 28px;
|
||||||
border: 1px solid rgba(105, 108, 115, 0.22);
|
border: 1px solid rgba(105, 108, 115, 0.12);
|
||||||
background:
|
background:
|
||||||
linear-gradient(180deg, rgba(255, 255, 255, 0.84), rgba(228, 229, 232, 0.86)),
|
radial-gradient(circle at top left, rgba(255, 255, 255, 0.07), transparent 20%),
|
||||||
linear-gradient(90deg, rgba(144, 148, 156, 0.06), rgba(144, 148, 156, 0));
|
linear-gradient(180deg, #26272b, #202126);
|
||||||
padding: 28px 40px 28px 74px;
|
padding: 16px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
box-shadow:
|
box-shadow:
|
||||||
inset 0 1px 0 rgba(255, 255, 255, 0.65),
|
inset 0 1px 0 rgba(255, 255, 255, 0.08),
|
||||||
inset 0 -18px 24px rgba(134, 137, 145, 0.12),
|
0 20px 40px rgba(20, 18, 16, 0.18);
|
||||||
0 24px 40px rgba(92, 84, 73, 0.12);
|
|
||||||
}
|
|
||||||
|
|
||||||
.rack-grid {
|
|
||||||
outline: 18px solid var(--rack-frame-dark);
|
|
||||||
outline-offset: -18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rack-grid::before,
|
|
||||||
.rack-grid::after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
top: 20px;
|
|
||||||
bottom: 20px;
|
|
||||||
width: 16px;
|
|
||||||
border-radius: 6px;
|
|
||||||
background:
|
|
||||||
radial-gradient(circle at center 8px, rgba(116, 120, 128, 0.48) 0 2px, transparent 2.5px) center top / 100% 18px repeat-y,
|
|
||||||
linear-gradient(180deg, var(--rack-frame-light), var(--rack-rail));
|
|
||||||
box-shadow:
|
|
||||||
inset 0 0 0 1px rgba(255, 255, 255, 0.45),
|
|
||||||
inset 0 -10px 10px rgba(79, 82, 90, 0.16);
|
|
||||||
}
|
|
||||||
|
|
||||||
.rack-grid::before {
|
|
||||||
left: 26px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rack-grid::after {
|
|
||||||
right: 26px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.rack-grid__bay {
|
.rack-grid__bay {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: var(--rack-inner-width);
|
width: min(100%, 1180px);
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 18px 0 14px;
|
aspect-ratio: 3 / 2;
|
||||||
background:
|
background-image:
|
||||||
linear-gradient(180deg, rgba(0, 0, 0, 0.5), transparent 13%, transparent 87%, rgba(0, 0, 0, 0.48)),
|
linear-gradient(180deg, color-mix(in srgb, var(--rack-frame) 38%, transparent), color-mix(in srgb, var(--rack-frame) 38%, transparent)),
|
||||||
linear-gradient(135deg, rgba(255, 255, 255, 0.05), transparent 30%);
|
url("images/rack-template.png");
|
||||||
border-radius: 8px;
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
border-radius: 18px;
|
||||||
box-shadow:
|
box-shadow:
|
||||||
inset 0 0 0 2px rgba(0, 0, 0, 0.35),
|
0 18px 34px rgba(7, 8, 10, 0.32),
|
||||||
inset 0 18px 32px rgba(0, 0, 0, 0.3),
|
inset 0 0 0 1px rgba(255, 255, 255, 0.04);
|
||||||
inset 0 -18px 32px rgba(0, 0, 0, 0.24);
|
isolation: isolate;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rack-grid__guides {
|
.rack-grid__guides {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: linear-gradient(180deg, rgba(20, 22, 28, 0.92), rgba(7, 8, 11, 0.98));
|
height: 100%;
|
||||||
border-left: 4px solid rgba(0, 0, 0, 0.4);
|
background: transparent;
|
||||||
border-right: 4px solid rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.rack-slot {
|
.rack-slot {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: var(--rack-unit-height);
|
height: calc(100% / var(--rack-total-u));
|
||||||
border-top: 1px solid rgba(126, 131, 140, 0.14);
|
border-top: 0;
|
||||||
background:
|
background: transparent;
|
||||||
linear-gradient(180deg, rgba(255, 255, 255, 0.52), rgba(221, 224, 230, 0.42));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.rack-slot:first-child {
|
.rack-slot:first-child {
|
||||||
@@ -372,50 +343,51 @@ button, input, select {
|
|||||||
|
|
||||||
.rack-slot__label {
|
.rack-slot__label {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: -52px;
|
left: 5.7%;
|
||||||
top: 8px;
|
top: 39%;
|
||||||
font-size: 0.76rem;
|
font-size: 0.78rem;
|
||||||
color: rgba(76, 78, 84, 0.82);
|
color: rgba(239, 241, 245, 0.92);
|
||||||
|
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.65);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rack-slot__label--right {
|
.rack-slot__label--right {
|
||||||
left: auto;
|
left: auto;
|
||||||
right: -42px;
|
right: 5.7%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rack-items-layer {
|
.rack-items-layer {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 18px 0 14px;
|
inset: 13.9% 17.4% 16.8% 17.4%;
|
||||||
width: var(--rack-inner-width);
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rack-insertion-layer {
|
.rack-insertion-layer {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 18px 0 14px;
|
inset: 13.9% 17.4% 16.8% 17.4%;
|
||||||
width: var(--rack-inner-width);
|
pointer-events: auto;
|
||||||
pointer-events: none;
|
z-index: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rack-grid__header-badge {
|
.rack-grid__header-badge {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 16px;
|
top: 1.7%;
|
||||||
z-index: 4;
|
z-index: 6;
|
||||||
padding: 14px 18px;
|
padding: 14px 18px;
|
||||||
border-radius: 14px;
|
border-radius: 16px;
|
||||||
background: rgba(17, 19, 24, 0.84);
|
background: rgba(17, 19, 24, 0.84);
|
||||||
color: #f6f7f9;
|
color: #f6f7f9;
|
||||||
font-size: 1rem;
|
font-size: 1.05rem;
|
||||||
box-shadow:
|
box-shadow:
|
||||||
inset 0 0 0 1px rgba(255, 255, 255, 0.12),
|
inset 0 0 0 1px rgba(255, 255, 255, 0.12),
|
||||||
0 10px 20px rgba(20, 22, 28, 0.18);
|
0 10px 20px rgba(20, 22, 28, 0.18);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rack-grid__header-badge--left {
|
.rack-grid__header-badge--left {
|
||||||
left: 16px;
|
left: 1.8%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rack-grid__header-badge--right {
|
.rack-grid__header-badge--right {
|
||||||
right: 16px;
|
right: 1.8%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rack-insert-zone {
|
.rack-insert-zone {
|
||||||
@@ -427,6 +399,7 @@ button, input, select {
|
|||||||
background: transparent;
|
background: transparent;
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
z-index: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rack-insert-zone.is-disabled {
|
.rack-insert-zone.is-disabled {
|
||||||
@@ -435,7 +408,7 @@ button, input, select {
|
|||||||
|
|
||||||
.rack-insert-zone__ear {
|
.rack-insert-zone__ear {
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: calc(100% - 2px);
|
height: calc(100% - 4px);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
background: rgba(83, 156, 243, 0.26);
|
background: rgba(83, 156, 243, 0.26);
|
||||||
border: 1px solid rgba(116, 184, 255, 0.5);
|
border: 1px solid rgba(116, 184, 255, 0.5);
|
||||||
@@ -477,6 +450,7 @@ button, input, select {
|
|||||||
background: linear-gradient(180deg, rgba(35, 92, 154, 0.34), rgba(23, 52, 84, 0.42));
|
background: linear-gradient(180deg, rgba(35, 92, 154, 0.34), rgba(23, 52, 84, 0.42));
|
||||||
box-shadow: inset 0 0 0 1px rgba(120, 182, 247, 0.24);
|
box-shadow: inset 0 0 0 1px rgba(120, 182, 247, 0.24);
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
|
transition: background 120ms ease, box-shadow 120ms ease, transform 120ms ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rack-insert-zone__icon {
|
.rack-insert-zone__icon {
|
||||||
@@ -489,6 +463,13 @@ button, input, select {
|
|||||||
background-color: rgba(72, 151, 228, 0.34);
|
background-color: rgba(72, 151, 228, 0.34);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rack-insert-zone:hover .rack-insert-zone__body {
|
||||||
|
transform: scaleY(1.02);
|
||||||
|
box-shadow:
|
||||||
|
inset 0 0 0 1px rgba(120, 182, 247, 0.34),
|
||||||
|
0 0 0 1px rgba(120, 182, 247, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
.rack-insert-zone.is-disabled .rack-insert-zone__body,
|
.rack-insert-zone.is-disabled .rack-insert-zone__body,
|
||||||
.rack-insert-zone.is-disabled .rack-insert-zone__ear {
|
.rack-insert-zone.is-disabled .rack-insert-zone__ear {
|
||||||
opacity: 0.28;
|
opacity: 0.28;
|
||||||
@@ -500,12 +481,12 @@ button, input, select {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: 10px;
|
border-radius: 8px;
|
||||||
border: 1px solid rgba(122, 127, 137, 0.35);
|
border: 1px solid rgba(34, 38, 44, 0.55);
|
||||||
background: linear-gradient(180deg, #fcfcfd, #e1e5eb);
|
background: linear-gradient(180deg, rgba(237, 241, 246, 0.96), rgba(205, 213, 222, 0.96));
|
||||||
box-shadow:
|
box-shadow:
|
||||||
inset 0 1px 0 rgba(255, 255, 255, 0.76),
|
inset 0 1px 0 rgba(255, 255, 255, 0.9),
|
||||||
0 10px 18px rgba(80, 84, 93, 0.18);
|
0 10px 18px rgba(5, 6, 7, 0.28);
|
||||||
touch-action: none;
|
touch-action: none;
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
}
|
}
|
||||||
@@ -548,16 +529,32 @@ button, input, select {
|
|||||||
color: #17191c;
|
color: #17191c;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rack-item__actions {
|
.rack-item__drag-hint {
|
||||||
display: flex;
|
align-self: start;
|
||||||
flex-wrap: wrap;
|
padding: 5px 8px;
|
||||||
gap: 8px;
|
border-radius: 999px;
|
||||||
|
background: rgba(19, 23, 28, 0.78);
|
||||||
|
color: rgba(245, 247, 250, 0.95);
|
||||||
|
font-size: 0.72rem;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rack-item__actions button {
|
.rack-item__remove {
|
||||||
padding: 8px 10px;
|
position: absolute;
|
||||||
font-size: 0.84rem;
|
top: 8px;
|
||||||
background: rgba(181, 93, 45, 0.92);
|
right: 8px;
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(16, 18, 23, 0.78);
|
||||||
|
color: #fff;
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.subpanel {
|
.subpanel {
|
||||||
|
|||||||
@@ -226,6 +226,7 @@ function renderRack() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ui.rackGrid.style.setProperty("--rack-unit-height", `${RACK_UNIT_PX}px`);
|
ui.rackGrid.style.setProperty("--rack-unit-height", `${RACK_UNIT_PX}px`);
|
||||||
|
ui.rackGrid.style.setProperty("--rack-total-u", String(rack.totalU));
|
||||||
applyRackColorTheme(ui.rackGrid, state.rackColor);
|
applyRackColorTheme(ui.rackGrid, state.rackColor);
|
||||||
|
|
||||||
const slots = [];
|
const slots = [];
|
||||||
@@ -238,26 +239,25 @@ function renderRack() {
|
|||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const insertionZones = renderInsertionZones(rack);
|
|
||||||
|
|
||||||
ui.rackGrid.innerHTML = `
|
ui.rackGrid.innerHTML = `
|
||||||
<div class="rack-grid__header-badge rack-grid__header-badge--left">${rack.rackStandard === "19_inch" ? '19" Rack' : '10" Rack'}</div>
|
<div class="rack-grid__header-badge rack-grid__header-badge--left">${rack.rackStandard === "19_inch" ? '19" Rack' : '10" Rack'}</div>
|
||||||
<div class="rack-grid__header-badge rack-grid__header-badge--right">${rack.totalU} HE</div>
|
<div class="rack-grid__header-badge rack-grid__header-badge--right">${rack.totalU} HE</div>
|
||||||
<div class="rack-grid__bay">
|
<div class="rack-grid__bay">
|
||||||
<div class="rack-grid__guides">${slots.join("")}</div>
|
<div class="rack-grid__guides">${slots.join("")}</div>
|
||||||
<div class="rack-insertion-layer">${insertionZones}</div>
|
<div class="rack-insertion-layer" id="rack-insertion-layer"></div>
|
||||||
<div class="rack-items-layer" id="rack-items-layer"></div>
|
<div class="rack-items-layer" id="rack-items-layer"></div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const layer = document.getElementById("rack-items-layer");
|
||||||
|
layer.style.height = "100%";
|
||||||
|
|
||||||
|
const insertionLayer = document.getElementById("rack-insertion-layer");
|
||||||
|
insertionLayer.innerHTML = renderInsertionZones(rack);
|
||||||
ui.rackGrid.querySelectorAll("[data-action='insert-component']").forEach((element) => {
|
ui.rackGrid.querySelectorAll("[data-action='insert-component']").forEach((element) => {
|
||||||
element.addEventListener("click", () => insertSelectedComponentAt(Number(element.dataset.insertY)));
|
element.addEventListener("click", () => insertSelectedComponentAt(Number(element.dataset.insertY)));
|
||||||
});
|
});
|
||||||
|
|
||||||
const layer = document.getElementById("rack-items-layer");
|
|
||||||
const rackHeight = rack.totalU * RACK_UNIT_PX;
|
|
||||||
layer.style.height = `${rackHeight}px`;
|
|
||||||
|
|
||||||
state.placedItems.forEach((item) => {
|
state.placedItems.forEach((item) => {
|
||||||
const component = getComponent(item.componentId);
|
const component = getComponent(item.componentId);
|
||||||
if (!component) {
|
if (!component) {
|
||||||
@@ -284,21 +284,12 @@ function renderRack() {
|
|||||||
</div>
|
</div>
|
||||||
<span class="chip">${formatRackPosition(item.y)}</span>
|
<span class="chip">${formatRackPosition(item.y)}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="rack-item__actions">
|
<div class="rack-item__drag-hint">Ziehen zum verschieben</div>
|
||||||
<button type="button" data-action="move-left">←</button>
|
<button type="button" class="rack-item__remove" data-action="remove" aria-label="Komponente entfernen">×</button>
|
||||||
<button type="button" data-action="move-right">→</button>
|
|
||||||
<button type="button" data-action="move-up">+1U</button>
|
|
||||||
<button type="button" data-action="move-down">-1U</button>
|
|
||||||
<button type="button" data-action="remove">Entfernen</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
element.addEventListener("pointerdown", (event) => beginPointerDrag(event, item, component));
|
element.addEventListener("pointerdown", (event) => beginPointerDrag(event, item, component));
|
||||||
element.querySelector("[data-action='move-left']").addEventListener("click", () => nudgePlacedItem(item.placementId, -2, 0));
|
|
||||||
element.querySelector("[data-action='move-right']").addEventListener("click", () => nudgePlacedItem(item.placementId, 2, 0));
|
|
||||||
element.querySelector("[data-action='move-up']").addEventListener("click", () => nudgePlacedItem(item.placementId, 0, -RACK_UNIT_PX));
|
|
||||||
element.querySelector("[data-action='move-down']").addEventListener("click", () => nudgePlacedItem(item.placementId, 0, RACK_UNIT_PX));
|
|
||||||
element.querySelector("[data-action='remove']").addEventListener("click", () => {
|
element.querySelector("[data-action='remove']").addEventListener("click", () => {
|
||||||
state.placedItems = state.placedItems.filter((entry) => entry.placementId !== item.placementId);
|
state.placedItems = state.placedItems.filter((entry) => entry.placementId !== item.placementId);
|
||||||
renderAll();
|
renderAll();
|
||||||
@@ -308,19 +299,6 @@ function renderRack() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function nudgePlacedItem(placementId, deltaX, deltaY) {
|
|
||||||
const rack = getCurrentRackTemplate();
|
|
||||||
const item = state.placedItems.find((entry) => entry.placementId === placementId);
|
|
||||||
const component = item ? getComponent(item.componentId) : null;
|
|
||||||
if (!rack || !item || !component) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
item.x = clamp(item.x + deltaX, 0, 100 - getComponentWidthPercent(component));
|
|
||||||
item.y = clamp(item.y + deltaY, 0, getRackHeightPx(rack) - getComponentHeightPx(component));
|
|
||||||
renderAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
function insertSelectedComponentAt(y) {
|
function insertSelectedComponentAt(y) {
|
||||||
if (!state.selectedComponentId) {
|
if (!state.selectedComponentId) {
|
||||||
return;
|
return;
|
||||||
@@ -494,7 +472,7 @@ function renderCableEstimate() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const verticalMm = Math.abs(getPlacementCenterY(from, fromComponent) - getPlacementCenterY(to, toComponent)) * (44.45 / RACK_UNIT_PX);
|
const verticalMm = Math.abs(getPlacementCenterY(from, fromComponent) - getPlacementCenterY(to, toComponent)) * (44.45 / getUnitHeightPx());
|
||||||
const depthAllowance = Math.min(rack.usableDepthMm * 0.35, 280);
|
const depthAllowance = Math.min(rack.usableDepthMm * 0.35, 280);
|
||||||
const sideAllowance = estimateSideAllowance(fromComponent, toComponent);
|
const sideAllowance = estimateSideAllowance(fromComponent, toComponent);
|
||||||
const rawLength = verticalMm + depthAllowance + sideAllowance;
|
const rawLength = verticalMm + depthAllowance + sideAllowance;
|
||||||
@@ -656,8 +634,9 @@ function findFirstFreePosition(heightU) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const testHeight = heightU * RACK_UNIT_PX;
|
const unitHeight = getUnitHeightPx();
|
||||||
for (let y = 0; y <= getRackHeightPx(rack) - testHeight; y += RACK_UNIT_PX) {
|
const testHeight = heightU * unitHeight;
|
||||||
|
for (let y = 0; y <= getRackHeightPx(rack) - testHeight; y += unitHeight) {
|
||||||
const blocked = state.placedItems.some((item) => {
|
const blocked = state.placedItems.some((item) => {
|
||||||
const otherComponent = getComponent(item.componentId);
|
const otherComponent = getComponent(item.componentId);
|
||||||
if (!otherComponent) {
|
if (!otherComponent) {
|
||||||
@@ -883,8 +862,9 @@ function renderInsertionZones(rack) {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const unitHeight = getUnitHeightPx();
|
||||||
const zones = [];
|
const zones = [];
|
||||||
for (let y = 0; y <= getRackHeightPx(rack) - getComponentHeightPx(component); y += RACK_UNIT_PX) {
|
for (let y = 0; y <= getRackHeightPx(rack) - getComponentHeightPx(component); y += unitHeight) {
|
||||||
const occupied = state.placedItems.some((item) => {
|
const occupied = state.placedItems.some((item) => {
|
||||||
const other = getComponent(item.componentId);
|
const other = getComponent(item.componentId);
|
||||||
if (!other) {
|
if (!other) {
|
||||||
@@ -929,11 +909,15 @@ function renderInsertionZones(rack) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getRackHeightPx(rack) {
|
function getRackHeightPx(rack) {
|
||||||
|
const layer = document.getElementById("rack-items-layer");
|
||||||
|
if (layer) {
|
||||||
|
return layer.clientHeight || rack.totalU * RACK_UNIT_PX;
|
||||||
|
}
|
||||||
return rack.totalU * RACK_UNIT_PX;
|
return rack.totalU * RACK_UNIT_PX;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getComponentHeightPx(component) {
|
function getComponentHeightPx(component) {
|
||||||
return component.heightU * RACK_UNIT_PX;
|
return component.heightU * getUnitHeightPx();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getComponentWidthPercent(component) {
|
function getComponentWidthPercent(component) {
|
||||||
@@ -961,7 +945,7 @@ function getPlacementCenterY(item, component) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function formatRackPosition(y) {
|
function formatRackPosition(y) {
|
||||||
return `${(y / RACK_UNIT_PX + 1).toFixed(1)}U`;
|
return `${(y / getUnitHeightPx() + 1).toFixed(1)}U`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPlacementOverlaps() {
|
function getPlacementOverlaps() {
|
||||||
@@ -995,6 +979,15 @@ function getRackInnerWidthPx() {
|
|||||||
return 620;
|
return 620;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getUnitHeightPx() {
|
||||||
|
const rack = getCurrentRackTemplate();
|
||||||
|
const layer = document.getElementById("rack-items-layer");
|
||||||
|
if (rack && layer && layer.clientHeight) {
|
||||||
|
return layer.clientHeight / rack.totalU;
|
||||||
|
}
|
||||||
|
return RACK_UNIT_PX;
|
||||||
|
}
|
||||||
|
|
||||||
function clamp(value, min, max) {
|
function clamp(value, min, max) {
|
||||||
return Math.max(min, Math.min(max, value));
|
return Math.max(min, Math.min(max, value));
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
public/assets/images/rack-template.png
Normal file
BIN
public/assets/images/rack-template.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 MiB |
Reference in New Issue
Block a user