Merge branch 'pintura-widget' into 'develop'
Pintura widget See merge request acs/public/villas/VILLASweb!24
|
@ -31,6 +31,7 @@
|
|||
"react-router-dom": "^4.1.2",
|
||||
"react-scripts": "1.0.10",
|
||||
"react-sortable-tree": "^0.1.19",
|
||||
"react-svg-pan-zoom": "^2.14.1",
|
||||
"superagent": "^3.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
61
public/Pintura/css/colours.css
Normal file
|
@ -0,0 +1,61 @@
|
|||
#menu {
|
||||
color:#fff!important;
|
||||
background-color:#000!important
|
||||
}
|
||||
.dark-grey-background {
|
||||
color:black;
|
||||
background:#aaa;
|
||||
}
|
||||
.light-grey-background {
|
||||
color:black;
|
||||
background:#ddd;
|
||||
}
|
||||
.blue-grey-background {
|
||||
color:white;
|
||||
background:#607d8b;
|
||||
}
|
||||
.floating-panel-item {
|
||||
font-size:12px;
|
||||
}
|
||||
#floating-panel-list-div {
|
||||
background:#aaa;
|
||||
}
|
||||
.floating-panel-list {
|
||||
background:grey;
|
||||
border:none;
|
||||
}
|
||||
.w3-ul li {
|
||||
border-bottom:0px;
|
||||
}
|
||||
#sidebar {
|
||||
background:#607d8b;
|
||||
border-right:thick solid white;
|
||||
}
|
||||
.component-type-name {
|
||||
color:black;
|
||||
font-size:12px;
|
||||
}
|
||||
.floating-panel-name {
|
||||
font-size:12px;
|
||||
}
|
||||
.dark-font {
|
||||
color:black;
|
||||
}
|
||||
.dropdown-menu {
|
||||
border:medium solid black;
|
||||
background:#607d8b;
|
||||
border:medium solid black;
|
||||
border-width: 1px 1px 1px 1px;
|
||||
}
|
||||
.dropdown-menu h4 {
|
||||
color:white;
|
||||
}
|
||||
.dropdown-menu a {
|
||||
color: black;
|
||||
background:#ddd;
|
||||
font-size:14px;
|
||||
}
|
||||
.dropdown-menu a:hover {
|
||||
background:#bbb;
|
||||
color: white;
|
||||
}
|
84
public/Pintura/css/svg.css
Normal file
|
@ -0,0 +1,84 @@
|
|||
.bar {
|
||||
stroke: #000;
|
||||
stroke-width: 3px;
|
||||
}
|
||||
|
||||
.highlighted-node:hover {
|
||||
stroke: #ff0;
|
||||
}
|
||||
|
||||
line {
|
||||
stroke: #000;
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.line {
|
||||
stroke: #000;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
.terminal-connnode {
|
||||
stroke: #000;
|
||||
stroke-width: 1px;
|
||||
}
|
||||
.terminal-toponode {
|
||||
stroke: #000;
|
||||
stroke-width: 1px;
|
||||
}
|
||||
.conduct {
|
||||
stroke: #000;
|
||||
stroke-width: 1px;
|
||||
}
|
||||
.unknown {
|
||||
stroke: #f0f;
|
||||
stroke-width: 1px;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
.acline {
|
||||
stroke: #000;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
#backing {
|
||||
fill: whitesmoke;
|
||||
}
|
||||
|
||||
/* Below here are SVG elements that we don't want the user to interact with
|
||||
therefore we disable pointer events */
|
||||
|
||||
.svglabel {
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
-webkit-user-select: none; /* Chrome all / Safari all */
|
||||
-moz-user-select: none; /* Firefox all */
|
||||
-ms-user-select: none; /* IE 10+ */
|
||||
}
|
||||
.svglabel-high {
|
||||
visibility: visible;
|
||||
font-size: 12px;
|
||||
font-family: "sans-serif";
|
||||
text-anchor: right;
|
||||
fill: black;
|
||||
stroke-width: 1px;
|
||||
pointer-events: none;
|
||||
-webkit-user-select: none; /* Chrome all / Safari all */
|
||||
-moz-user-select: none; /* Firefox all */
|
||||
-ms-user-select: none; /* IE 10+ */
|
||||
}
|
||||
.gridLine {
|
||||
stroke: #aaa;
|
||||
stroke-width: 1px;
|
||||
pointer-events: none;
|
||||
-webkit-user-select: none; /* Chrome all / Safari all */
|
||||
-moz-user-select: none; /* Firefox all */
|
||||
-ms-user-select: none; /* IE 10+ */
|
||||
}
|
||||
.gridLabel {
|
||||
font-size: 8px;
|
||||
font-family: "sans-serif";
|
||||
fill: grey;
|
||||
stroke-width: 0px;
|
||||
pointer-events: none;
|
||||
-webkit-user-select: none; /* Chrome all / Safari all */
|
||||
-moz-user-select: none; /* Firefox all */
|
||||
-ms-user-select: none; /* IE 10+ */
|
||||
}
|
1225
public/Pintura/images/Pintura_logo.svg
Normal file
After Width: | Height: | Size: 65 KiB |
24
public/Pintura/images/brea.svg
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Copyright © 2016-2017, RWTH Aachen University
|
||||
Authors: Richard Marston
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
A copy of the GNU General Public License is in the LICENSE file
|
||||
in the top level directory of this source tree.
|
||||
-->
|
||||
<svg height="24" width="24" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="4" y="4" height="16" width="16" fill-opacity="0" stroke="black" stroke-width="1" />
|
||||
<line x1="4" y1="12" x2="8" y2="12" fill-opacity="0" stroke="black" stroke-width="1" />
|
||||
<line x1="8" y1="12" x2="14" y2="8" fill-opacity="0" stroke="black" stroke-width="1" />
|
||||
<line x1="15" y1="12" x2="20" y2="12" fill-opacity="0" stroke="black" stroke-width="1" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
21
public/Pintura/images/conn.svg
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Copyright © 2016-2017, RWTH Aachen University
|
||||
Authors: Richard Marston
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
A copy of the GNU General Public License is in the LICENSE file
|
||||
in the top level directory of this source tree.
|
||||
-->
|
||||
<svg height="27" width="27" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle id="circle" cx="13" cy="14" r="6" fill-opacity="1" stroke="black" stroke-width="1" />
|
||||
</svg>
|
After Width: | Height: | Size: 909 B |
22
public/Pintura/images/cons.svg
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Copyright © 2016-2017, RWTH Aachen University
|
||||
Authors: Richard Marston
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
A copy of the GNU General Public License is in the LICENSE file
|
||||
in the top level directory of this source tree.
|
||||
-->
|
||||
<svg height="24" width="24" xmlns="http://www.w3.org/2000/svg">
|
||||
<polygon points="7,10 17,10 12,24" style="fill:black;stroke:black;stroke-width:1" />
|
||||
<line x1="12" y1="3" x2="12" y2="22" style="fill:black;stroke:black;stroke-width:1" />
|
||||
</svg>
|
After Width: | Height: | Size: 991 B |
27
public/Pintura/images/net.svg
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Copyright © 2016-2017, RWTH Aachen University
|
||||
Authors: Richard Marston
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
A copy of the GNU General Public License is in the LICENSE file
|
||||
in the top level directory of this source tree.
|
||||
-->
|
||||
<svg height="36" width="36" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<pattern id="diagonalHatch" width="8" height="8" patternUnits="userSpaceOnUse">
|
||||
<line x1="0" y1="0" x2="8" y2="8" style="stroke:black; stroke-width:1" />
|
||||
<line x1="8" y1="0" x2="0" y2="8" style="stroke:black; stroke-width:1" />
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect x="6" y="6" width="24" height="24" style="fill:url(#diagonalHatch);stroke:black;stroke-width:1" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
32
public/Pintura/images/sol.svg
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Copyright © 2016-2017, RWTH Aachen University
|
||||
Authors: Richard Marston
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
A copy of the GNU General Public License is in the LICENSE file
|
||||
in the top level directory of this source tree.
|
||||
-->
|
||||
<svg height="36" width="36" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<marker id="arrow" markerWidth="10" markerHeight="10" refX="0" refY="3" orient="auto" markerUnits="strokeWidth">
|
||||
<path d="M0,2 L0,4 L2,3 z" fill="#000" />
|
||||
</marker>
|
||||
<pattern id="diagonalHatch" width="8" height="8" patternUnits="userSpaceOnUse">
|
||||
<line x1="8" y1="0" x2="0" y2="8" style="stroke:black; stroke-width:1" />
|
||||
</pattern>
|
||||
</defs>
|
||||
<line x1="8" y1="8" x2="12" y2="12" stroke="#000" stroke-width="3" marker-end="url(#arrow)" />
|
||||
<line x1="16" y1="8" x2="20" y2="12" stroke="#000" stroke-width="3" marker-end="url(#arrow)" />
|
||||
<rect x="6" y="18" width="24" height="12" style="fill:url(#diagonalHatch);stroke:black;stroke-width:1" />
|
||||
<rect x="6" y="6" width="24" height="24" style="fill:none;stroke:black;stroke-width:1" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
22
public/Pintura/images/sync.svg
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Copyright © 2016-2017, RWTH Aachen University
|
||||
Authors: Richard Marston
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
A copy of the GNU General Public License is in the LICENSE file
|
||||
in the top level directory of this source tree.
|
||||
-->
|
||||
<svg height="24" width="24" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle id="circle" cx="12" cy="12" r="10" fill-opacity="0" stroke="black" stroke-width="1" />
|
||||
<path d="M4 12 C 6 5, 10 5, 12 12 S 19 19, 20 12" stroke="black" fill="transparent"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1,000 B |
21
public/Pintura/images/term.svg
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Copyright © 2016-2017, RWTH Aachen University
|
||||
Authors: Richard Marston
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
A copy of the GNU General Public License is in the LICENSE file
|
||||
in the top level directory of this source tree.
|
||||
-->
|
||||
<svg height="24" width="24" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="8" y="8" width="8" height="8" style="fill:black;stroke:black;stroke-width:1" />
|
||||
</svg>
|
After Width: | Height: | Size: 904 B |
22
public/Pintura/images/topo.svg
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Copyright © 2016-2017, RWTH Aachen University
|
||||
Authors: Richard Marston
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
A copy of the GNU General Public License is in the LICENSE file
|
||||
in the top level directory of this source tree.
|
||||
-->
|
||||
<svg height="12" width="12" xmlns="http://www.w3.org/2000/svg" stroke-width="1">
|
||||
<circle cx="6" cy="6" r="1" fill-opacity="1" stroke="black" stroke-width="1" />
|
||||
<rect x="0" y="0" height="12" width="12" fill-opacity="0" stroke="black" stroke-width="1" />
|
||||
</svg>
|
After Width: | Height: | Size: 1,009 B |
22
public/Pintura/images/trans.svg
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Copyright © 2016-2017, RWTH Aachen University
|
||||
Authors: Richard Marston
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
A copy of the GNU General Public License is in the LICENSE file
|
||||
in the top level directory of this source tree.
|
||||
-->
|
||||
<svg height="24" width="24" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle id="leftcircle" cx="13" cy="10" r="7" fill-opacity="0" stroke="black" stroke-width="1" />
|
||||
<circle id="rightcircle" cx="13" cy="14" r="7" fill-opacity="0" stroke="black" stroke-width="1" />
|
||||
</svg>
|
After Width: | Height: | Size: 1,016 B |
201
public/Pintura/js/cimjson.js
Normal file
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Copyright © 2016-2017, RWTH Aachen University
|
||||
* Authors: Richard Marston
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU General Public License is in the LICENSE file
|
||||
* in the top level directory of this source tree.
|
||||
*/
|
||||
|
||||
var cimjson = cimjson || (function() {
|
||||
|
||||
var pathBase = '';
|
||||
const imageNames = {
|
||||
"cim:ACLineSegment": "images/term.svg",
|
||||
"cim:Terminal": "images/term.svg",
|
||||
"cim:Breaker": "images/brea.svg",
|
||||
"cim:ConnectivityNode": "images/conn.svg",
|
||||
"cim:EnergyConsumer": "images/cons.svg",
|
||||
"cim:EquivalentInjection": "images/cons.svg",
|
||||
"cim:ExternalNetworkInjection": "images/net.svg",
|
||||
"cim:PowerTransformer": "images/trans.svg",
|
||||
"cim:SolarGeneratingUnit": "images/solar.svg",
|
||||
"cim:SynchronousMachine": "images/sync.svg",
|
||||
"cim:TopologicalNode": "images/topo.svg",
|
||||
"cim:TransformerWinding": "images/trans.svg",
|
||||
};
|
||||
|
||||
const PinturaDiagramObjectPoints = "Pintura:DiagramObjectPoints";
|
||||
|
||||
var getImageName = function(type) {
|
||||
return pathBase + imageNames[type];
|
||||
}
|
||||
|
||||
var convertDiagramObjectToTemplateFormat = function(diagramObject, graph, categoryGraphName, diagramList) {
|
||||
|
||||
let originalPoints = diagramObject[PinturaDiagramObjectPoints];
|
||||
let preOffsetPoints = [];
|
||||
let imagePoints = [];
|
||||
let labelPoint;
|
||||
let object;
|
||||
let categoryGraph = graph[categoryGraphName];
|
||||
const imageHeight = 12;
|
||||
const imageWidth = 12;
|
||||
if (diagramObject["cim:DiagramObject.IdentifiedObject"] != undefined) {
|
||||
let rdfId = diagramObject["cim:DiagramObject.IdentifiedObject"]["rdf:resource"].substring(1);
|
||||
for (let index in originalPoints) {
|
||||
let point = originalPoints[index];
|
||||
preOffsetPoints.push(
|
||||
{
|
||||
"x": parseInt(point["cim:DiagramObjectPoint.xPosition"]).toString(),
|
||||
"y": parseInt(point["cim:DiagramObjectPoint.yPosition"]).toString()
|
||||
});
|
||||
imagePoints.push(
|
||||
{
|
||||
"imageHeight" : imageHeight.toString(),
|
||||
"imageWidth" : imageWidth.toString(),
|
||||
"x" : (parseInt(point["cim:DiagramObjectPoint.xPosition"]) - (imageWidth/2)).toString(),
|
||||
"y" : (parseInt(point["cim:DiagramObjectPoint.yPosition"]) - (imageHeight/2)).toString()
|
||||
});
|
||||
};
|
||||
labelPoint = {
|
||||
"x": (parseInt(preOffsetPoints[0].x) + (imageWidth/2)).toString(),
|
||||
"y": (parseInt(preOffsetPoints[0].y) - (imageHeight/2)).toString()
|
||||
};
|
||||
object =
|
||||
{
|
||||
"pintura:image" : getImageName(categoryGraphName),
|
||||
"pintura:rdfId" : rdfId,
|
||||
"pintura:points" : imagePoints,
|
||||
"pintura:label" : {
|
||||
"text": categoryGraph[rdfId]["cim:IdentifiedObject.name"],
|
||||
"x" : labelPoint.x,
|
||||
"y" : labelPoint.y
|
||||
}
|
||||
}
|
||||
while (preOffsetPoints.length > 1) {
|
||||
if (object["pintura:line"] == null) {
|
||||
object["pintura:line"] = [];
|
||||
}
|
||||
let line = {
|
||||
"x1": preOffsetPoints[0].x,
|
||||
"y1": preOffsetPoints[0].y,
|
||||
"x2": preOffsetPoints[1].x,
|
||||
"y2": preOffsetPoints[1].y
|
||||
};
|
||||
object["pintura:line"].push(line);
|
||||
preOffsetPoints.shift()
|
||||
}
|
||||
}
|
||||
let diagram = diagramObject["cim:DiagramObject.Diagram"]["rdf:resource"].substring(1);
|
||||
if (diagramList[diagram] === undefined){
|
||||
diagramList[diagram] = { "pintura:name" : graph["cim:Diagram"][diagram]["cim:IdentifiedObject.name"] };
|
||||
}
|
||||
if (diagramObject["cim:DiagramObject.IdentifiedObject"]) {
|
||||
let identifiedObject = diagramObject["cim:DiagramObject.IdentifiedObject"]["rdf:resource"].substring(1);
|
||||
if (diagramList[diagram]["components"] === undefined){
|
||||
diagramList[diagram]["components"] = {};
|
||||
}
|
||||
if (diagramList[diagram]["components"][categoryGraphName] === undefined){
|
||||
diagramList[diagram]["components"][categoryGraphName] = {};
|
||||
}
|
||||
diagramList[diagram]["components"][categoryGraphName][identifiedObject] = object;
|
||||
}
|
||||
};
|
||||
|
||||
var convertToTemplatableFormat = function(diagramObjects, graph) {
|
||||
|
||||
let output = { 'Diagram' : {} };
|
||||
let diagramList = output['Diagram'];
|
||||
|
||||
for (categoryGraphName in imageNames) {
|
||||
|
||||
let categoryGraph = graph[categoryGraphName];
|
||||
for (let key in categoryGraph) {
|
||||
let diagramObject = diagramObjects[key];
|
||||
if (diagramObject != undefined) {
|
||||
convertDiagramObjectToTemplateFormat(diagramObject, graph, categoryGraphName, diagramList);
|
||||
}
|
||||
}
|
||||
}
|
||||
return output;
|
||||
};
|
||||
|
||||
var indexDiagramGraphByComponentType = function(input) {
|
||||
/*
|
||||
* Index the diagram object graph by the identified object's id so we don't
|
||||
* have to go hunting for the referenced object inside the diagram objects.
|
||||
*/
|
||||
let graph = {};
|
||||
for (let key in input) {
|
||||
let diagramObject = input[key];
|
||||
let diagram = diagramObject["cim:DiagramObject.Diagram"]["rdf:resource"].substring(1);
|
||||
if (diagramObject["cim:DiagramObject.IdentifiedObject"]) {
|
||||
let identifiedObject = input[key]["cim:DiagramObject.IdentifiedObject"]["rdf:resource"].substring(1);
|
||||
graph[identifiedObject] = input[key];
|
||||
}
|
||||
}
|
||||
return graph;
|
||||
};
|
||||
|
||||
var addDiagramObjectPointsToDiagramObjects = function(diagramObjectPointGraph, diagramObjectGraph){
|
||||
for (let key in diagramObjectPointGraph) {
|
||||
mergeMatchingDataIntoParentNodeArray(diagramObjectPointGraph[key], "cim:DiagramObjectPoint.DiagramObject", diagramObjectGraph, PinturaDiagramObjectPoints);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Create link to a member of an array of e.g. points
|
||||
*/
|
||||
var mergeMatchingDataIntoParentNodeArray = function(node, matchingElement, destinationGraph, destinationElement) {
|
||||
if (node[matchingElement]) {
|
||||
let id = node[matchingElement]["rdf:resource"].substr(1);
|
||||
if (destinationGraph[id]) {
|
||||
if (destinationGraph[id][destinationElement] === undefined) {
|
||||
destinationGraph[id][destinationElement] = [];
|
||||
}
|
||||
destinationGraph[id][destinationElement].push(node);
|
||||
}
|
||||
else {
|
||||
console.log("Could not find destination "+matchingElement+" to merge into "+destinationElement+".");
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log("Could not find matching element "+matchingElement+" to merge "+destinationElement+" into .");
|
||||
}
|
||||
};
|
||||
|
||||
var getTemplateJson = function(graph) {
|
||||
let updatedDiagramObjects = JSON.parse(JSON.stringify(graph['cim:DiagramObject']));
|
||||
let diagramObjectPoints = graph['cim:DiagramObjectPoint'];
|
||||
addDiagramObjectPointsToDiagramObjects(diagramObjectPoints, updatedDiagramObjects);
|
||||
|
||||
let diagramObjectsByIdentifiedObjects = indexDiagramGraphByComponentType(updatedDiagramObjects);
|
||||
|
||||
templateReadyFormat = convertToTemplatableFormat(diagramObjectsByIdentifiedObjects, graph);
|
||||
|
||||
return templateReadyFormat;
|
||||
};
|
||||
|
||||
return {
|
||||
setImagePathBase : function(path) {
|
||||
pathBase = path;
|
||||
},
|
||||
getTemplateJson,
|
||||
};
|
||||
}());
|
||||
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
cimjson
|
||||
};
|
||||
}
|
140
public/Pintura/js/cimsvg.js
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright © 2016-2017, RWTH Aachen University
|
||||
* Authors: Richard Marston
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU General Public License is in the LICENSE file
|
||||
* in the top level directory of this source tree.
|
||||
*/
|
||||
|
||||
var cimsvg = cimsvg || (function() {
|
||||
|
||||
var svgNode = null;
|
||||
var xmlNode = null;
|
||||
var pinturaNode = null;
|
||||
var sidebarNode = null;
|
||||
|
||||
function handler() {
|
||||
//console.log(this.getResponseHeader('content-type'));
|
||||
}
|
||||
|
||||
var includeFile = function(fileName, callback) {
|
||||
let dom = svgNode.ownerDocument;
|
||||
let newTag = dom.createElement("script");
|
||||
newTag.type = "text/javascript";
|
||||
newTag.src=fileName;
|
||||
if ( callback != undefined ) {
|
||||
newTag.onload=function() {
|
||||
callback();
|
||||
};
|
||||
}
|
||||
svgNode.parentElement.appendChild(newTag);
|
||||
};
|
||||
|
||||
var applyTemplate = function(data) {
|
||||
var template = Handlebars.templates['cim2svg'];
|
||||
return template(data);
|
||||
};
|
||||
|
||||
var loadFile = function(fileContents) {
|
||||
if (cimxml.moreXmlData(fileContents)) {
|
||||
baseJson = cimxml.getBaseJson();
|
||||
templateJson = cimjson.getTemplateJson(baseJson);
|
||||
svgNode.ownerDocument.getElementById('diagrams').innerHTML = applyTemplate(templateJson);
|
||||
if(sidebarNode != null) {
|
||||
cimmenu.populateSidebar(sidebarNode, templateJson);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var setFileCount = function(count) {
|
||||
cimxml.setRdfFileCount(count);
|
||||
};
|
||||
|
||||
var isNode = false;
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
isNode = true;
|
||||
}
|
||||
|
||||
var updateComponent = function(type, id, attribute, value) {
|
||||
cimxml.updateComponentInBaseJson(type, id, attribute, value)
|
||||
baseJson = cimxml.getBaseJson();
|
||||
templateJson = cimjson.getTemplateJson(baseJson);
|
||||
if (attribute === "cim:IdentifiedObject.name") {
|
||||
buttonId = '#' + id + "-sidebar-button"
|
||||
button = sidebarNode.querySelector(buttonId)
|
||||
button.innerHTML = value;
|
||||
}
|
||||
};
|
||||
|
||||
var loadXml = function(fileName, callback) {
|
||||
// Create a connection to the file.
|
||||
var Connect = new XMLHttpRequest();
|
||||
// Define which file to open and
|
||||
Connect.open("GET", fileName, true);
|
||||
Connect.setRequestHeader("Content-Type", "text/xml");
|
||||
Connect.onreadystatechange = handler;
|
||||
Connect.onload = function (e) {
|
||||
if(Connect.readyState === 4) {
|
||||
if(Connect.status === 200) {
|
||||
callback(Connect.responseXML);
|
||||
}
|
||||
else {
|
||||
console.log(Connect.statusText);
|
||||
}
|
||||
}
|
||||
};
|
||||
// send the request.
|
||||
Connect.send(null);
|
||||
};
|
||||
|
||||
return {
|
||||
init : function(svg, sidebar, componentAttributes, componentCreation) {
|
||||
svgNode = svg;
|
||||
sidebarNode = sidebar;
|
||||
includeFile("handlebars.runtime.js", function() {
|
||||
includeFile("src/cimview.js", function() {
|
||||
cimview.init(svgNode);
|
||||
if(sidebarNode != undefined) {
|
||||
includeFile("src/cimmenu.js", function() {
|
||||
cimmenu.init(componentAttributes)
|
||||
});
|
||||
}
|
||||
includeFile("templates/template.js", function(){
|
||||
includeFile("src/cimxml.js", function(){
|
||||
includeFile("src/cimjson.js", function(){});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
loadXml("templates/generated_add_components/menu.xml", function(xml){
|
||||
if(componentCreation != undefined) {
|
||||
accordion = componentCreation.querySelector('#component-creation-list-div')
|
||||
accordion.innerHTML = xml.documentElement.innerHTML;
|
||||
}
|
||||
});
|
||||
},
|
||||
setSVG : function(svg) {
|
||||
svgNode = svg;
|
||||
},
|
||||
loadFile,
|
||||
setFileCount,
|
||||
updateComponent,
|
||||
};
|
||||
|
||||
}());
|
||||
|
||||
if (cimsvg.isNode) {
|
||||
module.exports = {
|
||||
cimsvg
|
||||
}
|
||||
}
|
208
public/Pintura/js/cimview.js
Normal file
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* Copyright © 2016-2017, RWTH Aachen University
|
||||
* Authors: Richard Marston
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU General Public License is in the LICENSE file
|
||||
* in the top level directory of this source tree.
|
||||
*/
|
||||
|
||||
var cimview = cimview || (function() {
|
||||
|
||||
var svgNode = null;
|
||||
|
||||
var zoomSizes = [
|
||||
{ width: 1024, height: 768 },
|
||||
{ width: 920, height: 690 },
|
||||
{ width: 816, height: 612 },
|
||||
{ width: 712, height: 532 },
|
||||
{ width: 608, height: 456 },
|
||||
{ width: 504, height: 378 },
|
||||
{ width: 400, height: 300 },
|
||||
];
|
||||
|
||||
var zoomLevel = 0;
|
||||
|
||||
var zoomToLevel = function(level) {
|
||||
zoomLevel = level;
|
||||
let rect = getViewBox();
|
||||
centreOfGrid = { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 };
|
||||
rect.width = zoomSizes[level].width;
|
||||
rect.height = zoomSizes[level].height;
|
||||
rect.x = centreOfGrid.x - (rect.width / 2);
|
||||
rect.y = centreOfGrid.y - (rect.height / 2);
|
||||
setViewBox(rect);
|
||||
};
|
||||
|
||||
var zoomOut = function() {
|
||||
let level = zoomLevel-1;
|
||||
if (level < 0) {
|
||||
level = 0;
|
||||
}
|
||||
zoomToLevel(level);
|
||||
//document.getElementById("zoomer").value=level;
|
||||
};
|
||||
|
||||
var zoomIn = function() {
|
||||
let level = zoomLevel+1;
|
||||
let lastIndex = zoomSizes.length-1;
|
||||
if (level > lastIndex) {
|
||||
level = lastIndex;
|
||||
}
|
||||
zoomToLevel(level);
|
||||
//document.getElementById("zoomer").value=level;
|
||||
};
|
||||
|
||||
var pan = function(point) {
|
||||
let rect = getViewBox();
|
||||
rect.x += point.x;
|
||||
rect.y += point.y;
|
||||
setViewBox(rect);
|
||||
};
|
||||
|
||||
var clearGrid = function() {
|
||||
let oldLines = Array.from(svgNode.getElementsByClassName("gridLine"));
|
||||
oldLines.forEach(function(key) {
|
||||
key.remove();
|
||||
});
|
||||
let oldLabels = Array.from(svgNode.getElementsByClassName("gridLabel"));
|
||||
oldLabels.forEach(function(key) {
|
||||
key.remove();
|
||||
});
|
||||
};
|
||||
|
||||
var createLocationMarker = function(id, loc, x, y) {
|
||||
let grid = svgNode.ownerDocument.getElementById("grid");
|
||||
let textAttributes = {
|
||||
"x": x,
|
||||
"y": y,
|
||||
"class": "gridLabel",
|
||||
"id": id,
|
||||
};
|
||||
let text = createSvgTag("text", textAttributes);
|
||||
text.innerHTML = loc;
|
||||
grid.appendChild(text);
|
||||
};
|
||||
|
||||
var createGridLine = function(x1, y1, x2, y2) {
|
||||
let grid = svgNode.ownerDocument.getElementById("grid");
|
||||
let lineAttributes = {
|
||||
"x1": x1,
|
||||
"x2": x2,
|
||||
"y1": y1,
|
||||
"y2": y2,
|
||||
"class": "gridLine",
|
||||
};
|
||||
let line = createSvgTag("line", lineAttributes);
|
||||
grid.appendChild(line);
|
||||
};
|
||||
|
||||
/*
|
||||
* Create a tag in the svg namespace
|
||||
*/
|
||||
const createSvgTag = function(tagname, attributes) {
|
||||
let xmlns="http://www.w3.org/2000/svg";
|
||||
let newTag = svgNode.ownerDocument.createElementNS(xmlns, tagname);
|
||||
for (let key in attributes) {
|
||||
newTag.setAttribute(key, attributes[key]);
|
||||
}
|
||||
return newTag;
|
||||
};
|
||||
|
||||
var calculateStartOffset = function(distanceFromOrigin, gridSize) {
|
||||
let offset;
|
||||
if (distanceFromOrigin < 0) {
|
||||
offset = distanceFromOrigin - ( distanceFromOrigin % gridSize );
|
||||
}
|
||||
else {
|
||||
offset = distanceFromOrigin + gridSize - ( distanceFromOrigin % gridSize );
|
||||
}
|
||||
return offset;
|
||||
};
|
||||
|
||||
var createGrid = function() {
|
||||
clearGrid();
|
||||
let gridSize = 100;
|
||||
let viewBoxRect = getViewBox();
|
||||
/* horizontal lines */
|
||||
let startOffsetY = calculateStartOffset(viewBoxRect.y, gridSize);
|
||||
let startOffsetX = calculateStartOffset(viewBoxRect.x, gridSize);
|
||||
for (let i=0; i<(viewBoxRect.height/gridSize); i++) {
|
||||
let yval = i*gridSize+startOffsetY;
|
||||
createGridLine(viewBoxRect.x, yval, viewBoxRect.width+viewBoxRect.x, yval);
|
||||
createLocationMarker(yval+"y", yval.toString(), viewBoxRect.x+10, yval+20);
|
||||
}
|
||||
/* vertical lines */
|
||||
for (let i=0; i<(viewBoxRect.width/gridSize); i++) {
|
||||
let xval = i*gridSize+startOffsetX;
|
||||
createGridLine(xval, viewBoxRect.y, xval, viewBoxRect.height+viewBoxRect.y);
|
||||
createLocationMarker(xval+"x", xval.toString(), xval+10, viewBoxRect.y+20);
|
||||
}
|
||||
};
|
||||
|
||||
var getViewBox = function() {
|
||||
let rect = {};
|
||||
viewBoxString = svgNode.getAttribute("viewBox");
|
||||
viewBoxElements = viewBoxString.split(" ");
|
||||
rect.x = parseInt(viewBoxElements[0]);
|
||||
rect.y = parseInt(viewBoxElements[1]);
|
||||
rect.width = parseInt(viewBoxElements[2]);
|
||||
rect.height = parseInt(viewBoxElements[3]);
|
||||
return rect;
|
||||
};
|
||||
|
||||
var setViewBox = function(rect) {
|
||||
let viewBoxString = rect.x+" "+rect.y+" "+rect.width+" "+rect.height;
|
||||
svgNode.setAttribute("viewBox", viewBoxString);
|
||||
let bg = svgNode.ownerDocument.getElementById("backing");
|
||||
bg.setAttribute("x", rect.x);
|
||||
bg.setAttribute("y", rect.y);
|
||||
bg.setAttribute("width", "100%");
|
||||
bg.setAttribute("height", "100%");
|
||||
createGrid();
|
||||
};
|
||||
|
||||
var clearDisplay = function() {
|
||||
while (svgNode.firstChild) {
|
||||
svgNode.removeChild(svgNode.firstChild);
|
||||
}
|
||||
};
|
||||
|
||||
var hideAllLabels = function() {
|
||||
Array.from(svgNode.getElementsByClassName("svglabel")).forEach(function (label) {
|
||||
label.setAttributeNS(null, "visibility", "hidden");
|
||||
});
|
||||
};
|
||||
|
||||
var init = function(svg) {
|
||||
svgNode = svg;
|
||||
let rect = { x: "-100", y: "-100", width: "1024", height: "768" };
|
||||
setViewBox(rect);
|
||||
};
|
||||
|
||||
/*
|
||||
* Specify the functions that this module exports
|
||||
*/
|
||||
return {
|
||||
init,
|
||||
pan,
|
||||
zoomIn,
|
||||
zoomOut,
|
||||
};
|
||||
|
||||
}());
|
||||
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
cimview
|
||||
}
|
||||
}
|
253
public/Pintura/js/cimxml.js
Normal file
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
* Copyright © 2016-2017, RWTH Aachen University
|
||||
* Authors: Richard Marston
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU General Public License is in the LICENSE file
|
||||
* in the top level directory of this source tree.
|
||||
*/
|
||||
|
||||
var cimxml = cimxml || (function() {
|
||||
|
||||
var xmlDoc;
|
||||
var rdfFileCount = 0;
|
||||
var rdfFileReceived = 0;
|
||||
var jsonBaseData = null;
|
||||
const xmlnsString = "xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns:cim='http://iec.ch/TC57/2012/CIM-schema-cim16#' xmlns:md='http://iec.ch/TC57/61970-552/ModelDescription/1#' xmlns:entsoe='http://entsoe.eu/Secretariat/ProfileExtension/2#'";
|
||||
|
||||
var getRawXML = function() {
|
||||
return xmlDoc;
|
||||
};
|
||||
|
||||
var getBaseJson = function() {
|
||||
return jsonBaseData;
|
||||
};
|
||||
|
||||
/*
|
||||
* Convert a small data item into XML and add it to a node
|
||||
*/
|
||||
var addChild = function(object, name, doc, owner) {
|
||||
|
||||
let child;
|
||||
if (typeof object == "object") {
|
||||
child = doc.createElement(name);
|
||||
child.setAttribute("rdf:resource", object["rdf:resource"]);
|
||||
}
|
||||
else {
|
||||
child = doc.createElement(name);
|
||||
child.innerHTML = object;
|
||||
}
|
||||
owner.appendChild(child);
|
||||
};
|
||||
|
||||
var copyXmlDataIntoObject = function(object, node) {
|
||||
|
||||
let childNodes = node.children;
|
||||
for (let childIndex = 0; childIndex < childNodes.length; childIndex++) {
|
||||
let thisChild = childNodes[childIndex];
|
||||
if (thisChild.nodeType == Node.ELEMENT_NODE) {
|
||||
if (thisChild.attributes.length > 0) {
|
||||
object[thisChild.nodeName] = { "rdf:resource": thisChild.getAttribute("rdf:resource")};
|
||||
}
|
||||
else {
|
||||
object[thisChild.nodeName] = thisChild.innerHTML;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var importXmlNodeIntoGraph = function(graph, nodeCategory, node, id) {
|
||||
|
||||
let thisObject = { };
|
||||
|
||||
thisObject['rdfid'] = id
|
||||
|
||||
copyXmlDataIntoObject(thisObject, node);
|
||||
|
||||
if (!graph[nodeCategory]) {
|
||||
graph[nodeCategory] = {};
|
||||
}
|
||||
|
||||
/* add the new object to the graph */
|
||||
let categoryGraph = graph[nodeCategory];
|
||||
categoryGraph[id] = thisObject;
|
||||
};
|
||||
|
||||
var importAboutDataIntoGraph = function(graph, nodeCategory, thisNode, id) {
|
||||
|
||||
if (graph[nodeCategory] && graph[nodeCategory][id]) {
|
||||
let thisObject = graph[nodeCategory][id].about = [];
|
||||
copyXmlDataIntoObject(thisObject, thisNode);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* What is the rdf:ID attribute for this node
|
||||
*/
|
||||
var getRdfId = function(node) {
|
||||
|
||||
let rdfId = node.getAttribute("rdf:ID");
|
||||
return rdfId;
|
||||
};
|
||||
|
||||
/*
|
||||
* What is the rdf:about attribute for this node
|
||||
*/
|
||||
var getRdfAbout = function(node) {
|
||||
|
||||
let rdfAbout = node.getAttribute("rdf:about");
|
||||
return rdfAbout;
|
||||
};
|
||||
|
||||
/*
|
||||
* Clear the buffer of XML data that we use to handle multiple file imports
|
||||
*/
|
||||
var clearXmlData = function() {
|
||||
|
||||
xmlDoc = null;
|
||||
};
|
||||
|
||||
var xmlns = function(){
|
||||
|
||||
return xmlnsString;
|
||||
};
|
||||
|
||||
/*
|
||||
* Function to create a JSON document from an RDF (XML) DOM.
|
||||
* RDF is a shallow xml format so we don"t have to dig too
|
||||
* deep, a node will only ever have children or attributes.
|
||||
*/
|
||||
var createObjectGraphFromXml = function( xmlData ) {
|
||||
|
||||
let graph = {};
|
||||
let topLevelNodes = xmlData.documentElement.childNodes;
|
||||
|
||||
/* loop through all of the top level nodes */
|
||||
for (let topLevelIndex=0; topLevelIndex<topLevelNodes.length; topLevelIndex++) {
|
||||
let thisNode = topLevelNodes[topLevelIndex];
|
||||
if (thisNode.nodeType == Node.ELEMENT_NODE)
|
||||
{
|
||||
/* find out what type of node we are reading */
|
||||
let nodeCategory = thisNode.nodeName;
|
||||
let id = getRdfId(thisNode);
|
||||
if (id) {
|
||||
importXmlNodeIntoGraph(graph, nodeCategory, thisNode, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* we need all of the rdf:id nodes before importing the rdf:about nodes */
|
||||
for (let topLevelIndex=0; topLevelIndex<topLevelNodes.length; topLevelIndex++) {
|
||||
let thisNode = topLevelNodes[topLevelIndex];
|
||||
if (thisNode.nodeType == Node.ELEMENT_NODE)
|
||||
{
|
||||
/* find out what type of node we are reading */
|
||||
let nodeCategory = thisNode.nodeName;
|
||||
let id = getRdfAbout(thisNode);
|
||||
if (id) {
|
||||
importAboutDataIntoGraph(graph, nodeCategory, thisNode, id.substr(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
return graph;
|
||||
};
|
||||
|
||||
/*
|
||||
* Tell this module how many pieces the data will be arriving in
|
||||
*/
|
||||
var setRdfFileCount = function(count) {
|
||||
|
||||
rdfFileCount = count;
|
||||
};
|
||||
|
||||
/*
|
||||
* Have we received all the data files yet?
|
||||
*/
|
||||
var checkIfParseReady = function() {
|
||||
|
||||
if (rdfFileReceived > 0) {
|
||||
if (rdfFileCount == rdfFileReceived) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Here comes some more data
|
||||
*/
|
||||
var moreXmlData = function(text, draw=true) {
|
||||
|
||||
if (!xmlDoc) {
|
||||
xmlDoc = getDOM("<rdf:RDF "+xmlns()+"/>");
|
||||
}
|
||||
|
||||
let newDoc = getDOM(text);
|
||||
let nodes = newDoc.documentElement.childNodes;
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
if (nodes[i].nodeType == Node.ELEMENT_NODE) {
|
||||
if (nodes[i].nodeName != "md:FullModel") {
|
||||
xmlDoc.documentElement.appendChild(nodes[i].cloneNode(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rdfFileReceived++;
|
||||
if (checkIfParseReady()) {
|
||||
jsonBaseData = createObjectGraphFromXml(xmlDoc);
|
||||
rdfFileReceived = 0;
|
||||
rdfFileCount = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/*
|
||||
* Different method of getting DOM required for some platforms
|
||||
*/
|
||||
var getDOM = function(text) {
|
||||
|
||||
let newDoc;
|
||||
if ( window.DOMParser ) {
|
||||
newDoc = ( new DOMParser() ).parseFromString( text, "application/xml" );
|
||||
}
|
||||
else if( window.ActiveXObject ) {
|
||||
let xmlObject = new ActiveXObject( "Microsoft.XMLDOM" );
|
||||
xmlObject.async = false;
|
||||
xmlObject.loadXML( text );
|
||||
newDoc = xmlObject;
|
||||
xmlObject = undefined;
|
||||
}
|
||||
else {
|
||||
throw new Error( "Cannot find an XML parser!" );
|
||||
}
|
||||
return newDoc;
|
||||
};
|
||||
|
||||
var updateComponentInBaseJson = function(type, id, attribute, value) {
|
||||
jsonBaseData[type][id][attribute] = value
|
||||
};
|
||||
|
||||
return {
|
||||
getBaseJson,
|
||||
setRdfFileCount,
|
||||
clearXmlData,
|
||||
moreXmlData,
|
||||
getRawXML,
|
||||
updateComponentInBaseJson,
|
||||
};
|
||||
}());
|
||||
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
cimxml
|
||||
};
|
||||
}
|
1468
public/Pintura/js/handlebars.runtime.js
Normal file
2521
public/Pintura/templates/template.js
Normal file
|
@ -27,5 +27,12 @@
|
|||
To begin the development, run `npm start`.
|
||||
To create a production bundle, use `npm run build`.
|
||||
-->
|
||||
<link rel="stylesheet" href="%PUBLIC_URL%/Pintura/css/svg.css"/>
|
||||
<script type="text/javascript" src="%PUBLIC_URL%/Pintura/js/cimsvg.js"></script>
|
||||
<script type="text/javascript" src="%PUBLIC_URL%/Pintura/js/cimview.js"></script>
|
||||
<script type="text/javascript" src="%PUBLIC_URL%/Pintura/js/cimxml.js"></script>
|
||||
<script type="text/javascript" src="%PUBLIC_URL%/Pintura/js/cimjson.js"></script>
|
||||
<script type="text/javascript" src="%PUBLIC_URL%/Pintura/js/handlebars.runtime.js"></script>
|
||||
<script type="text/javascript" src="%PUBLIC_URL%/Pintura/templates/template.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -83,8 +83,10 @@ export default function createControls(widgetType = null, widget = null, session
|
|||
);
|
||||
break;
|
||||
case 'Image':
|
||||
// Restrict to only image file types (MIME)
|
||||
let imageControlFiles = files == null? [] : files.filter(file => file.type.includes('image'));
|
||||
dialogControls.push(
|
||||
<EditImageWidgetControl key={0} sessionToken={sessionToken} widget={widget} files={files} validate={(id) => validateForm(id)} simulation={simulation} handleChange={(e) => handleChange(e)} />,
|
||||
<EditImageWidgetControl key={0} sessionToken={sessionToken} widget={widget} files={imageControlFiles} validate={(id) => validateForm(id)} simulation={simulation} handleChange={(e) => handleChange(e)} />,
|
||||
<EditWidgetAspectControl key={1} widget={widget} handleChange={e => handleChange(e)} />
|
||||
);
|
||||
break;
|
||||
|
@ -141,6 +143,13 @@ export default function createControls(widgetType = null, widget = null, session
|
|||
<EditWidgetHTMLContent key={0} widget={widget} placeholder='HTML Code' controlId='content' handleChange={e => handleChange(e)} />
|
||||
);
|
||||
break;
|
||||
case 'Topology':
|
||||
// Restrict to only xml files (MIME)
|
||||
let topologyControlFiles = files == null? [] : files.filter( file => file.type.includes('xml'));
|
||||
dialogControls.push(
|
||||
<EditImageWidgetControl key={0} sessionToken={sessionToken} widget={widget} files={topologyControlFiles} validate={(id) => validateForm(id)} simulation={simulation} handleChange={(e) => handleChange(e)} />
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log('Non-valid widget type: ' + widgetType);
|
||||
|
|
|
@ -58,7 +58,7 @@ class EditWidgetDialog extends React.Component {
|
|||
// scale width to match aspect
|
||||
const aspectRatio = file.dimensions.width / file.dimensions.height;
|
||||
changeObject.width = this.state.temporal.height * aspectRatio;
|
||||
|
||||
|
||||
return changeObject;
|
||||
}
|
||||
|
||||
|
@ -90,8 +90,10 @@ class EditWidgetDialog extends React.Component {
|
|||
} else if (e.target.id === 'file') {
|
||||
changeObject[e.target.id] = e.target.value;
|
||||
|
||||
// get file and update size
|
||||
changeObject = this.assignAspectRatio(changeObject, e.target.value);
|
||||
// get file and update size (if it's an image)
|
||||
if ('lockAspect' in this.state.temporal && this.state.temporal.lockAspect) {
|
||||
changeObject = this.assignAspectRatio(changeObject, e.target.value);
|
||||
}
|
||||
} else if (e.target.type === 'checkbox') {
|
||||
changeObject[e.target.id] = e.target.checked;
|
||||
} else if (e.target.type === 'number') {
|
||||
|
|
|
@ -53,13 +53,13 @@ class ToolboxItem extends React.Component {
|
|||
|
||||
if (this.props.disabled === false) {
|
||||
return this.props.connectDragSource(
|
||||
<span className={itemClass}>
|
||||
<span className={itemClass} title={this.props.title}>
|
||||
{this.props.name}
|
||||
</span>
|
||||
, {dropEffect});
|
||||
} else {
|
||||
return (
|
||||
<span className={itemClass}>
|
||||
<span className={itemClass} title={this.props.title}>
|
||||
{this.props.name}
|
||||
</span>
|
||||
);
|
||||
|
|
|
@ -143,6 +143,10 @@ class WidgetFactory {
|
|||
case 'HTML':
|
||||
widget.content = '<i>Hello World</i>';
|
||||
break;
|
||||
case 'Topology':
|
||||
widget.width = 600;
|
||||
widget.height = 400;
|
||||
break;
|
||||
|
||||
default:
|
||||
widget.width = 100;
|
||||
|
|
176
src/components/widget-topology.js
Normal file
|
@ -0,0 +1,176 @@
|
|||
/**
|
||||
* File: widget-topology.js
|
||||
* Author: Ricardo Hernandez-Montoya <rhernandez@gridhound.de>
|
||||
* Date: 08.01.2018
|
||||
*
|
||||
* This file is part of VILLASweb.
|
||||
*
|
||||
* VILLASweb is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* VILLASweb is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with VILLASweb. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
import React from 'react';
|
||||
import {ReactSVGPanZoom} from 'react-svg-pan-zoom';
|
||||
import config from '../config';
|
||||
import '../styles/simple-spinner.css';
|
||||
|
||||
|
||||
// Do not show Pintura's grid
|
||||
const pinturaGridStyle = {
|
||||
display: 'none'
|
||||
}
|
||||
|
||||
// Avoid another color in the frontend
|
||||
const pinturaBackingStyle = {
|
||||
fill: 'transparent'
|
||||
}
|
||||
|
||||
// Center spinner
|
||||
const spinnerContainerStyle = {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
}
|
||||
|
||||
// Topology failed message
|
||||
const msgContainerStyle = Object.assign({
|
||||
backgroundColor: '#ececec'
|
||||
},spinnerContainerStyle)
|
||||
|
||||
const msgStyle = {
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
|
||||
// Initialize functions
|
||||
function attachComponentEvents() {
|
||||
window.onMouseOver = (e) => show(textSibling(e));
|
||||
window.onMouseLeave = (e) => hide(textSibling(e));
|
||||
}
|
||||
|
||||
function textSibling(e) {
|
||||
// Find sibling text element and toggle its visibility
|
||||
let gParent = e.target.parentElement;
|
||||
return gParent.getElementsByTagName('text')[0];
|
||||
}
|
||||
|
||||
function show(element) {
|
||||
element.style.visibility = 'inherit';
|
||||
}
|
||||
|
||||
function hide(element) {
|
||||
element.style.visibility = 'hidden';
|
||||
}
|
||||
|
||||
// De-initialize functions
|
||||
function detachComponentEvents() {
|
||||
window.onMouseOver = null;
|
||||
window.onMouseLeave = null;
|
||||
}
|
||||
|
||||
class WidgetTopology extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.svgElem = null;
|
||||
this.Viewer = null;
|
||||
|
||||
this.state = {
|
||||
visualizationState: 'initial'
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.svgElem) {
|
||||
window.cimjson.setImagePathBase(process.env.PUBLIC_URL + '/Pintura/');
|
||||
window.cimsvg.setSVG(this.svgElem); // function not available in upstream source
|
||||
window.cimview.init(this.svgElem);
|
||||
window.onMouseLeave = function() {};
|
||||
window.onMouseOver = function() {};
|
||||
window.onMouseLeave = function() {};
|
||||
window.onMouseUp = function() {};
|
||||
window.onMouseDown = function() {};
|
||||
window.onMouseMove = function() {};
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
detachComponentEvents();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const file = nextProps.files.find(file => file._id === nextProps.widget.file);
|
||||
// Ensure model is requested only once or a different was selected
|
||||
if (this.props.widget.file !== nextProps.widget.file || (this.state.visualizationState === 'initial' && file)) {
|
||||
this.setState({'visualizationState': 'loading' });
|
||||
if (file) {
|
||||
fetch(new Request('/' + config.publicPathBase + file.path))
|
||||
.then( response => {
|
||||
if (response.status === 200) {
|
||||
this.setState({'visualizationState': 'ready' });
|
||||
window.cimxml.clearXmlData()
|
||||
window.cimsvg.setFileCount(1);
|
||||
return response.text().then( contents => {
|
||||
window.cimsvg.loadFile(contents);
|
||||
attachComponentEvents();
|
||||
});
|
||||
} else {
|
||||
throw new Error('Request failed');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.setState({
|
||||
'visualizationState': 'show_message',
|
||||
'message': 'Topology could not be loaded.'});
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// No file has been selected
|
||||
if (!nextProps.widget.file) {
|
||||
this.setState({
|
||||
'visualizationState': 'show_message',
|
||||
'message': 'Select a topology model first.'});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
var markup = null;
|
||||
|
||||
switch(this.state.visualizationState) {
|
||||
case 'loading':
|
||||
markup = <div style={spinnerContainerStyle}><div className="loader" /></div>; break;
|
||||
case 'show_message':
|
||||
markup = <div style={msgContainerStyle}><div style={msgStyle}>{ this.state.message }</div></div>; break;
|
||||
default:
|
||||
markup = (<div>
|
||||
<ReactSVGPanZoom
|
||||
ref={Viewer => this.Viewer = Viewer}
|
||||
style={{outline: "1px solid black"}}
|
||||
detectAutoPan={false}
|
||||
width={this.props.widget.width-2} height={this.props.widget.height-2} >
|
||||
<svg width={this.props.widget.width} height={this.props.widget.height}>
|
||||
<svg ref={ c => this.svgElem = c }width={this.props.widget.width} height={this.props.widget.height}>
|
||||
<rect id="backing" style={pinturaBackingStyle} />
|
||||
<g id="grid" style={pinturaGridStyle} />
|
||||
<g id="diagrams"/>
|
||||
</svg>
|
||||
</svg>
|
||||
</ReactSVGPanZoom>
|
||||
</div>);
|
||||
}
|
||||
return markup;
|
||||
}
|
||||
}
|
||||
|
||||
export default WidgetTopology;
|
|
@ -454,6 +454,10 @@ class Visualization extends React.Component {
|
|||
</Button>
|
||||
);
|
||||
|
||||
// Only one topology widget at the time is supported
|
||||
let thereIsTopologyWidget = current_widgets && Object.values(current_widgets).filter( widget => widget.type === 'Topology').length > 0;
|
||||
let topologyItemMsg = !thereIsTopologyWidget? '' : 'Currently only one is supported';
|
||||
|
||||
return (
|
||||
<div className={boxClasses} >
|
||||
<div className='section-header box-header'>
|
||||
|
@ -482,6 +486,7 @@ class Visualization extends React.Component {
|
|||
<ToolboxItem name="Gauge" type="widget" />
|
||||
<ToolboxItem name="Box" type="widget" />
|
||||
<ToolboxItem name="HTML" type="html" />
|
||||
<ToolboxItem name="Topology" type="widget" disabled={thereIsTopologyWidget} title={topologyItemMsg}/>
|
||||
|
||||
<div className="section-buttons-group-right">
|
||||
{ editingControls }
|
||||
|
|
|
@ -43,6 +43,7 @@ import WidgetSlider from '../components/widget-slider';
|
|||
import WidgetGauge from '../components/widget-gauge';
|
||||
import WidgetBox from '../components/widget-box';
|
||||
import WidgetHTML from '../components/widget-html';
|
||||
import WidgetTopology from '../components/widget-topology';
|
||||
|
||||
import '../styles/widgets.css';
|
||||
|
||||
|
@ -188,6 +189,8 @@ class Widget extends React.Component {
|
|||
element = <WidgetBox widget={widget} editing={this.props.editing} />
|
||||
} else if (widget.type === 'HTML') {
|
||||
element = <WidgetHTML widget={widget} editing={this.props.editing} />
|
||||
} else if (widget.type === 'Topology') {
|
||||
element = <WidgetTopology widget={widget} files={this.state.files} />
|
||||
}
|
||||
|
||||
const widgetClasses = classNames({
|
||||
|
|
19
src/styles/simple-spinner.css
Normal file
|
@ -0,0 +1,19 @@
|
|||
|
||||
/*
|
||||
Basic spinner animation
|
||||
taken from: https://www.w3schools.com/howto/howto_css_loader.asp
|
||||
*/
|
||||
|
||||
.loader {
|
||||
border: 16px solid #f3f3f3;
|
||||
border-top: 16px solid #6ea2b0;
|
||||
border-radius: 50%;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|