diff --git a/demo/src/diagram-viewers/add-diagrams.ts b/demo/src/diagram-viewers/add-diagrams.ts index b0f5c8d5..af682ef6 100644 --- a/demo/src/diagram-viewers/add-diagrams.ts +++ b/demo/src/diagram-viewers/add-diagrams.ts @@ -34,13 +34,14 @@ import { OnMoveTextNodeCallbackType, OnSelectNodeCallbackType, OnToggleNadHoverCallbackType, + BranchLabel, } from '../../../src'; export const addNadToDemo = () => { fetch(NadSvgExample) .then((response) => response.text()) .then((svgContent) => { - new NetworkAreaDiagramViewer( + const nadViewer = new NetworkAreaDiagramViewer( document.getElementById('svg-container-nad')!, svgContent, NadSvgExampleMeta, @@ -61,6 +62,42 @@ export const addNadToDemo = () => { .getElementById('svg-container-nad') ?.getElementsByTagName('svg')[0] .setAttribute('style', 'border:2px; border-style:solid;'); + + // add range slider to update branch labels + const branchLabelsSlider = document.createElement('input'); + branchLabelsSlider.type = 'range'; + branchLabelsSlider.min = '1'; + branchLabelsSlider.max = '20'; + branchLabelsSlider.value = '1'; + branchLabelsSlider.step = 'any'; + branchLabelsSlider.style.width = '97%'; + branchLabelsSlider.style.display = 'flex'; + branchLabelsSlider.style.justifyContent = 'space-between'; + branchLabelsSlider.style.padding = '0 5px'; + branchLabelsSlider.addEventListener('input', () => { + const branchLabels = + '[{"branchId": "NGEN_NHV1", "value1": ' + + (627 - +branchLabelsSlider.value * 20) + + ', "value2": ' + + (-626 + +branchLabelsSlider.value * 20) + + '}, {"branchId": "NHV1_NHV2_1", "value1": ' + + (322 - +branchLabelsSlider.value * 20) + + ', "value2": ' + + (-320 + +branchLabelsSlider.value * 20) + + '}, {"branchId": "NHV1_NHV2_2", "value1": ' + + (322 - +branchLabelsSlider.value * 20) + + ', "value2": ' + + (-320 + +branchLabelsSlider.value * 20) + + '}, {"branchId": "NHV2_NLOAD", "value1": ' + + (-620 + +branchLabelsSlider.value * 20) + + ', "value2": ' + + (621 - +branchLabelsSlider.value * 20) + + '}]'; + console.log(branchLabels); + nadViewer.setJsonBranchLabels(branchLabels); + }); + + document.getElementById('svg-container-nad')?.appendChild(branchLabelsSlider); }); fetch(NadSvgExample) @@ -92,7 +129,7 @@ export const addNadToDemo = () => { fetch(NadSvgMultibusVLNodesExample) .then((response) => response.text()) .then((svgContent) => { - new NetworkAreaDiagramViewer( + const nadViewer = new NetworkAreaDiagramViewer( document.getElementById('svg-container-nad-multibus-vlnodes')!, svgContent, NadSvgMultibusVLNodesExampleMeta, @@ -113,6 +150,25 @@ export const addNadToDemo = () => { .getElementById('svg-container-nad-multibus-vlnodes') ?.getElementsByTagName('svg')[0] .setAttribute('style', 'border:2px; border-style:solid;'); + + // add button to update branch labels + const branchLabels = '[{"branchId": "L7-5-0", "value1": 609, "value2": -611}]'; + const updateFlowsTextArea = document.createElement('textarea'); + updateFlowsTextArea.rows = 2; + updateFlowsTextArea.cols = 65; + updateFlowsTextArea.value = branchLabels; + const br = document.createElement('br'); + const updateFlowsButton = document.createElement('button'); + updateFlowsButton.innerHTML = 'Update Branch Labels'; + updateFlowsButton.addEventListener('click', () => { + const branchLabelsArray: BranchLabel[] = JSON.parse(updateFlowsTextArea.value); + nadViewer.setBranchLabels(branchLabelsArray); + }); + const updateFlowsDiv = document.createElement('div'); + updateFlowsDiv.appendChild(updateFlowsTextArea); + updateFlowsDiv.appendChild(br); + updateFlowsDiv.appendChild(updateFlowsButton); + document.getElementById('svg-container-nad-multibus-vlnodes')?.appendChild(updateFlowsDiv); }); fetch(NadSvgMultibusVLNodes14Example) @@ -208,7 +264,7 @@ export const addNadToDemo = () => { handleTextNodeMove, handleNodeSelect, true, - true, + false, null, handleToggleNadHover ); diff --git a/demo/src/diagram-viewers/data/nad-eurostag-tutorial-example1.svg b/demo/src/diagram-viewers/data/nad-eurostag-tutorial-example1.svg index 48d0f81b..e3298910 100644 --- a/demo/src/diagram-viewers/data/nad-eurostag-tutorial-example1.svg +++ b/demo/src/diagram-viewers/data/nad-eurostag-tutorial-example1.svg @@ -128,7 +128,7 @@ path.nad-arrow-in:not(.nad-state-in .nad-arrow-in) {visibility: hidden} - + @@ -140,7 +140,7 @@ path.nad-arrow-in:not(.nad-state-in .nad-arrow-in) {visibility: hidden} - + @@ -161,7 +161,7 @@ path.nad-arrow-in:not(.nad-state-in .nad-arrow-in) {visibility: hidden} - + @@ -173,7 +173,7 @@ path.nad-arrow-in:not(.nad-state-in .nad-arrow-in) {visibility: hidden} - + @@ -192,7 +192,7 @@ path.nad-arrow-in:not(.nad-state-in .nad-arrow-in) {visibility: hidden} - + @@ -204,7 +204,7 @@ path.nad-arrow-in:not(.nad-state-in .nad-arrow-in) {visibility: hidden} - + @@ -223,7 +223,7 @@ path.nad-arrow-in:not(.nad-state-in .nad-arrow-in) {visibility: hidden} - + @@ -235,7 +235,7 @@ path.nad-arrow-in:not(.nad-state-in .nad-arrow-in) {visibility: hidden} - + diff --git a/src/components/network-area-diagram-viewer/diagram-utils.test.ts b/src/components/network-area-diagram-viewer/diagram-utils.test.ts index eb14acfe..3b9170a8 100644 --- a/src/components/network-area-diagram-viewer/diagram-utils.test.ts +++ b/src/components/network-area-diagram-viewer/diagram-utils.test.ts @@ -344,6 +344,11 @@ test('getTextNodeMoves', () => { expect(textNodeMove[1].yNew).toBe(-53.76); }); +test('getArrowClass', () => { + expect(DiagramUtils.getArrowClass(12)).toBe('nad-state-out'); + expect(DiagramUtils.getArrowClass(-12)).toBe('nad-state-in'); +}); + function getSvgNode(): SVGGraphicsElement { const nodeSvg = '' + diff --git a/src/components/network-area-diagram-viewer/diagram-utils.ts b/src/components/network-area-diagram-viewer/diagram-utils.ts index 50a2f10a..dd0b2113 100644 --- a/src/components/network-area-diagram-viewer/diagram-utils.ts +++ b/src/components/network-area-diagram-viewer/diagram-utils.ts @@ -521,3 +521,8 @@ export function getTextNodeMoves( { xOrig: textNode.connectionShiftX, yOrig: textNode.connectionShiftY, xNew: connXNew, yNew: connYNew }, ]; } + +// get arrow element class, based on p value +export function getArrowClass(p: number): string { + return p < 0 ? 'nad-state-in' : 'nad-state-out'; +} diff --git a/src/components/network-area-diagram-viewer/network-area-diagram-viewer.ts b/src/components/network-area-diagram-viewer/network-area-diagram-viewer.ts index ff17b69f..7b9eff01 100644 --- a/src/components/network-area-diagram-viewer/network-area-diagram-viewer.ts +++ b/src/components/network-area-diagram-viewer/network-area-diagram-viewer.ts @@ -16,6 +16,7 @@ import { debounce } from '@mui/material'; type DIMENSIONS = { width: number; height: number; viewbox: VIEWBOX }; type VIEWBOX = { x: number; y: number; width: number; height: number }; +export type BranchLabel = { branchId: string; value1: number | string; value2: number | string }; export type OnMoveNodeCallbackType = ( equipmentId: string, @@ -73,6 +74,7 @@ export class NetworkAreaDiagramViewer { onSelectNodeCallback: OnSelectNodeCallbackType | null; dynamicCssRules: CSS_RULE[]; onToggleHoverCallback: OnToggleNadHoverCallbackType | null; + edgesMap: Map = new Map(); constructor( container: HTMLElement, @@ -1390,4 +1392,55 @@ export class NetworkAreaDiagramViewer { } }); } + + public setJsonBranchLabels(branchLabels: string) { + const branchLabelsArray: BranchLabel[] = JSON.parse(branchLabels); + this.setBranchLabels(branchLabelsArray); + } + + public setBranchLabels(branchLabels: BranchLabel[]) { + branchLabels.forEach((branchLabel) => { + if (!this.edgesMap.has(branchLabel.branchId)) { + const edge: EdgeMetadata | undefined = this.diagramMetadata?.edges.find( + (edge) => edge.equipmentId == branchLabel.branchId + ); + if (edge === undefined) { + console.warn('Skipping updating branch ' + branchLabel.branchId + ' labels: branch not found'); + return; + } + this.edgesMap.set(branchLabel.branchId, edge); + } + this.setBranchSideLabel( + branchLabel.branchId, + '1', + this.edgesMap.get(branchLabel.branchId)?.svgId ?? '-1', + branchLabel.value1 + ); + this.setBranchSideLabel( + branchLabel.branchId, + '2', + this.edgesMap.get(branchLabel.branchId)?.svgId ?? '-1', + branchLabel.value2 + ); + }); + } + + private setBranchSideLabel(branchId: string, side: string, edgeId: string, value: number | string) { + const halfEdge: SVGGraphicsElement | null = this.container.querySelector("[id='" + edgeId + '.' + side + "']"); + const arrowGElement = halfEdge?.lastElementChild?.firstElementChild; + if (arrowGElement !== null && arrowGElement !== undefined) { + arrowGElement.classList.remove('nad-state-in', 'nad-state-out'); + if (typeof value === 'number') { + arrowGElement.classList.add(DiagramUtils.getArrowClass(value)); + } + const branchLabelElement = arrowGElement.lastElementChild; + if (branchLabelElement !== null && branchLabelElement !== undefined) { + branchLabelElement.innerHTML = typeof value === 'number' ? value.toFixed(0) : value; + } else { + console.warn('Skipping updating branch ' + branchId + ' side ' + side + ' label: edge not found'); + } + } else { + console.warn('Skipping updating branch ' + branchId + ' side ' + side + ' label: edge not found'); + } + } } diff --git a/src/index.ts b/src/index.ts index fe85f952..9379f634 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,6 +11,7 @@ export type { OnMoveTextNodeCallbackType, OnSelectNodeCallbackType, OnToggleNadHoverCallbackType, + BranchLabel, } from './components/network-area-diagram-viewer/network-area-diagram-viewer'; export type { DiagramMetadata } from './components/network-area-diagram-viewer/diagram-metadata'; export { THRESHOLD_STATUS } from './components/network-area-diagram-viewer/dynamic-css-utils';