Added more component dialogs and component links to settings page.

This commit is contained in:
Andrew Lalis 2022-05-23 09:36:49 +02:00
parent b5bcdc12e1
commit 6cfc630310
22 changed files with 1158 additions and 120 deletions

View File

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="256"
height="256"
viewBox="0 0 67.733332 67.733335"
version="1.1"
id="svg8"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
sodipodi:docname="label_icon.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4"
inkscape:cx="-7.53551"
inkscape:cy="167.89676"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:pagecheckerboard="true"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-229.26665)">
<path
style="fill:none;stroke:#000000;stroke-width:6.3499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 23.812499,294.90224 V 240.28468"
id="path841"
inkscape:connector-curvature="0" />
<rect
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:6.3499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect843"
width="38.364582"
height="24.095985"
x="23.812498"
y="233.40552"
rx="6.614583" />
<path
style="fill:none;stroke:#000000;stroke-width:4.23333334;stroke-linecap:round;stroke-linejoin:bevel;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="M 31.372024,241.57922 H 54.475819"
id="path845"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path847"
d="M 31.479768,247.91032 H 54.583563"
style="fill:none;stroke:#000000;stroke-width:4.23333311;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="256"
height="256"
viewBox="0 0 67.733332 67.733335"
version="1.1"
id="svg8"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
sodipodi:docname="segment-boundary_icon.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="56.595604"
inkscape:cy="134.48081"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:pagecheckerboard="true"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-229.26665)">
<path
style="fill:none;stroke:#000000;stroke-width:6.3499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 0.70544035,242.15266 H 28.234201 v 41.96132 H 1.1063446"
id="path869"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path871"
d="M 67.027893,284.11398 H 39.499132 v -41.96132 h 27.127856"
style="fill:none;stroke:#000000;stroke-width:6.3499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;stroke:#000000;stroke-width:6.3499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 6.9392617,256.58521 H 60.794072"
id="path873"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path875"
d="M 6.9392617,269.68142 H 60.794072"
style="fill:none;stroke:#000000;stroke-width:6.3499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="256"
height="256"
viewBox="0 0 67.733332 67.733335"
version="1.1"
id="svg8"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
sodipodi:docname="signal_icon.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="97.668938"
inkscape:cy="136.97831"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:pagecheckerboard="true"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-229.26665)">
<path
style="fill:none;stroke:#000000;stroke-width:6.35000002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 33.866667,296.90549 V 276.77826"
id="path815"
inkscape:connector-curvature="0" />
<rect
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:6.3499999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect817"
width="33.866665"
height="43.845234"
x="16.933334"
y="233.04643"
rx="6.6145835" />
<circle
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:4.23333311;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path819"
cx="33.866665"
cy="245.50073"
r="5.8586307" />
<circle
r="5.8586307"
cy="262.60416"
cx="33.866665"
id="circle821"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:4.23333311;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="256"
height="256"
viewBox="0 0 67.733332 67.733335"
version="1.1"
id="svg8"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
sodipodi:docname="switch_icon.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="34.945838"
inkscape:cy="171.1685"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:pagecheckerboard="true"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-229.26665)">
<path
style="fill:none;stroke:#000000;stroke-width:6.3499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 33.866667,291.12006 V 259.31498"
id="path838"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path840"
d="M 33.866667,259.31498 56.356255,236.8254"
style="fill:none;stroke:#000000;stroke-width:6.3499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;stroke:#000000;stroke-width:6.3499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 33.866667,259.31498 11.377087,236.8254"
id="path842"
inkscape:connector-curvature="0" />
<circle
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:6.3499999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path844"
cx="13.554182"
cy="238.06705"
r="7.7508163" />
<circle
r="7.7508163"
cy="238.06705"
cx="54.713692"
id="circle846"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:6.3499999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<circle
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:6.3499999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="circle848"
cx="33.866665"
cy="287.79529"
r="7.7508163" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -5,17 +5,14 @@ export function refreshComponents(rs) {
return new Promise((resolve, reject) => {
axios.get(`${API_URL}/rs/${rs.id}/c`)
.then(response => {
const previousSelectedComponentId = rs.selectedComponent ? rs.selectedComponent.id : null;
const previousSelectedComponentIds = rs.selectedComponents.map(c => c.id);
rs.selectedComponents.length = 0;
rs.components = response.data;
if (previousSelectedComponentId !== null) {
const previousComponent = rs.components.find(c => c.id === previousSelectedComponentId);
if (previousComponent) {
rs.selectedComponent = previousComponent;
} else {
rs.selectedComponent = null;
}
} else {
rs.selectedComponent = null;
for (let i = 0; i < previousSelectedComponentIds.length; i++) {
const component = rs.components.find(c => c.id === previousSelectedComponentIds[i]);
if (component) {
rs.selectedComponents.push(component);
}
}
resolve();
})
@ -42,7 +39,7 @@ export function refreshSomeComponents(rs, components) {
export function getComponent(rs, id) {
return new Promise((resolve, reject) => {
axios.get(`${this.apiUrl}/rs/${rs.id}/c/${id}`)
axios.get(`${API_URL}/rs/${rs.id}/c/${id}`)
.then(response => resolve(response.data))
.catch(reject);
});
@ -78,7 +75,8 @@ export function createComponent(rs, data) {
.then(() => {
const newComponent = rs.components.find(c => c.id === newComponentId);
if (newComponent) {
rs.selectedComponent = newComponent;
rs.selectedComponents.length = 0;
rs.selectedComponents.push(newComponent);
}
resolve();
})

View File

@ -17,7 +17,7 @@ export class LinkToken {
* @param {RailSystem} rs
* @return {Promise<LinkToken[]>}
*/
export function getTokens(rs) {
export function getLinkTokens(rs) {
return new Promise((resolve, reject) => {
axios.get(`${API_URL}/rs/${rs.id}/lt`)
.then(response => {
@ -54,4 +54,4 @@ export function deleteToken(rs, tokenId) {
.then(resolve)
.catch(reject);
});
}
}

View File

@ -10,7 +10,7 @@ export class RailSystem {
this.segments = [];
this.components = [];
this.websocket = null;
this.selectedComponent = null;
this.selectedComponents = [];
}
}

View File

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="256"
height="256"
viewBox="0 0 67.733332 67.733335"
version="1.1"
id="svg8"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
sodipodi:docname="label_icon.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4"
inkscape:cx="-7.53551"
inkscape:cy="167.89676"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:pagecheckerboard="true"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-229.26665)">
<path
style="fill:none;stroke:#000000;stroke-width:6.3499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 23.812499,294.90224 V 240.28468"
id="path841"
inkscape:connector-curvature="0" />
<rect
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:6.3499999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect843"
width="38.364582"
height="24.095985"
x="23.812498"
y="233.40552"
rx="6.614583" />
<path
style="fill:none;stroke:#000000;stroke-width:4.23333334;stroke-linecap:round;stroke-linejoin:bevel;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="M 31.372024,241.57922 H 54.475819"
id="path845"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path847"
d="M 31.479768,247.91032 H 54.583563"
style="fill:none;stroke:#000000;stroke-width:4.23333311;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="256"
height="256"
viewBox="0 0 67.733332 67.733335"
version="1.1"
id="svg8"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
sodipodi:docname="segment-boundary_icon.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="56.595604"
inkscape:cy="134.48081"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:pagecheckerboard="true"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-229.26665)">
<path
style="fill:none;stroke:#000000;stroke-width:6.3499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 0.70544035,242.15266 H 28.234201 v 41.96132 H 1.1063446"
id="path869"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path871"
d="M 67.027893,284.11398 H 39.499132 v -41.96132 h 27.127856"
style="fill:none;stroke:#000000;stroke-width:6.3499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;stroke:#000000;stroke-width:6.3499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 6.9392617,256.58521 H 60.794072"
id="path873"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path875"
d="M 6.9392617,269.68142 H 60.794072"
style="fill:none;stroke:#000000;stroke-width:6.3499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="256"
height="256"
viewBox="0 0 67.733332 67.733335"
version="1.1"
id="svg8"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
sodipodi:docname="signal_icon.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="97.668938"
inkscape:cy="136.97831"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:pagecheckerboard="true"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-229.26665)">
<path
style="fill:none;stroke:#000000;stroke-width:6.35000002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 33.866667,296.90549 V 276.77826"
id="path815"
inkscape:connector-curvature="0" />
<rect
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:6.3499999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect817"
width="33.866665"
height="43.845234"
x="16.933334"
y="233.04643"
rx="6.6145835" />
<circle
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:4.23333311;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path819"
cx="33.866665"
cy="245.50073"
r="5.8586307" />
<circle
r="5.8586307"
cy="262.60416"
cx="33.866665"
id="circle821"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:4.23333311;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="256"
height="256"
viewBox="0 0 67.733332 67.733335"
version="1.1"
id="svg8"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
sodipodi:docname="switch_icon.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="34.945838"
inkscape:cy="171.1685"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:pagecheckerboard="true"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-229.26665)">
<path
style="fill:none;stroke:#000000;stroke-width:6.3499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 33.866667,291.12006 V 259.31498"
id="path838"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path840"
d="M 33.866667,259.31498 56.356255,236.8254"
style="fill:none;stroke:#000000;stroke-width:6.3499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;stroke:#000000;stroke-width:6.3499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 33.866667,259.31498 11.377087,236.8254"
id="path842"
inkscape:connector-curvature="0" />
<circle
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:6.3499999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path844"
cx="13.554182"
cy="238.06705"
r="7.7508163" />
<circle
r="7.7508163"
cy="238.06705"
cx="54.713692"
id="circle846"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:6.3499999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<circle
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:6.3499999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="circle848"
cx="33.866665"
cy="287.79529"
r="7.7508163" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1,48 @@
<template>
<q-card>
<q-form>
<q-input
label="Name"
type="text"
v-model="component.name"
/>
<q-input
label="X"
type="number"
v-model="component.position.x"
/>
<q-input
label="Y"
type="number"
v-model="component.position.y"
/>
<q-input
label="Z"
type="number"
v-model="component.position.z"
/>
</q-form>
</q-card>
</template>
<script>
export default {
name: "AddComponentDialog",
data() {
return {
component: {
name: "",
position: {
x: 0,
y: 0,
z: 0
}
}
}
}
};
</script>
<style scoped>
</style>

View File

@ -1,54 +0,0 @@
<template>
<div class="flex">
<div class="row full-width">
<div class="col-md-6">
<q-list>
<q-item
v-for="component in railSystem.components"
:key="component.id"
clickable
v-ripple
>
<q-item-section>
<q-item-label>{{component.name}}</q-item-label>
<q-item-label caption>Id: {{component.id}}</q-item-label>
</q-item-section>
<q-item-section side top>
<q-item-label caption>x: {{component.position.x}}, y: {{component.position.y}}, z: {{component.position.z}}</q-item-label>
<q-item-label caption>{{component.type}}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</div>
</div>
</div>
<q-page-sticky position="bottom-right" :offset="[50, 18]">
<q-fab
icon="add"
direction="up"
color="accent"
>
<q-fab-action color="primary" label="Signal"/>
<q-fab-action color="primary" label="Switch"/>
<q-fab-action color="primary" label="Signal Boundary"/>
</q-fab>
</q-page-sticky>
</template>
<script>
import { RailSystem } from "src/api/railSystems";
export default {
name: "ComponentsView",
props: {
railSystem: {
type: RailSystem,
required: true
}
}
};
</script>
<style scoped>
</style>

View File

@ -5,27 +5,250 @@
Your browser doesn't support canvas.
</canvas>
</div>
<div class="col-md-4" v-if="railSystem.selectedComponent">
<selected-component-view :component="railSystem.selectedComponent" />
</div>
</div>
<q-scroll-area class="col-md-4" v-if="railSystem.selectedComponents.length > 0">
<div class="row" v-for="component in railSystem.selectedComponents" :key="component.id">
<div class="col full-width">
<selected-component-view :component="component" :rail-system="railSystem" />
</div>
</div>
</q-scroll-area>
</div>
<q-page-sticky position="bottom-right" :offset="[25, 25]">
<q-fab icon="add" direction="up" color="accent">
<q-fab-action @click="addSignalDialog = true">
<q-icon><img src="~assets/icons/signal_icon.svg"/></q-icon>
<q-tooltip>Add Signal</q-tooltip>
</q-fab-action>
<q-fab-action @click="addSegmentBoundaryDialog = true">
<q-icon><img src="~assets/icons/segment-boundary_icon.svg"/></q-icon>
<q-tooltip>Add Segment Boundary</q-tooltip>
</q-fab-action>
<q-fab-action @click="addSwitchDialog = true">
<q-icon><img src="~assets/icons/switch_icon.svg"/></q-icon>
<q-tooltip>Add Switch</q-tooltip>
</q-fab-action>
<q-fab-action @click="addLabelDialog = true">
<q-icon><img src="~assets/icons/label_icon.svg"/></q-icon>
<q-tooltip>Add Label</q-tooltip>
</q-fab-action>
</q-fab>
</q-page-sticky>
<!-- Add Signal Dialog -->
<q-dialog v-model="addSignalDialog" style="min-width: 400px" @hide="resetAll">
<q-card>
<q-form @submit="onAddSignalSubmit" @reset="resetAll">
<q-card-section>
<div class="text-h6">Add Signal</div>
<p>
Add a signal to the rail system.
</p>
</q-card-section>
<q-card-section>
<q-input
label="Name"
type="text"
v-model="addComponentData.name"
/>
<div class="row">
<q-input
label="X"
type="number"
class="col-sm-4"
v-model="addComponentData.position.x"
/>
<q-input
label="Y"
type="number"
class="col-sm-4"
v-model="addComponentData.position.y"
/>
<q-input
label="Z"
type="number"
class="col-sm-4"
v-model="addComponentData.position.z"
/>
</div>
</q-card-section>
<q-card-section>
<q-select
v-model="addSignalData.segment"
:options="railSystem.segments"
option-value="id"
option-label="name"
label="Segment"
/>
</q-card-section>
<q-card-actions align="right" class="text-primary">
<q-btn flat label="Cancel" type="reset" @click="addSignalDialog = false"/>
<q-btn flat label="Add Signal" type="submit"/>
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
<!-- Add Segment boundary -->
<q-dialog v-model="addSegmentBoundaryDialog" style="min-width: 400px" @hide="resetAll">
<q-card>
<q-form @submit="onAddSegmentBoundarySubmit" @reset="resetAll">
<q-card-section>
<div class="text-h6">Add Segment Boundary</div>
<p>
Add a segment boundary to the rail system. A segment boundary is a
point where a train can cross between two segments, or "blocks" in
the system. For example, a train may move from a junction segment to
a main line. This boundary is a place where a detector component can
update the system as trains pass.
</p>
</q-card-section>
<q-card-section>
<q-input
label="Name"
type="text"
v-model="addComponentData.name"
/>
<div class="row">
<q-input
label="X"
type="number"
class="col-sm-4"
v-model="addComponentData.position.x"
/>
<q-input
label="Y"
type="number"
class="col-sm-4"
v-model="addComponentData.position.y"
/>
<q-input
label="Z"
type="number"
class="col-sm-4"
v-model="addComponentData.position.z"
/>
</div>
</q-card-section>
<q-card-section>
<q-select
v-model="addSegmentBoundaryData.segments"
:options="railSystem.segments"
multiple
option-value="id"
option-label="name"
label="Segments"
/>
</q-card-section>
<q-card-actions align="right" class="text-primary">
<q-btn flat label="Cancel" type="reset" @click="addSegmentBoundaryDialog = false"/>
<q-btn flat label="Add Segment Boundary" type="submit"/>
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
<!-- Add Switch dialog -->
<q-dialog v-model="addSwitchDialog" @hide="resetAll"></q-dialog>
<!-- Add Label dialog -->
<q-dialog v-model="addLabelDialog" style="min-width: 400px" @hide="resetAll">
<q-card>
<q-form @submit="onAddLabelSubmit" @reset="resetAll">
<q-card-section>
<div class="text-h6">Add Label</div>
<p>
Add a label to the rail system as a piece of text on the map. Labels
are purely a visual component, and do not interact with the system
in any way, besides being a helpful point of reference for users.
</p>
</q-card-section>
<q-card-section>
<q-input
label="Name"
type="text"
v-model="addComponentData.name"
/>
<div class="row">
<q-input
label="X"
type="number"
class="col-sm-4"
v-model="addComponentData.position.x"
/>
<q-input
label="Y"
type="number"
class="col-sm-4"
v-model="addComponentData.position.y"
/>
<q-input
label="Z"
type="number"
class="col-sm-4"
v-model="addComponentData.position.z"
/>
</div>
</q-card-section>
<q-card-section>
<q-input
label="Label Text"
type="text"
v-model="addLabelData.text"
/>
</q-card-section>
<q-card-actions align="right" class="text-primary">
<q-btn flat label="Cancel" type="reset" @click="addLabelDialog = false"/>
<q-btn flat label="Add Label" type="submit"/>
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
</template>
<script>
import { RailSystem } from "src/api/railSystems";
import { draw, initMap } from "src/render/mapRenderer";
import SelectedComponentView from "components/rs/SelectedComponentView.vue";
import { useQuasar } from "quasar";
import { createComponent } from "src/api/components";
export default {
name: "MapView",
components: { SelectedComponentView },
setup() {
const quasar = useQuasar();
return {quasar};
},
props: {
railSystem: {
type: RailSystem,
required: true
}
},
data() {
return {
addSignalDialog: false,
addSegmentBoundaryDialog: false,
addSwitchDialog: false,
addLabelDialog: false,
addComponentData: {
name: "",
position: {
x: 0, y: 0, z: 0
}
},
addSignalData: {
segment: null
},
addSegmentBoundaryData: {
segments: []
},
addLabelData: {
text: ""
}
}
},
mounted() {
initMap(this.railSystem);
},
@ -39,6 +262,53 @@ export default {
},
deep: true
}
},
methods: {
onAddSignalSubmit() {
const data = {...this.addComponentData, ...this.addSignalData};
data.type = "SIGNAL";
this.attemptCreateComponent(data, "Signal added.", () => this.addSignalDialog = false);
},
onAddSegmentBoundarySubmit() {
const data = {...this.addComponentData, ...this.addSegmentBoundaryData};
data.type = "SEGMENT_BOUNDARY";
this.attemptCreateComponent(data, "Segment boundary added.", () => this.addSegmentBoundaryDialog = false);
},
segmentBoundarySegmentsValid() {
const set = new Set(this.addSegmentBoundaryData.segments);
return set.size === 2 && set.size === this.addSegmentBoundaryData.segments.length;
},
onAddLabelSubmit() {
const data = {...this.addComponentData, ...this.addLabelData};
data.type = "LABEL";
this.attemptCreateComponent(data, "Label added.", () => this.addLabelDialog = false);
},
resetAll() {
this.addComponentData.name = "";
this.addComponentData.position.x = 0;
this.addComponentData.position.y = 0;
this.addComponentData.position.z = 0;
this.addSignalDialog.segment = null;
this.addSegmentBoundaryData.segments = [];
this.addLabelData.text = "";
},
attemptCreateComponent(data, successMessage, successHandler) {
createComponent(this.railSystem, data)
.then(() => {
this.quasar.notify({
color: "positive",
message: successMessage
});
successHandler();
})
.catch(error => {
console.log(error);
this.quasar.notify({
color: "negative",
message: "An error occurred: " + error.response.data.message
});
});
}
}
};
</script>

View File

@ -0,0 +1,27 @@
<template>
<q-item clickable v-ripple>
<q-item-section>
<q-item-label>{{segment.name}}</q-item-label>
<q-item-label caption>Id: {{segment.id}}</q-item-label>
</q-item-section>
<q-item-section side v-if="segment.occupied">
<q-badge align="middle"></q-badge>
</q-item-section>
</q-item>
</template>
<script>
export default {
name: "SegmentListItem",
props: {
segment: {
type: Object,
required: true
}
}
};
</script>
<style scoped>
</style>

View File

@ -30,27 +30,18 @@
expand-separator
>
<q-list>
<q-item
v-for="segment in [component.segment]"
:key="segment.id"
clickable
v-ripple
>
<q-item-section>
<q-item-label>Linked to segment: {{segment.name}}</q-item-label>
<q-item-label caption>Id: {{segment.id}}</q-item-label>
</q-item-section>
</q-item>
<segment-list-item v-for="segment in [component.segment]" :key="segment.id" :segment="segment" />
</q-list>
</q-expansion-item>
<!-- Path node info -->
<q-expansion-item
label="Path Node Information"
label="Connected Nodes"
v-if="component.connectedNodes !== undefined && component.connectedNodes !== null"
content-inset-level="0.5"
switch-toggle-side
expand-separator
class="q-gutter-md"
>
<q-list>
<q-item
@ -70,24 +61,14 @@
<!-- Segment boundary info -->
<q-expansion-item
label="Segment Boundary Information"
label="Connected Segments"
v-if="component.type === 'SEGMENT_BOUNDARY'"
content-inset-level="0.5"
switch-toggle-side
expand-separator
>
<q-list>
<q-item
v-for="segment in component.segments"
:key="segment.id"
clickable
v-ripple
>
<q-item-section>
<q-item-label>{{segment.name}}</q-item-label>
<q-item-label caption>Id: {{segment.id}}</q-item-label>
</q-item-section>
</q-item>
<segment-list-item v-for="segment in component.segments" :key="segment.id" :segment="segment"/>
</q-list>
</q-expansion-item>
@ -120,6 +101,12 @@
</q-item>
</q-list>
</q-expansion-item>
<q-item>
<q-item-section side>
<q-btn color="warning" label="Remove" size="sm" @click="remove(component)"/>
</q-item-section>
</q-item>
</q-list>
</div>
</template>
@ -127,25 +114,56 @@
<script>
import { RailSystem } from "src/api/railSystems";
import { useRailSystemsStore } from "stores/railSystemsStore";
import SegmentListItem from "components/rs/SegmentListItem.vue";
import { useQuasar } from "quasar";
import { removeComponent } from "src/api/components";
export default {
name: "SelectedComponentView",
components: { SegmentListItem },
setup() {
const rsStore = useRailSystemsStore();
return {rsStore};
const quasar = useQuasar();
return {rsStore, quasar};
},
props: {
component: {
type: Object,
required: true
},
railSystem: {
type: RailSystem,
required: true
}
},
methods: {
select(component) {
const c = this.rsStore.selectedRailSystem.components.find(cp => cp.id === component.id);
if (c) {
this.rsStore.selectedRailSystem.selectedComponent = c;
this.rsStore.selectedRailSystem.selectedComponents.length = 0;
this.rsStore.selectedRailSystem.selectedComponents.push(c);
}
},
remove(component) {
this.quasar.dialog({
title: "Confirm Removal",
message: "Are you sure you want to remove this component? This cannot be undone.",
cancel: true
}).onOk(() => {
removeComponent(this.railSystem, component.id)
.then(() => {
this.quasar.notify({
color: "positive",
message: "Component has been removed."
});
})
.catch(error => {
this.quasar.notify({
color: "negative",
message: "An error occurred: " + error.response.data.message
});
});
});
}
}
};

View File

@ -1,16 +1,22 @@
<template>
<div>
<p>
Settings view. Nothing here yet.
</p>
</div>
<q-list>
<q-expansion-item
expand-separator
label="Component Links"
caption="Link components to your system."
>
<link-tokens-view :rail-system="railSystem"/>
</q-expansion-item>
</q-list>
</template>
<script>
import { RailSystem } from "src/api/railSystems";
import LinkTokensView from "components/rs/settings/LinkTokensView.vue";
export default {
name: "SettingsView",
components: { LinkTokensView },
props: {
railSystem: {
type: RailSystem,

View File

@ -0,0 +1,48 @@
<template>
<q-list>
<q-item>
<q-item-section side>
<q-btn label="Add Link" color="positive" />
</q-item-section>
</q-item>
<q-item
v-for="token in linkTokens"
:key="token.id"
>
<q-item-section>
<q-item-label>{{token.name}}</q-item-label>
<q-item-label caption>{{token.id}}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</template>
<script>
import { RailSystem } from "src/api/railSystems";
import { getLinkTokens } from "src/api/linkTokens";
export default {
name: "LinkTokensView",
props: {
railSystem: {
type: RailSystem,
required: true
}
},
data() {
return {
linkTokens: [],
addTokenDialog: false
};
},
mounted() {
getLinkTokens(this.railSystem)
.then(tokens => this.linkTokens = tokens);
}
};
</script>
<style scoped>
</style>

View File

@ -9,7 +9,6 @@
>
<q-tab name="map" label="Map"/>
<q-tab name="segments" label="Segments"/>
<q-tab name="components" label="Components"/>
<q-tab name="settings" label="Settings"/>
</q-tabs>
<q-tab-panels v-model="panel">
@ -19,9 +18,6 @@
<q-tab-panel name="segments">
<segments-view :rail-system="railSystem"/>
</q-tab-panel>
<q-tab-panel name="components">
<components-view :rail-system="railSystem"/>
</q-tab-panel>
<q-tab-panel name="settings">
<settings-view :rail-system="railSystem"/>
</q-tab-panel>
@ -36,12 +32,11 @@
import { useRailSystemsStore } from "stores/railSystemsStore";
import MapView from "components/rs/MapView.vue";
import SegmentsView from "components/rs/SegmentsView.vue";
import ComponentsView from "components/rs/ComponentsView.vue";
import SettingsView from "components/rs/SettingsView.vue";
export default {
name: "RailSystemPage",
components: { SettingsView, ComponentsView, SegmentsView, MapView },
components: { SettingsView, SegmentsView, MapView },
data() {
return {
panel: "map",

View File

@ -19,6 +19,8 @@ export function drawComponent(ctx, worldTx, component) {
drawSegmentBoundary(ctx, component);
} else if (component.type === "SWITCH") {
drawSwitch(ctx, component);
} else if (component.type === "LABEL") {
drawLabel(ctx, component);
}
ctx.setTransform(tx.translate(0.75, -0.75));
@ -99,6 +101,15 @@ function drawSwitch(ctx, sw) {
ctx.stroke();
}
function drawLabel(ctx, lbl) {
ctx.fillStyle = "black";
circle(ctx, 0, 0, 0.1);
ctx.fill();
ctx.strokeStyle = "black";
ctx.font = "0.5px Sans-Serif";
ctx.fillText(lbl.text, 0.1, -0.2);
}
function drawOnlineIndicator(ctx, component) {
ctx.lineWidth = 0.1;
if (component.online) {

View File

@ -147,14 +147,11 @@ function getWorldTransform() {
}
export function isComponentHovered(component) {
for (let i = 0; i < hoveredElements.length; i++) {
if (hoveredElements[i].id === component.id) return true;
}
return false;
return hoveredElements.some(c => c.id === component.id);
}
export function isComponentSelected(component) {
return railSystem.selectedComponent !== null && railSystem.selectedComponent.id === component.id;
return railSystem.selectedComponents.some(c => c.id === component.id);
}
/**
@ -209,10 +206,11 @@ function onMouseUp() {
mapTranslation.y += mapDragTranslation.y;
finishedDrag = true;
}
if (hoveredElements.length === 1) {
railSystem.selectedComponent = hoveredElements[0];
if (hoveredElements.length > 0) {
railSystem.selectedComponents.length = 0;
railSystem.selectedComponents.push(...hoveredElements);
} else if (!finishedDrag) {
railSystem.selectedComponent = null;
railSystem.selectedComponents.length = 0;
}
mapDragOrigin = null;
mapDragTranslation = null;

View File

@ -3,7 +3,6 @@ package nl.andrewl.railsignalapi.rest.dto.component.in;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import nl.andrewl.railsignalapi.model.component.Label;
import nl.andrewl.railsignalapi.model.component.Position;
import javax.validation.constraints.NotBlank;
@ -15,7 +14,7 @@ import javax.validation.constraints.NotNull;
@JsonSubTypes.Type(value = SignalPayload.class, name = "SIGNAL"),
@JsonSubTypes.Type(value = SwitchPayload.class, name = "SWITCH"),
@JsonSubTypes.Type(value = SegmentBoundaryPayload.class, name = "SEGMENT_BOUNDARY"),
@JsonSubTypes.Type(value = Label.class, name = "LABEL")
@JsonSubTypes.Type(value = LabelPayload.class, name = "LABEL")
})
public abstract class ComponentPayload {
@NotNull @NotBlank