Skip to content

Commit

Permalink
feat(editors/SingleLineDiagram) Allow edit/move of bays (#504)
Browse files Browse the repository at this point in the history
feat(editors/SingleLineDiagram) Allow edit/move of bays (#504)
  • Loading branch information
Dennis Labordus authored Jan 27, 2022
1 parent fa468b7 commit c6f1e0d
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 47 deletions.
50 changes: 33 additions & 17 deletions src/editors/SingleLineDiagram.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import {
drawCNodeConnections,
getConnectivityNodesDrawingPosition,
createSubstationElement,
addLabelToBay,
addLabelToBusBar,
} from './singlelinediagram/sld-drawing.js';
import {
isBusBar,
Expand Down Expand Up @@ -198,7 +200,7 @@ export default class SingleLineDiagramPlugin extends LitElement {
*/
private drawPowerTransformer(parentGroup: SVGElement, powerTransformerElement: Element): void {
const powerTransformerGroup = createPowerTransformerElement(powerTransformerElement,
(event: Event) => this.openEditWizard(event, powerTransformerElement!)
(event: Event) => this.openEditWizard(event, powerTransformerElement)
);
parentGroup.appendChild(powerTransformerGroup);
}
Expand All @@ -222,14 +224,21 @@ export default class SingleLineDiagramPlugin extends LitElement {
});

// After all devices are drawn we can draw the connections between the devices.
// And also add the label on the correct place, we now know where the boundaries are.
this.getVoltageLevels(substationElement)
.forEach(voltageLevelElement => {
this.getBusBars(voltageLevelElement).forEach( busbarElement => {
this.drawBusBarConnections(substationElement, this.svg, busbarElement);

addLabelToBusBar(this.svg, busbarElement,
(event: Event) => this.openEditWizard(event, busbarElement))
});

this.getBays(voltageLevelElement).forEach( bayElement => {
this.drawBayConnections(substationElement, this.svg, bayElement);

addLabelToBay(this.svg, bayElement,
(event: Event) => this.openEditWizard(event, bayElement));
});
});
}
Expand Down Expand Up @@ -349,19 +358,10 @@ export default class SingleLineDiagramPlugin extends LitElement {
*/
private drawBusBars(voltageLevelElement: Element, voltageLevelGroup: SVGElement): void {
this.getBusBars(voltageLevelElement)
.forEach(busbarElement => this.drawBusBar(voltageLevelElement, voltageLevelGroup, busbarElement));
}

/**
* Draw an SVG of the passed Busbar Element.
* @param parentElement - The parent (Voltage Level) Element that is used to determine the length of the Busbar.
* @param parentGroup - The group to which to add the line.
* @param busbarElement - The Busbar Element to draw.
*/
private drawBusBar(parentElement: Element, parentGroup: SVGElement, busbarElement: Element): void {
const busBarGroup = createBusBarElement(busbarElement, getBusBarLength(parentElement),
(event: Event) => this.openEditWizard(event, busbarElement));
parentGroup.appendChild(busBarGroup);
.forEach(busbarElement => {
const busbarGroup = createBusBarElement(busbarElement, getBusBarLength(voltageLevelElement));
voltageLevelGroup.appendChild(busbarGroup);
});
}

/**
Expand All @@ -372,15 +372,15 @@ export default class SingleLineDiagramPlugin extends LitElement {
*/
private drawBusBarConnections(rootElement: Element, rootGroup: SVGElement, busbarElement: Element): void {
const pathName = getPathNameAttribute(busbarElement.children[0]);
const busBarPosition = getAbsolutePositionBusBar(busbarElement);
const busbarPosition = getAbsolutePositionBusBar(busbarElement);

this.findEquipment(rootElement, pathName)
.forEach(element => {
const parentElement = element.parentElement;
const elementPosition = getAbsolutePosition(element);

const elementsTerminalSide =
busBarPosition.y < elementPosition.y ? 'top' : 'bottom';
busbarPosition.y < elementPosition.y ? 'top' : 'bottom';

const elementsTerminalPosition = getAbsolutePositionTerminal(
element,
Expand All @@ -389,7 +389,7 @@ export default class SingleLineDiagramPlugin extends LitElement {

const busbarTerminalPosition = {
x: elementsTerminalPosition.x,
y: busBarPosition.y,
y: busbarPosition.y,
};

const terminalElement = element.querySelector(
Expand Down Expand Up @@ -564,6 +564,22 @@ export default class SingleLineDiagramPlugin extends LitElement {
pointer-events: bounding-box;
}
g[type='Bay'] > g[type='BayLabel'] {
visibility: hidden;
}
g[type='Bay']:hover > g[type='BayLabel'] {
visibility: visible;
}
g[type='Busbar'] > g[type='BusbarLabel'] {
visibility: hidden;
}
g[type='Busbar'] > g[type='BusbarLabel'] > text ,
g[type='Busbar']:hover > g[type='BusbarLabel'] {
visibility: visible;
}
g[type='Bay']:hover,
g[type='Busbar']:hover,
g[type='ConductingEquipment']:hover,
g[type='ConnectivityNode']:hover,
Expand Down
125 changes: 100 additions & 25 deletions src/editors/singlelinediagram/sld-drawing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { getDescriptionAttribute, getNameAttribute, identity } from '../../found
import { getIcon } from '../../zeroline/foundation.js';
import {
connectivityNodeIcon,
editIcon,
powerTransformerTwoWindingIcon,
} from '../../icons.js';

Expand Down Expand Up @@ -172,7 +173,7 @@ export function getConnectivityNodesDrawingPosition(
* @param element - The element.
* @returns The <g> element.
*/
function createGroupElement(element: Element): SVGElement {
function createGroupElement(element: Element): SVGGraphicsElement {
const finalElement = document.createElementNS(
'http://www.w3.org/2000/svg',
'g'
Expand Down Expand Up @@ -217,11 +218,53 @@ export function createVoltageLevelElement(voltageLevel: Element): SVGElement {

/**
* Create a Bay <g> element.
* @param bay - The Bay from the SCL document to use.
* @param bayElement - The Bay from the SCL document to use.
* @returns A Bay <g> element.
*/
export function createBayElement(bay: Element): SVGElement {
return createGroupElement(bay);
export function createBayElement(bayElement: Element): SVGGraphicsElement {
return createGroupElement(bayElement);
}

/**
* Add a Text Element to the top of the Bay
*
* @param rootGroup - The Root group containing all groups.
* @param bayElement - The Bay from the SCL document to use.
* @param clickAction - The action to execute when the Name of the Bay is being clicked.
*/
export function addLabelToBay(rootGroup: SVGElement,
bayElement: Element,
clickAction?: (event: Event) => void
): void {
rootGroup
.querySelectorAll(`g[id="${identity(bayElement)}"]`)
.forEach(bayGroup => {
const labelGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g');
labelGroup.setAttribute('type', 'BayLabel');
if (clickAction) labelGroup.addEventListener('click', clickAction);
bayGroup.prepend(labelGroup);

const bayBox = (<SVGGraphicsElement>bayGroup).getBBox();
const text = createTextElement(
bayElement.getAttribute('name') || '',
{x: bayBox.x, y: bayBox.y - 20},
'medium'
);
labelGroup.append(text);

const textBox = text.getBBox();
const parsedIcon = new DOMParser().parseFromString(
editIcon.strings[0],
'application/xml'
);
parsedIcon.querySelectorAll('circle,path,line').forEach(icon => {
icon.setAttribute(
'transform',
`translate(${textBox.x + textBox.width + 5},${textBox.y}) scale(0.75)`
);
labelGroup.append(icon);
});
});
}

/**
Expand All @@ -235,7 +278,7 @@ export function createTextElement(
textContent: string,
coordinates: Point,
textSize: string
): SVGElement {
): SVGGraphicsElement {
const finalElement = document.createElementNS(
'http://www.w3.org/2000/svg',
'text'
Expand Down Expand Up @@ -285,7 +328,6 @@ export function createTerminalElement(
icon.setAttribute('cx', `${terminalPosition.x}`);
icon.setAttribute('cy', `${terminalPosition.y}`);
icon.setAttribute('r', '2');

groupElement.appendChild(icon);

if (clickAction) groupElement.addEventListener('click', clickAction);
Expand All @@ -295,25 +337,23 @@ export function createTerminalElement(

/**
* Create a bus bar element.
* @param busBarElement - The Bus Bar SCL Element.
* @param busbarElement - The Bus Bar SCL Element.
* @param busbarLength - The length of the bus bar depending on the x coordinate of the most far out right equipment ()
* @returns The Bus Bar SVG element.
*/
export function createBusBarElement(
busBarElement: Element,
busbarLength: number,
clickAction?: (event: Event) => void
): SVGElement {
const groupElement = createGroupElement(busBarElement);
busbarElement: Element,
busbarLength: number
): SVGGraphicsElement {
const groupElement = createGroupElement(busbarElement);
// Overwrite the type to make a distinction between Bays and Busbars.
groupElement.setAttribute('type', 'Busbar');

const busBarName = getNameAttribute(busBarElement)!;
const absolutePosition = getAbsolutePositionBusBar(busBarElement);
const absolutePosition = getAbsolutePositionBusBar(busbarElement);

// TODO: Add this to the icons.ts file.
const icon = document.createElementNS('http://www.w3.org/2000/svg', 'line');
icon.setAttribute('name', getNameAttribute(busBarElement)!);
icon.setAttribute('name', getNameAttribute(busbarElement)!);
icon.setAttribute('stroke-width', '4');
icon.setAttribute('stroke', 'currentColor');

Expand All @@ -324,21 +364,55 @@ export function createBusBarElement(

groupElement.appendChild(icon);

const text = createTextElement(
busBarName,
{ x: absolutePosition.x, y: absolutePosition.y! - 10 },
'small'
);
groupElement.appendChild(text);

if (clickAction) groupElement.addEventListener('click', clickAction);

return groupElement;
}

/**
* Add a Text Element to the top of the Bay
*
* @param rootGroup - The Root group containing all groups.
* @param busbarElement - The BusBar from the SCL document to use.
* @param clickAction - The action to execute when the Name of the BusBar is being clicked.
*/
export function addLabelToBusBar(rootGroup: SVGElement,
busbarElement: Element,
clickAction?: (event: Event) => void
): void {
rootGroup
.querySelectorAll(`g[id="${identity(busbarElement)}"]`)
.forEach(busbarGroup => {
const labelGroup = document.createElementNS('http://www.w3.org/2000/svg','g');
labelGroup.setAttribute('type', 'BusbarLabel');
if (clickAction) labelGroup.addEventListener('click', clickAction);
busbarGroup.prepend(labelGroup);

const busbarBox = (<SVGGraphicsElement>busbarGroup).getBBox();
const text = createTextElement(
busbarElement.getAttribute('name') || '',
{ x: busbarBox.x, y: busbarBox.y - 20 },
'medium'
);
labelGroup.append(text);

const textBox = text.getBBox();
const parsedIcon = new DOMParser().parseFromString(
editIcon.strings[0],
'application/xml'
);
parsedIcon.querySelectorAll('circle,path,line').forEach(icon => {
icon.setAttribute(
'transform',
`translate(${textBox.x + textBox.width + 5},${textBox.y}) scale(0.75)`
);
labelGroup.append(icon);
});
});
}

/**
* Create a Conducting Equipment element.
* @param equipmentElement - The SCL element ConductingEquipment
* @param clickAction - The action to execute when the Conducting Equipment is being clicked.
* @returns The Conducting Equipment SVG element.
*/
export function createConductingEquipmentElement(
Expand Down Expand Up @@ -377,6 +451,7 @@ export function createConductingEquipmentElement(
/**
* Create a PowerTransformer element.
* @param powerTransformerElement - The SCL element PowerTransformer
* @param clickAction - The action to execute when the Power Transformer is being clicked.
* @returns The Power Transformer SVG element.
*/
export function createPowerTransformerElement(
Expand Down Expand Up @@ -415,7 +490,7 @@ export function createPowerTransformerElement(
/**
* Create a Connectivity Node element.
* @param cNodeElement - The SCL element ConnectivityNode
* @param clickAction - The action to execute when the terminal is being clicked.
* @param clickAction - The action to execute when the Terminal is being clicked.
* @returns The Connectivity Node SVG element.
*/
export function createConnectivityNodeElement(
Expand Down
20 changes: 15 additions & 5 deletions src/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ export const logIcon = svg`<svg style="width:24px;height:24px" viewBox="0 0 24 2
<path fill="currentColor" d="M9,7H11V15H15V17H9V7M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4Z" />
</svg>`;

export const editIcon = html`<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 25 25">
<path d="M14.06 9.02l.92.92L5.92 19H5v-.92l9.06-9.06M17.66 3c-.25 0-.51.1-.7.29l-1.83 1.83 3.75 3.75 1.83-1.83c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.2-.2-.45-.29-.71-.29zm-3.6 3.19L3 17.25V21h3.75L17.81 9.94l-3.75-3.75z"
stroke="currentColor"
fill="transparent"
stroke-width="1.5"
stroke-linecap="round"/>
</svg>`;

export const controlBlockIcons: Partial<Record<string, SVGTemplateResult>> = {
ReportControl: reportIcon,
LogControl: logIcon,
Expand Down Expand Up @@ -537,8 +547,8 @@ export const generalConductingEquipmentIcon = html`<svg
/>
<path
d=" M 7.5 17.5
L 12 13
d=" M 7.5 17.5
L 12 13
Z"
fill="transparent"
stroke="currentColor"
Expand All @@ -548,7 +558,7 @@ export const generalConductingEquipmentIcon = html`<svg
/>
<path
d=" M 11 7
L 10 8
L 10 8
C 5 13, 11 20, 17 15
L 18 14
Z"
Expand All @@ -558,7 +568,7 @@ export const generalConductingEquipmentIcon = html`<svg
/>
<path
d=" M 13 9
L 16 6
L 16 6
Z"
fill="transparent"
stroke="currentColor"
Expand All @@ -568,7 +578,7 @@ export const generalConductingEquipmentIcon = html`<svg
/>
<path
d=" M 16 12
L 19 9
L 19 9
Z"
fill="transparent"
stroke="currentColor"
Expand Down

0 comments on commit c6f1e0d

Please sign in to comment.