Add default MCM symbol to every MCM's device list

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
igurielidze 2026-03-21 19:18:10 +04:00
parent 224aad4408
commit 84bd2f2978
3 changed files with 120 additions and 12 deletions

View File

@ -99,6 +99,14 @@ function hitTest(cx: number, cy: number): number | null {
return hitTestSymbols(cx, cy, layout.symbols); return hitTestSymbols(cx, cy, layout.symbols);
} }
/** Check if a device type (symbolDef) is compatible with a placed symbol for label assignment.
* Matches by SVG file so base and _v variants are treated as the same type. */
function isTypeCompatible(symbolDef: (typeof SYMBOLS)[number], placedSymbolId: string): boolean {
const placedDef = SYMBOLS.find(s => s.id === placedSymbolId);
if (!placedDef) return false;
return symbolDef.file === placedDef.file;
}
function onCanvasMousedown(e: MouseEvent) { function onCanvasMousedown(e: MouseEvent) {
if (e.button !== 0) return; if (e.button !== 0) return;
e.preventDefault(); e.preventDefault();
@ -471,12 +479,14 @@ function onMousemove(e: MouseEvent) {
const sym = dragState.symbolDef; const sym = dragState.symbolDef;
dragState.ghost.style.left = (e.clientX - sym.w / 2) + 'px'; dragState.ghost.style.left = (e.clientX - sym.w / 2) + 'px';
dragState.ghost.style.top = (e.clientY - sym.h / 2) + 'px'; dragState.ghost.style.top = (e.clientY - sym.h / 2) + 'px';
// Show drop-target highlight when dragging a device over an existing symbol // Show drop-target highlight when dragging a device over a compatible symbol
if (dragState.deviceLabel) { if (dragState.deviceLabel) {
const pos = screenToCanvas(e.clientX, e.clientY); const pos = screenToCanvas(e.clientX, e.clientY);
const hoverId = hitTest(pos.x, pos.y); const hoverId = hitTest(pos.x, pos.y);
if (layout.labelDropTarget !== hoverId) { const hoverSym = hoverId !== null ? layout.symbols.find(s => s.id === hoverId) : null;
layout.labelDropTarget = hoverId; const compatible = hoverSym && isTypeCompatible(sym, hoverSym.symbolId) ? hoverId : null;
if (layout.labelDropTarget !== compatible) {
layout.labelDropTarget = compatible;
layout.markDirty(); layout.markDirty();
} }
} }
@ -646,16 +656,14 @@ function onMouseup(e: MouseEvent) {
const rot = sym.defaultRotation || 0; const rot = sym.defaultRotation || 0;
const pos = screenToCanvas(e.clientX, e.clientY); const pos = screenToCanvas(e.clientX, e.clientY);
// If dropped onto an existing symbol and we have a device label, assign the label // If dropped onto a compatible existing symbol and we have a device label, assign the label
const hitId = dragState.deviceLabel ? hitTest(pos.x, pos.y) : null; const hitId = dragState.deviceLabel ? hitTest(pos.x, pos.y) : null;
if (hitId !== null && dragState.deviceLabel) { const target = hitId !== null ? layout.symbols.find(s => s.id === hitId) : null;
const target = layout.symbols.find(s => s.id === hitId); if (target && dragState.deviceLabel && isTypeCompatible(sym, target.symbolId)) {
if (target) { layout.pushUndo();
layout.pushUndo(); target.label = dragState.deviceLabel;
target.label = dragState.deviceLabel; layout.markDirty();
layout.markDirty(); layout.saveMcmState();
layout.saveMcmState();
}
} else { } else {
// Drop onto empty space: place a new symbol // Drop onto empty space: place a new symbol
let dropX = pos.x - sym.w / 2; let dropX = pos.x - sym.w / 2;

View File

@ -1,5 +1,10 @@
{ {
"MCM01": [ "MCM01": [
{
"id": "MCM01",
"svg": "mcm",
"zone": "MCM01"
},
{ {
"id": "PDP01", "id": "PDP01",
"svg": "pdp", "svg": "pdp",
@ -807,6 +812,11 @@
} }
], ],
"MCM02": [ "MCM02": [
{
"id": "MCM02",
"svg": "mcm",
"zone": "MCM02"
},
{ {
"id": "PDP02", "id": "PDP02",
"svg": "pdp", "svg": "pdp",
@ -2404,6 +2414,11 @@
} }
], ],
"MCM03": [ "MCM03": [
{
"id": "MCM03",
"svg": "mcm",
"zone": "MCM03"
},
{ {
"id": "PDP03", "id": "PDP03",
"svg": "pdp", "svg": "pdp",
@ -4001,6 +4016,11 @@
} }
], ],
"MCM04": [ "MCM04": [
{
"id": "MCM04",
"svg": "mcm",
"zone": "MCM04"
},
{ {
"id": "PDP06", "id": "PDP06",
"svg": "pdp", "svg": "pdp",
@ -5648,6 +5668,11 @@
} }
], ],
"MCM05": [ "MCM05": [
{
"id": "MCM05",
"svg": "mcm",
"zone": "MCM05"
},
{ {
"id": "PDP09", "id": "PDP09",
"svg": "pdp", "svg": "pdp",
@ -7230,6 +7255,11 @@
} }
], ],
"MCM06": [ "MCM06": [
{
"id": "MCM06",
"svg": "mcm",
"zone": "MCM06"
},
{ {
"id": "PDP10", "id": "PDP10",
"svg": "pdp", "svg": "pdp",
@ -8607,6 +8637,11 @@
} }
], ],
"MCM07": [ "MCM07": [
{
"id": "MCM07",
"svg": "mcm",
"zone": "MCM07"
},
{ {
"id": "PDP11", "id": "PDP11",
"svg": "pdp", "svg": "pdp",
@ -9404,6 +9439,11 @@
} }
], ],
"MCM08": [ "MCM08": [
{
"id": "MCM08",
"svg": "mcm",
"zone": "MCM08"
},
{ {
"id": "PDP15", "id": "PDP15",
"svg": "pdp", "svg": "pdp",
@ -10786,6 +10826,11 @@
} }
], ],
"MCM09": [ "MCM09": [
{
"id": "MCM09",
"svg": "mcm",
"zone": "MCM09"
},
{ {
"id": "NCP1_1_BCN1", "id": "NCP1_1_BCN1",
"svg": "beacon", "svg": "beacon",
@ -11473,6 +11518,11 @@
} }
], ],
"MCM10": [ "MCM10": [
{
"id": "MCM10",
"svg": "mcm",
"zone": "MCM10"
},
{ {
"id": "NCP2_1_BCN1", "id": "NCP2_1_BCN1",
"svg": "beacon", "svg": "beacon",
@ -12195,6 +12245,11 @@
} }
], ],
"MCM11": [ "MCM11": [
{
"id": "MCM11",
"svg": "mcm",
"zone": "MCM11"
},
{ {
"id": "NCP1_10_BCN1", "id": "NCP1_10_BCN1",
"svg": "beacon", "svg": "beacon",
@ -16052,6 +16107,11 @@
} }
], ],
"MCM12": [ "MCM12": [
{
"id": "MCM12",
"svg": "mcm",
"zone": "MCM12"
},
{ {
"id": "NCP2_11_TPE1", "id": "NCP2_11_TPE1",
"svg": "photoeye", "svg": "photoeye",
@ -19994,6 +20054,11 @@
} }
], ],
"MCM13": [ "MCM13": [
{
"id": "MCM13",
"svg": "mcm",
"zone": "MCM13"
},
{ {
"id": "PDP01", "id": "PDP01",
"svg": "pdp", "svg": "pdp",
@ -24496,6 +24561,11 @@
"svg": "conveyor", "svg": "conveyor",
"zone": "BYDC_9" "zone": "BYDC_9"
}, },
{
"id": "MCM14",
"svg": "mcm",
"zone": "MCM14"
},
{ {
"id": "PDP17", "id": "PDP17",
"svg": "pdp", "svg": "pdp",
@ -26303,6 +26373,11 @@
"svg": "conveyor", "svg": "conveyor",
"zone": "BYDC_20" "zone": "BYDC_20"
}, },
{
"id": "MCM15",
"svg": "mcm",
"zone": "MCM15"
},
{ {
"id": "PDP19", "id": "PDP19",
"svg": "pdp", "svg": "pdp",
@ -26655,6 +26730,11 @@
"svg": "jam_reset", "svg": "jam_reset",
"zone": "JP1102_1C" "zone": "JP1102_1C"
}, },
{
"id": "MCM16",
"svg": "mcm",
"zone": "MCM16"
},
{ {
"id": "S011011_BCN1", "id": "S011011_BCN1",
"svg": "beacon", "svg": "beacon",
@ -28382,6 +28462,11 @@
"svg": "jam_reset", "svg": "jam_reset",
"zone": "JP3103_1C" "zone": "JP3103_1C"
}, },
{
"id": "MCM17",
"svg": "mcm",
"zone": "MCM17"
},
{ {
"id": "S013041_BCN1", "id": "S013041_BCN1",
"svg": "beacon", "svg": "beacon",
@ -30334,6 +30419,11 @@
"svg": "jam_reset", "svg": "jam_reset",
"zone": "JP2098_1C" "zone": "JP2098_1C"
}, },
{
"id": "MCM18",
"svg": "mcm",
"zone": "MCM18"
},
{ {
"id": "S012011_BCN1", "id": "S012011_BCN1",
"svg": "beacon", "svg": "beacon",
@ -32396,6 +32486,11 @@
"svg": "jam_reset", "svg": "jam_reset",
"zone": "JP4108_1C" "zone": "JP4108_1C"
}, },
{
"id": "MCM19",
"svg": "mcm",
"zone": "MCM19"
},
{ {
"id": "S014015_BCN1", "id": "S014015_BCN1",
"svg": "beacon", "svg": "beacon",

View File

@ -216,6 +216,11 @@ function generateDeviceManifest() {
} }
} }
// Always include the MCM symbol itself
if (!devices.some(d => d.id === mcm)) {
devices.push({ id: mcm, svg: 'mcm', zone: mcm });
}
// Sort by zone then id // Sort by zone then id
devices.sort((a, b) => a.zone.localeCompare(b.zone) || a.id.localeCompare(b.id)); devices.sort((a, b) => a.zone.localeCompare(b.zone) || a.id.localeCompare(b.id));
manifest[mcm] = devices; manifest[mcm] = devices;