Compare commits
76 Commits
v0.1.1-alp
...
v0.2.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b72d92ffd7 | ||
|
|
e04e4b2dec | ||
|
|
35709987e7 | ||
|
|
bcc6b5b5c3 | ||
|
|
a047a04d09 | ||
|
|
f6d16944c2 | ||
|
|
ee361f12f2 | ||
|
|
14cdec9615 | ||
|
|
5cff54bfde | ||
|
|
a9e18e42d3 | ||
|
|
6ce9b2ddea | ||
|
|
06f10cd399 | ||
|
|
3124a0f6b5 | ||
|
|
090973a3d1 | ||
|
|
992b1d40c9 | ||
|
|
41be6402cd | ||
|
|
c3c84b2115 | ||
|
|
f24c57cc18 | ||
|
|
cfd98e74ea | ||
|
|
be69aeb69e | ||
|
|
79f616cf8d | ||
|
|
d77735581a | ||
|
|
77d39c17b8 | ||
|
|
3eefe441b4 | ||
|
|
e84fa7caaa | ||
|
|
a3d919bad9 | ||
|
|
8707982769 | ||
|
|
39698c66a3 | ||
|
|
b56f1ca547 | ||
|
|
4a90193426 | ||
|
|
7eee469bed | ||
|
|
316261e01e | ||
|
|
df2aef498f | ||
|
|
f4bb484c7d | ||
|
|
f4ddbbd1af | ||
|
|
c3233ad999 | ||
|
|
1f51d69126 | ||
|
|
14ae0d083f | ||
|
|
8d951410e5 | ||
|
|
7605dd26ff | ||
|
|
1b093782c3 | ||
|
|
2947d55bc5 | ||
|
|
103fcde426 | ||
|
|
3193eb0021 | ||
|
|
0456bbef52 | ||
|
|
c54c7d2d78 | ||
|
|
9c834e4072 | ||
|
|
b10522498b | ||
|
|
fd23fd3034 | ||
|
|
3aa6d27ed3 | ||
|
|
b98c392f79 | ||
|
|
071942b632 | ||
|
|
5dda45ad22 | ||
|
|
6ffcb76f03 | ||
|
|
6993650ff8 | ||
|
|
6b22c1ef63 | ||
|
|
ee6fadfb36 | ||
|
|
2f5b9d1f94 | ||
|
|
b9f32a5b82 | ||
|
|
6f64bd1622 | ||
|
|
ff20eec472 | ||
|
|
9c9d53f3fb | ||
|
|
b4e34bf9e4 | ||
|
|
73a539bf94 | ||
|
|
ac44c208a8 | ||
|
|
04618cb247 | ||
|
|
3bdba116e8 | ||
|
|
ea94d8ac24 | ||
|
|
ab51a76075 | ||
|
|
cae9b16d97 | ||
|
|
ee6537de7c | ||
|
|
efae7c23ff | ||
|
|
df79f6577b | ||
|
|
14147168f9 | ||
|
|
da008c220d | ||
|
|
d86a250575 |
@@ -4,6 +4,7 @@ var cookieParser = require('cookie-parser');
|
||||
var logger = require('morgan');
|
||||
var fs = require('fs');
|
||||
|
||||
var atcRouter = require('./routes/api/atc');
|
||||
var indexRouter = require('./routes/index');
|
||||
var uikitRouter = require('./routes/uikit');
|
||||
var usersRouter = require('./routes/users');
|
||||
@@ -17,6 +18,7 @@ app.use(cookieParser());
|
||||
app.use(express.static(path.join(__dirname, 'public')));
|
||||
|
||||
app.use('/', indexRouter);
|
||||
app.use('/api/atc', atcRouter);
|
||||
app.use('/users', usersRouter);
|
||||
app.use('/uikit', uikitRouter);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ const DEMO_UNIT_DATA = {
|
||||
["1"]:{
|
||||
baseData: {
|
||||
AI: true,
|
||||
name: "F-5E",
|
||||
name: "KC-135",
|
||||
unitName: "Olympus 1-1",
|
||||
groupName: "Group 1",
|
||||
alive: true,
|
||||
@@ -49,7 +49,16 @@ const DEMO_UNIT_DATA = {
|
||||
currentTask: "Holding",
|
||||
activePath: undefined,
|
||||
targetSpeed: 400,
|
||||
targetAltitude: 3000
|
||||
targetAltitude: 3000,
|
||||
isTanker: false,
|
||||
TACANOn: false,
|
||||
TACANChannel: 32,
|
||||
TACANXY: "Y",
|
||||
TACANCallsign: "ASD",
|
||||
radioFrequency: 123.750,
|
||||
radioCallsign: 2,
|
||||
radioCallsignNumber: 3,
|
||||
radioAMFM: "FM"
|
||||
},
|
||||
optionsData: {
|
||||
ROE: "Designated",
|
||||
@@ -625,6 +634,10 @@ class DemoDataGenerator {
|
||||
|
||||
units(req, res){
|
||||
var ret = this.demoUnits;
|
||||
for (let ID in this.demoUnits["units"]){
|
||||
this.demoUnits["units"][ID].flightData.latitude += 0.00001;
|
||||
}
|
||||
ret.time = Date.now();
|
||||
res.send(JSON.stringify(ret));
|
||||
};
|
||||
|
||||
|
||||
4
client/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "DCSOlympus",
|
||||
"version": "0.1.0-alpha",
|
||||
"version": "0.1.1-alpha",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "DCSOlympus",
|
||||
"version": "0.1.0-alpha",
|
||||
"version": "0.1.1-alpha",
|
||||
"dependencies": {
|
||||
"@types/geojson": "^7946.0.10",
|
||||
"@types/leaflet": "^1.9.0",
|
||||
|
||||
1
client/public/images/icons/arrow-pointer-solid.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M0 55.2V426c0 12.2 9.9 22 22 22c6.3 0 12.4-2.7 16.6-7.5L121.2 346l58.1 116.3c7.9 15.8 27.1 22.2 42.9 14.3s22.2-27.1 14.3-42.9L179.8 320H297.9c12.2 0 22.1-9.9 22.1-22.1c0-6.3-2.7-12.3-7.4-16.5L38.6 37.9C34.3 34.1 28.9 32 23.2 32C10.4 32 0 42.4 0 55.2z"/></svg>
|
||||
|
After Width: | Height: | Size: 498 B |
1
client/public/images/icons/arrows-to-eye-solid.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M15 15C24.4 5.7 39.6 5.7 49 15l63 63V40c0-13.3 10.7-24 24-24s24 10.7 24 24v96c0 13.3-10.7 24-24 24H40c-13.3 0-24-10.7-24-24s10.7-24 24-24H78.1L15 49C5.7 39.6 5.7 24.4 15 15zM133.5 243.9C158.6 193.6 222.7 112 320 112s161.4 81.6 186.5 131.9c3.8 7.6 3.8 16.5 0 24.2C481.4 318.4 417.3 400 320 400s-161.4-81.6-186.5-131.9c-3.8-7.6-3.8-16.5 0-24.2zM320 320a64 64 0 1 0 0-128 64 64 0 1 0 0 128zM591 15c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-63 63H600c13.3 0 24 10.7 24 24s-10.7 24-24 24H504c-13.3 0-24-10.7-24-24V40c0-13.3 10.7-24 24-24s24 10.7 24 24V78.1l63-63zM15 497c-9.4-9.4-9.4-24.6 0-33.9l63-63H40c-13.3 0-24-10.7-24-24s10.7-24 24-24h96c13.3 0 24 10.7 24 24v96c0 13.3-10.7 24-24 24s-24-10.7-24-24V433.9L49 497c-9.4 9.4-24.6 9.4-33.9 0zm576 0l-63-63V472c0 13.3-10.7 24-24 24s-24-10.7-24-24V376c0-13.3 10.7-24 24-24h96c13.3 0 24 10.7 24 24s-10.7 24-24 24H561.9l63 63c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
1
client/public/images/icons/bullseye-solid.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M448 256A192 192 0 1 0 64 256a192 192 0 1 0 384 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm256 80a80 80 0 1 0 0-160 80 80 0 1 0 0 160zm0-224a144 144 0 1 1 0 288 144 144 0 1 1 0-288zM224 256a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"/></svg>
|
||||
|
After Width: | Height: | Size: 480 B |
63
client/public/images/icons/echelon-lh.svg
Normal file
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<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="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg14"
|
||||
sodipodi:docname="echelon-lh.svg"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)">
|
||||
<metadata
|
||||
id="metadata20">
|
||||
<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>
|
||||
<defs
|
||||
id="defs18" />
|
||||
<sodipodi:namedview
|
||||
inkscape:document-rotation="0"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
id="namedview16"
|
||||
showgrid="false"
|
||||
inkscape:zoom="34.345186"
|
||||
inkscape:cx="9.7964424"
|
||||
inkscape:cy="8.7196642"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg14" />
|
||||
<path
|
||||
d="m 11.760336,0.82277727 c 0.03507,-0.0819211 0.116519,-0.13468436 0.20644,-0.13468436 0.08985,0 0.171299,0.0527631 0.206441,0.13468436 L 12.79247,2.2515013 c 0.04782,0.1110719 0.07304,0.2290997 0.07304,0.3498999 v 1.0690957 l 2.022304,1.1663106 V 4.5758186 c 0,-0.1846888 0.150282,-0.3332707 0.337016,-0.3332707 0.186803,0 0.337085,0.1485819 0.337085,0.3332707 V 5.353336 5.7976518 6.1308542 c 0,0.1846885 -0.150282,0.3332711 -0.337085,0.3332711 -0.186734,0 -0.337016,-0.1485826 -0.337016,-0.3332711 V 6.0198095 H 12.865509 V 6.473799 l 0.821559,0.7123218 c 0.04913,0.041627 0.07724,0.1027332 0.07724,0.1665674 v 0.2221572 c 0,0.1222175 -0.101084,0.2221571 -0.224701,0.2221571 H 12.191408 V 6.9083724 c 0,-0.1221494 -0.101085,-0.22209 -0.224632,-0.22209 -0.123616,0 -0.2247,0.099941 -0.2247,0.22209 v 0.8886301 h -1.348203 c -0.123616,0 -0.2247,-0.09994 -0.2247,-0.2221571 V 7.3526882 c 0,-0.063834 0.02804,-0.1249429 0.07717,-0.1665674 L 11.067975,6.473799 V 6.0198095 H 9.0456705 v 0.1110447 c 0,0.1846885 -0.1502827,0.3332711 -0.3370162,0.3332711 -0.1868027,0 -0.3370854,-0.1485826 -0.3370854,-0.3332711 V 5.7976518 5.353336 4.5758186 c 0,-0.1846888 0.1502827,-0.3332707 0.3370854,-0.3332707 0.1867335,0 0.3370162,0.1485819 0.3370162,0.3332707 V 4.8368075 L 11.067975,3.6704969 V 2.6014012 c 0,-0.1208002 0.02529,-0.238828 0.07304,-0.3498999 z"
|
||||
fill="#202831"
|
||||
id="path2"
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.685147" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.685147"
|
||||
id="path2-4"
|
||||
fill="#202831"
|
||||
d="m 4.3098319,8.5178559 c 0.03507,-0.081921 0.116519,-0.1346843 0.206441,-0.1346843 0.08985,0 0.171299,0.052763 0.206441,0.1346843 L 5.3419659,9.94658 c 0.04782,0.111072 0.07304,0.2291 0.07304,0.3499 v 1.069096 l 2.0223043,1.166311 v -0.26099 c 0,-0.184688 0.1502822,-0.33327 0.3370163,-0.33327 0.1868027,0 0.3370848,0.148582 0.3370848,0.33327 v 0.777518 0.444316 0.333202 c 0,0.184689 -0.1502821,0.333271 -0.3370848,0.333271 -0.1867341,0 -0.3370163,-0.148582 -0.3370163,-0.333271 V 13.714889 H 5.4150049 v 0.453989 l 0.821559,0.712322 c 0.04913,0.04163 0.07724,0.102733 0.07724,0.166567 v 0.222157 c 0,0.122218 -0.101084,0.222158 -0.2247,0.222158 h -1.348203 v -0.888631 c 0,-0.122149 -0.101084,-0.22209 -0.224631,-0.22209 -0.123616,0 -0.224701,0.09994 -0.224701,0.22209 v 0.888631 h -1.348202 c -0.123616,0 -0.224701,-0.09994 -0.224701,-0.222158 v -0.222157 c 0,-0.06383 0.02804,-0.124943 0.07717,-0.166567 l 0.821635,-0.712322 v -0.453989 h -2.022304 v 0.111044 c 0,0.184689 -0.150283,0.333271 -0.337016,0.333271 -0.186803,0 -0.33708499,-0.148582 -0.33708499,-0.333271 v -0.333202 -0.444316 -0.777518 c 0,-0.184688 0.15028199,-0.33327 0.33708499,-0.33327 0.186733,0 0.337016,0.148582 0.337016,0.33327 v 0.26099 l 2.022304,-1.166311 V 10.29648 c 0,-0.1208 0.02529,-0.238828 0.07304,-0.3499 z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.3 KiB |
63
client/public/images/icons/echelon-rh.svg
Normal file
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<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="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg14"
|
||||
sodipodi:docname="echelon-rh.svg"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)">
|
||||
<metadata
|
||||
id="metadata20">
|
||||
<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>
|
||||
<defs
|
||||
id="defs18" />
|
||||
<sodipodi:namedview
|
||||
inkscape:document-rotation="0"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
id="namedview16"
|
||||
showgrid="false"
|
||||
inkscape:zoom="34.345186"
|
||||
inkscape:cx="9.7964424"
|
||||
inkscape:cy="8.7196642"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg14" />
|
||||
<path
|
||||
d="M 4.7226453,0.82277727 C 4.687573,0.74085619 4.6061264,0.68809291 4.516205,0.68809291 c -0.089853,0 -0.1712993,0.0527631 -0.206441,0.13468436 L 3.6905114,2.2515013 c -0.04782,0.1110719 -0.07304,0.2290997 -0.07304,0.3498999 V 3.6704969 L 1.5951671,4.8368075 V 4.5758186 c 0,-0.1846888 -0.1502822,-0.3332707 -0.3370163,-0.3332707 -0.1868027,0 -0.33708489,0.1485819 -0.33708489,0.3332707 V 5.353336 5.7976518 6.1308542 c 0,0.1846885 0.15028219,0.3332711 0.33708489,0.3332711 0.1867341,0 0.3370163,-0.1485826 0.3370163,-0.3332711 V 6.0198095 H 3.6174719 V 6.473799 l -0.821559,0.7123218 c -0.049132,0.041627 -0.077243,0.1027332 -0.077243,0.1665674 v 0.2221572 c 0,0.1222175 0.1010844,0.2221571 0.2247007,0.2221571 H 4.2915732 V 6.9083724 c 0,-0.1221494 0.1010844,-0.22209 0.2246318,-0.22209 0.1236157,0 0.2247001,0.099941 0.2247001,0.22209 v 0.8886301 h 1.3482024 c 0.1236163,0 0.2247007,-0.09994 0.2247007,-0.2221571 V 7.3526882 c 0,-0.063834 -0.028044,-0.1249429 -0.077174,-0.1665674 L 5.4150063,6.473799 V 6.0198095 h 2.0223041 v 0.1110447 c 0,0.1846885 0.1502827,0.3332711 0.3370162,0.3332711 0.1868027,0 0.3370854,-0.1485826 0.3370854,-0.3332711 V 5.7976518 5.353336 4.5758186 c 0,-0.1846888 -0.1502827,-0.3332707 -0.3370854,-0.3332707 -0.1867335,0 -0.3370162,0.1485819 -0.3370162,0.3332707 V 4.8368075 L 5.4150063,3.6704969 V 2.6014012 c 0,-0.1208002 -0.025289,-0.238828 -0.07304,-0.3498999 z"
|
||||
fill="#202831"
|
||||
id="path2"
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.685147" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.685147"
|
||||
id="path2-4"
|
||||
fill="#202831"
|
||||
d="m 12.173149,8.5178559 c -0.03507,-0.081921 -0.116519,-0.1346843 -0.206441,-0.1346843 -0.08985,0 -0.171299,0.052763 -0.206441,0.1346843 L 11.141015,9.94658 c -0.04782,0.111072 -0.07304,0.2291 -0.07304,0.3499 v 1.069096 l -2.0223043,1.166311 v -0.26099 c 0,-0.184688 -0.1502822,-0.33327 -0.3370163,-0.33327 -0.1868027,0 -0.3370848,0.148582 -0.3370848,0.33327 v 0.777518 0.444316 0.333202 c 0,0.184689 0.1502821,0.333271 0.3370848,0.333271 0.1867341,0 0.3370163,-0.148582 0.3370163,-0.333271 v -0.111044 h 2.0223053 v 0.453989 L 10.246417,14.8812 c -0.04913,0.04163 -0.07724,0.102733 -0.07724,0.166567 v 0.222157 c 0,0.122218 0.101084,0.222158 0.2247,0.222158 h 1.348203 v -0.888631 c 0,-0.122149 0.101084,-0.22209 0.224631,-0.22209 0.123616,0 0.224701,0.09994 0.224701,0.22209 v 0.888631 h 1.348202 c 0.123616,0 0.224701,-0.09994 0.224701,-0.222158 v -0.222157 c 0,-0.06383 -0.02804,-0.124943 -0.07717,-0.166567 L 12.86551,14.168878 v -0.453989 h 2.022304 v 0.111044 c 0,0.184689 0.150283,0.333271 0.337016,0.333271 0.186803,0 0.337085,-0.148582 0.337085,-0.333271 v -0.333202 -0.444316 -0.777518 c 0,-0.184688 -0.150282,-0.33327 -0.337085,-0.33327 -0.186733,0 -0.337016,0.148582 -0.337016,0.33327 v 0.26099 L 12.86551,11.365576 V 10.29648 c 0,-0.1208 -0.02529,-0.238828 -0.07304,-0.3499 z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
63
client/public/images/icons/echelon.svg
Normal file
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<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="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg14"
|
||||
sodipodi:docname="echelon.svg"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)">
|
||||
<metadata
|
||||
id="metadata20">
|
||||
<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>
|
||||
<defs
|
||||
id="defs18" />
|
||||
<sodipodi:namedview
|
||||
inkscape:document-rotation="0"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
id="namedview16"
|
||||
showgrid="false"
|
||||
inkscape:zoom="34.345186"
|
||||
inkscape:cx="9.7964424"
|
||||
inkscape:cy="8.7196642"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg14" />
|
||||
<path
|
||||
d="M 4.7226453,0.82277727 C 4.687573,0.74085619 4.6061264,0.68809291 4.516205,0.68809291 c -0.089853,0 -0.1712993,0.0527631 -0.206441,0.13468436 L 3.6905114,2.2515013 c -0.04782,0.1110719 -0.07304,0.2290997 -0.07304,0.3498999 V 3.6704969 L 1.5951671,4.8368075 V 4.5758186 c 0,-0.1846888 -0.1502822,-0.3332707 -0.3370163,-0.3332707 -0.1868027,0 -0.33708489,0.1485819 -0.33708489,0.3332707 V 5.353336 5.7976518 6.1308542 c 0,0.1846885 0.15028219,0.3332711 0.33708489,0.3332711 0.1867341,0 0.3370163,-0.1485826 0.3370163,-0.3332711 V 6.0198095 H 3.6174719 V 6.473799 l -0.821559,0.7123218 c -0.049132,0.041627 -0.077243,0.1027332 -0.077243,0.1665674 v 0.2221572 c 0,0.1222175 0.1010844,0.2221571 0.2247007,0.2221571 H 4.2915732 V 6.9083724 c 0,-0.1221494 0.1010844,-0.22209 0.2246318,-0.22209 0.1236157,0 0.2247001,0.099941 0.2247001,0.22209 v 0.8886301 h 1.3482024 c 0.1236163,0 0.2247007,-0.09994 0.2247007,-0.2221571 V 7.3526882 c 0,-0.063834 -0.028044,-0.1249429 -0.077174,-0.1665674 L 5.4150063,6.473799 V 6.0198095 h 2.0223041 v 0.1110447 c 0,0.1846885 0.1502827,0.3332711 0.3370162,0.3332711 0.1868027,0 0.3370854,-0.1485826 0.3370854,-0.3332711 V 5.7976518 5.353336 4.5758186 c 0,-0.1846888 -0.1502827,-0.3332707 -0.3370854,-0.3332707 -0.1867335,0 -0.3370162,0.1485819 -0.3370162,0.3332707 V 4.8368075 L 5.4150063,3.6704969 V 2.6014012 c 0,-0.1208002 -0.025289,-0.238828 -0.07304,-0.3498999 z"
|
||||
fill="#202831"
|
||||
id="path2"
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.685147" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.685147"
|
||||
id="path2-4"
|
||||
fill="#202831"
|
||||
d="m 12.173149,8.5178559 c -0.03507,-0.081921 -0.116519,-0.1346843 -0.206441,-0.1346843 -0.08985,0 -0.171299,0.052763 -0.206441,0.1346843 L 11.141015,9.94658 c -0.04782,0.111072 -0.07304,0.2291 -0.07304,0.3499 v 1.069096 l -2.0223043,1.166311 v -0.26099 c 0,-0.184688 -0.1502822,-0.33327 -0.3370163,-0.33327 -0.1868027,0 -0.3370848,0.148582 -0.3370848,0.33327 v 0.777518 0.444316 0.333202 c 0,0.184689 0.1502821,0.333271 0.3370848,0.333271 0.1867341,0 0.3370163,-0.148582 0.3370163,-0.333271 v -0.111044 h 2.0223053 v 0.453989 L 10.246417,14.8812 c -0.04913,0.04163 -0.07724,0.102733 -0.07724,0.166567 v 0.222157 c 0,0.122218 0.101084,0.222158 0.2247,0.222158 h 1.348203 v -0.888631 c 0,-0.122149 0.101084,-0.22209 0.224631,-0.22209 0.123616,0 0.224701,0.09994 0.224701,0.22209 v 0.888631 h 1.348202 c 0.123616,0 0.224701,-0.09994 0.224701,-0.222158 v -0.222157 c 0,-0.06383 -0.02804,-0.124943 -0.07717,-0.166567 L 12.86551,14.168878 v -0.453989 h 2.022304 v 0.111044 c 0,0.184689 0.150283,0.333271 0.337016,0.333271 0.186803,0 0.337085,-0.148582 0.337085,-0.333271 v -0.333202 -0.444316 -0.777518 c 0,-0.184688 -0.150282,-0.33327 -0.337085,-0.33327 -0.186733,0 -0.337016,0.148582 -0.337016,0.33327 v 0.26099 L 12.86551,11.365576 V 10.29648 c 0,-0.1208 -0.02529,-0.238828 -0.07304,-0.3499 z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
58
client/public/images/icons/follow.svg
Normal file
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<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="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg14"
|
||||
sodipodi:docname="follow.svg"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)">
|
||||
<metadata
|
||||
id="metadata20">
|
||||
<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>
|
||||
<defs
|
||||
id="defs18" />
|
||||
<sodipodi:namedview
|
||||
inkscape:document-rotation="0"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
id="namedview16"
|
||||
showgrid="false"
|
||||
inkscape:zoom="12.142857"
|
||||
inkscape:cx="22.433158"
|
||||
inkscape:cy="14.663012"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg14" />
|
||||
<path
|
||||
d="m 8.6152043,0.96068491 c -0.070984,-0.1658027 -0.2358263,-0.272592 -0.4178212,-0.272592 -0.1818565,0 -0.346698,0.106789 -0.4178225,0.272592 L 6.5262355,3.8523252 C 6.4294515,4.0771272 6.3784085,4.3160075 6.3784085,4.560499 V 6.7242759 L 2.2854009,9.0848093 V 8.5565855 c 0,-0.3737975 -0.304161,-0.6745171 -0.682098,-0.6745171 -0.378076,0 -0.68223699,0.3007196 -0.68223699,0.6745171 v 1.5736425 0.899265 0.674379 c 0,0.373797 0.30416099,0.674518 0.68223699,0.674518 0.377937,0 0.682098,-0.300721 0.682098,-0.674518 v -0.224747 h 4.0930076 v 0.918844 L 4.7156289,13.83966 c -0.09944,0.08425 -0.156335,0.207925 -0.156335,0.337121 v 0.449631 c 0,0.24736 0.204588,0.449631 0.454779,0.449631 h 2.7286708 v -1.798527 c 0,-0.247222 0.2045879,-0.449495 0.4546394,-0.449495 0.2501899,0 0.4547778,0.202273 0.4547778,0.449495 v 1.798527 h 2.7286701 c 0.250191,0 0.454779,-0.202271 0.454779,-0.449631 v -0.449631 c 0,-0.129196 -0.05676,-0.252876 -0.156195,-0.337121 l -1.662919,-1.441691 v -0.918844 h 4.093006 v 0.224747 c 0,0.373797 0.304162,0.674518 0.682098,0.674518 0.378076,0 0.682238,-0.300721 0.682238,-0.674518 V 11.029493 10.130228 8.5565855 c 0,-0.3737975 -0.304162,-0.6745171 -0.682238,-0.6745171 -0.377936,0 -0.682098,0.3007196 -0.682098,0.6745171 V 9.0848093 L 10.016496,6.7242759 V 4.560499 c 0,-0.2444915 -0.051184,-0.4833718 -0.1478275,-0.7081738 z"
|
||||
fill="#202831"
|
||||
id="path2"
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:1.38669" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
63
client/public/images/icons/front.svg
Normal file
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<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="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg14"
|
||||
sodipodi:docname="front.svg"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)">
|
||||
<metadata
|
||||
id="metadata20">
|
||||
<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>
|
||||
<defs
|
||||
id="defs18" />
|
||||
<sodipodi:namedview
|
||||
inkscape:document-rotation="0"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
id="namedview16"
|
||||
showgrid="false"
|
||||
inkscape:zoom="34.345186"
|
||||
inkscape:cx="9.7964424"
|
||||
inkscape:cy="8.7196642"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg14" />
|
||||
<path
|
||||
d="m 7.5384925,0.85189343 c 0.03507,-0.0819211 0.116519,-0.13468436 0.20644,-0.13468436 0.08985,0 0.171299,0.0527631 0.206441,0.13468436 l 0.619253,1.42872407 c 0.04782,0.1110719 0.07304,0.2290997 0.07304,0.3498999 V 3.6996131 L 10.665971,4.8659237 V 4.6049348 c 0,-0.1846888 0.150282,-0.3332707 0.337016,-0.3332707 0.186803,0 0.337085,0.1485819 0.337085,0.3332707 V 5.3824522 5.826768 6.1599704 c 0,0.1846885 -0.150282,0.3332711 -0.337085,0.3332711 -0.186734,0 -0.337016,-0.1485826 -0.337016,-0.3332711 V 6.0489257 H 8.6436655 v 0.4539895 l 0.821559,0.7123218 c 0.04913,0.041627 0.07724,0.1027332 0.07724,0.1665674 v 0.2221572 c 0,0.1222175 -0.101084,0.2221571 -0.224701,0.2221571 H 7.9695645 V 6.9374886 c 0,-0.1221494 -0.101085,-0.22209 -0.224632,-0.22209 -0.123616,0 -0.2247,0.099941 -0.2247,0.22209 v 0.8886301 h -1.348203 c -0.123616,0 -0.2247,-0.09994 -0.2247,-0.2221571 V 7.3818044 c 0,-0.063834 0.02804,-0.1249429 0.07717,-0.1665674 L 6.8461315,6.5029152 V 6.0489257 H 4.823827 v 0.1110447 c 0,0.1846885 -0.1502827,0.3332711 -0.3370162,0.3332711 -0.1868027,0 -0.3370854,-0.1485826 -0.3370854,-0.3332711 V 5.826768 5.3824522 4.6049348 c 0,-0.1846888 0.1502827,-0.3332707 0.3370854,-0.3332707 0.1867335,0 0.3370162,0.1485819 0.3370162,0.3332707 V 4.8659237 L 6.8461315,3.6996131 V 2.6305174 c 0,-0.1208002 0.02529,-0.238828 0.07304,-0.3498999 z"
|
||||
fill="#202831"
|
||||
id="path2"
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.685147" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.685147"
|
||||
id="path2-4"
|
||||
fill="#202831"
|
||||
d="m 7.5417259,8.4887398 c 0.03507,-0.081921 0.116519,-0.1346843 0.206441,-0.1346843 0.08985,0 0.171299,0.052763 0.206441,0.1346843 l 0.619252,1.4287241 c 0.04782,0.1110721 0.07304,0.2291001 0.07304,0.3499001 v 1.069096 l 2.0223041,1.166311 v -0.26099 c 0,-0.184688 0.150282,-0.33327 0.337016,-0.33327 0.186803,0 0.337085,0.148582 0.337085,0.33327 v 0.777518 0.444316 0.333202 c 0,0.184689 -0.150282,0.333271 -0.337085,0.333271 -0.186734,0 -0.337016,-0.148582 -0.337016,-0.333271 V 13.685773 H 8.6468989 v 0.453989 l 0.821559,0.712322 c 0.04913,0.04163 0.07724,0.102733 0.07724,0.166567 v 0.222157 c 0,0.122218 -0.101084,0.222158 -0.2247,0.222158 h -1.348203 v -0.888631 c 0,-0.122149 -0.101084,-0.22209 -0.224631,-0.22209 -0.123616,0 -0.224701,0.09994 -0.224701,0.22209 v 0.888631 h -1.348202 c -0.123616,0 -0.224701,-0.09994 -0.224701,-0.222158 v -0.222157 c 0,-0.06383 0.02804,-0.124943 0.07717,-0.166567 l 0.821635,-0.712322 v -0.453989 h -2.022304 v 0.111044 c 0,0.184689 -0.150283,0.333271 -0.337016,0.333271 -0.186803,0 -0.337085,-0.148582 -0.337085,-0.333271 v -0.333202 -0.444316 -0.777518 c 0,-0.184688 0.150282,-0.33327 0.337085,-0.33327 0.186733,0 0.337016,0.148582 0.337016,0.33327 v 0.26099 l 2.022304,-1.166311 v -1.069096 c 0,-0.1208 0.02529,-0.238828 0.07304,-0.3499001 z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.3 KiB |
1
client/public/images/icons/grip-lines-solid.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M32 288c-17.7 0-32 14.3-32 32s14.3 32 32 32l384 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L32 288zm0-128c-17.7 0-32 14.3-32 32s14.3 32 32 32l384 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L32 160z"/></svg>
|
||||
|
After Width: | Height: | Size: 433 B |
65
client/public/images/icons/line-abreast.svg
Normal file
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<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="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg14"
|
||||
sodipodi:docname="line-abreast.svg"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)">
|
||||
<metadata
|
||||
id="metadata20">
|
||||
<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>
|
||||
<defs
|
||||
id="defs18" />
|
||||
<sodipodi:namedview
|
||||
inkscape:document-rotation="0"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
id="namedview16"
|
||||
showgrid="false"
|
||||
inkscape:zoom="34.345186"
|
||||
inkscape:cx="9.7964424"
|
||||
inkscape:cy="8.7196642"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg14" />
|
||||
<path
|
||||
inkscape:transform-center-y="-0.37851011"
|
||||
inkscape:transform-center-x="-0.37851011"
|
||||
d="m 3.8116238,3.5888127 c 0.03507,-0.081921 0.116519,-0.1346844 0.20644,-0.1346844 0.08985,0 0.171299,0.052763 0.206441,0.1346844 l 0.619253,1.428724 c 0.04782,0.1110719 0.07304,0.2290997 0.07304,0.3498999 V 6.4365323 L 6.9391023,7.6028429 V 7.341854 c 0,-0.1846888 0.150282,-0.3332707 0.337016,-0.3332707 0.186803,0 0.337085,0.1485819 0.337085,0.3332707 v 0.7775174 0.4443158 0.3332024 c 0,0.1846885 -0.150282,0.3332711 -0.337085,0.3332711 -0.186734,0 -0.337016,-0.1485826 -0.337016,-0.3332711 V 8.7858449 H 4.9167968 v 0.4539895 l 0.821559,0.7123218 c 0.04913,0.041627 0.07724,0.1027328 0.07724,0.1665678 v 0.222157 c 0,0.122217 -0.101084,0.222157 -0.224701,0.222157 H 4.2426958 V 9.6744078 c 0,-0.1221494 -0.101085,-0.22209 -0.224632,-0.22209 -0.123616,0 -0.2247,0.099941 -0.2247,0.22209 v 0.8886302 h -1.348203 c -0.123616,0 -0.2247,-0.09994 -0.2247,-0.222157 v -0.222157 c 0,-0.06383 0.02804,-0.1249433 0.07717,-0.1665678 L 3.1192628,9.2398344 V 8.7858449 H 1.0969583 v 0.1110447 c 0,0.1846885 -0.15028273,0.3332711 -0.33701623,0.3332711 -0.1868027,0 -0.3370854,-0.1485826 -0.3370854,-0.3332711 V 8.5636872 8.1193714 7.341854 c 0,-0.1846888 0.1502827,-0.3332707 0.3370854,-0.3332707 0.1867335,0 0.33701623,0.1485819 0.33701623,0.3332707 V 7.6028429 L 3.1192628,6.4365323 V 5.3674366 c 0,-0.1208002 0.02529,-0.238828 0.07304,-0.3498999 z"
|
||||
fill="#202831"
|
||||
id="path2"
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.685147" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.685147"
|
||||
id="path2-4"
|
||||
fill="#202831"
|
||||
d="m 11.763569,3.5972246 c 0.03507,-0.081921 0.116519,-0.1346843 0.206441,-0.1346843 0.08985,0 0.171299,0.052763 0.206441,0.1346843 l 0.619252,1.4287241 c 0.04782,0.1110721 0.07304,0.2291001 0.07304,0.3499001 v 1.069096 l 2.022304,1.166311 v -0.26099 c 0,-0.184688 0.150282,-0.33327 0.337016,-0.33327 0.186803,0 0.337085,0.148582 0.337085,0.33327 v 0.777518 0.444316 0.333202 c 0,0.184689 -0.150282,0.333271 -0.337085,0.333271 -0.186734,0 -0.337016,-0.148582 -0.337016,-0.333271 v -0.111044 h -2.022305 v 0.453989 l 0.821559,0.712322 c 0.04913,0.04163 0.07724,0.1027332 0.07724,0.1665672 v 0.222157 c 0,0.122218 -0.101084,0.222158 -0.2247,0.222158 H 12.194638 V 9.6828198 c 0,-0.122149 -0.101084,-0.22209 -0.224631,-0.22209 -0.123616,0 -0.224701,0.09994 -0.224701,0.22209 v 0.8886312 h -1.348202 c -0.123616,0 -0.224701,-0.09994 -0.224701,-0.222158 v -0.222157 c 0,-0.06383 0.02804,-0.124943 0.07717,-0.1665672 l 0.821635,-0.712322 V 8.7942578 H 9.0489044 v 0.111044 c 0,0.184689 -0.150283,0.333271 -0.337016,0.333271 -0.186803,0 -0.337085,-0.148582 -0.337085,-0.333271 v -0.333202 -0.444316 -0.777518 c 0,-0.184688 0.150282,-0.33327 0.337085,-0.33327 0.186733,0 0.337016,0.148582 0.337016,0.33327 v 0.26099 l 2.0223036,-1.166311 v -1.069096 c 0,-0.1208 0.02529,-0.238828 0.07304,-0.3499001 z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
61
client/public/images/icons/sword.svg
Normal file
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<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"
|
||||
class="svg-icon"
|
||||
style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;"
|
||||
viewBox="0 0 1024 1024"
|
||||
version="1.1"
|
||||
id="svg6"
|
||||
sodipodi:docname="sword.svg"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)">
|
||||
<metadata
|
||||
id="metadata12">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs10" />
|
||||
<sodipodi:namedview
|
||||
inkscape:document-rotation="0"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
id="namedview8"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.83007812"
|
||||
inkscape:cx="512"
|
||||
inkscape:cy="512"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg6" />
|
||||
<path
|
||||
d="M34.133333 870.4c-17.066667-17.066667-17.066667-42.666667 0-59.733333l194.133334-194.133334-134.4-134.4c-17.066667-17.066667-17.066667-42.666667 0-59.733333 17.066667-17.066667 42.666667-17.066667 59.733333 0l59.733333 59.733333 448-448c10.666667-10.666667 25.6-14.933333 38.4-10.666666l224 44.8c17.066667 4.266667 29.866667 17.066667 34.133334 34.133333L1002.666667 324.266667c2.133333 14.933333-2.133333 27.733333-10.666667 38.4l-448 448 59.733333 59.733333c17.066667 17.066667 17.066667 42.666667 0 59.733333-8.533333 8.533333-19.2 12.8-29.866666 12.8-10.666667 0-21.333333-4.266667-29.866667-12.8l-134.4-134.4-196.266667 194.133334c-8.533333 8.533333-19.2 12.8-29.866666 12.8s-21.333333-4.266667-29.866667-12.8l-119.466667-119.466667z m253.866667-194.133333l-164.266667 164.266666 59.733334 59.733334 164.266666-164.266667-59.733333-59.733333zM706.133333 110.933333L273.066667 541.866667l209.066666 209.066666L913.066667 320l-34.133334-172.8-172.8-36.266667z"
|
||||
fill="#2F3CF4"
|
||||
id="path2"
|
||||
style="fill:#000000;fill-opacity:1" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
d="M795.733333 288c17.066667-17.066667 17.066667-42.666667 0-59.733333s-42.666667-17.066667-59.733333 0L422.4 541.866667c-17.066667 17.066667-17.066667 42.666667 0 59.733333 8.533333 8.533333 19.2 12.8 29.866667 12.8 10.666667 0 21.333333-4.266667 29.866666-12.8l313.6-313.6z"
|
||||
fill="#FFFFFF"
|
||||
id="path4" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
63
client/public/images/icons/trail.svg
Normal file
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<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="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg14"
|
||||
sodipodi:docname="trail.svg"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)">
|
||||
<metadata
|
||||
id="metadata20">
|
||||
<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>
|
||||
<defs
|
||||
id="defs18" />
|
||||
<sodipodi:namedview
|
||||
inkscape:document-rotation="0"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
id="namedview16"
|
||||
showgrid="false"
|
||||
inkscape:zoom="34.345186"
|
||||
inkscape:cx="9.7964424"
|
||||
inkscape:cy="8.7196642"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg14" />
|
||||
<path
|
||||
d="m 7.5384925,0.85189343 c 0.03507,-0.0819211 0.116519,-0.13468436 0.20644,-0.13468436 0.08985,0 0.171299,0.0527631 0.206441,0.13468436 l 0.619253,1.42872407 c 0.04782,0.1110719 0.07304,0.2290997 0.07304,0.3498999 V 3.6996131 L 10.665971,4.8659237 V 4.6049348 c 0,-0.1846888 0.150282,-0.3332707 0.337016,-0.3332707 0.186803,0 0.337085,0.1485819 0.337085,0.3332707 V 5.3824522 5.826768 6.1599704 c 0,0.1846885 -0.150282,0.3332711 -0.337085,0.3332711 -0.186734,0 -0.337016,-0.1485826 -0.337016,-0.3332711 V 6.0489257 H 8.6436655 v 0.4539895 l 0.821559,0.7123218 c 0.04913,0.041627 0.07724,0.1027332 0.07724,0.1665674 v 0.2221572 c 0,0.1222175 -0.101084,0.2221571 -0.224701,0.2221571 H 7.9695645 V 6.9374886 c 0,-0.1221494 -0.101085,-0.22209 -0.224632,-0.22209 -0.123616,0 -0.2247,0.099941 -0.2247,0.22209 v 0.8886301 h -1.348203 c -0.123616,0 -0.2247,-0.09994 -0.2247,-0.2221571 V 7.3818044 c 0,-0.063834 0.02804,-0.1249429 0.07717,-0.1665674 L 6.8461315,6.5029152 V 6.0489257 H 4.823827 v 0.1110447 c 0,0.1846885 -0.1502827,0.3332711 -0.3370162,0.3332711 -0.1868027,0 -0.3370854,-0.1485826 -0.3370854,-0.3332711 V 5.826768 5.3824522 4.6049348 c 0,-0.1846888 0.1502827,-0.3332707 0.3370854,-0.3332707 0.1867335,0 0.3370162,0.1485819 0.3370162,0.3332707 V 4.8659237 L 6.8461315,3.6996131 V 2.6305174 c 0,-0.1208002 0.02529,-0.238828 0.07304,-0.3498999 z"
|
||||
fill="#202831"
|
||||
id="path2"
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.685147" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.685147"
|
||||
id="path2-4"
|
||||
fill="#202831"
|
||||
d="m 7.5417259,8.4887398 c 0.03507,-0.081921 0.116519,-0.1346843 0.206441,-0.1346843 0.08985,0 0.171299,0.052763 0.206441,0.1346843 l 0.619252,1.4287241 c 0.04782,0.1110721 0.07304,0.2291001 0.07304,0.3499001 v 1.069096 l 2.0223041,1.166311 v -0.26099 c 0,-0.184688 0.150282,-0.33327 0.337016,-0.33327 0.186803,0 0.337085,0.148582 0.337085,0.33327 v 0.777518 0.444316 0.333202 c 0,0.184689 -0.150282,0.333271 -0.337085,0.333271 -0.186734,0 -0.337016,-0.148582 -0.337016,-0.333271 V 13.685773 H 8.6468989 v 0.453989 l 0.821559,0.712322 c 0.04913,0.04163 0.07724,0.102733 0.07724,0.166567 v 0.222157 c 0,0.122218 -0.101084,0.222158 -0.2247,0.222158 h -1.348203 v -0.888631 c 0,-0.122149 -0.101084,-0.22209 -0.224631,-0.22209 -0.123616,0 -0.224701,0.09994 -0.224701,0.22209 v 0.888631 h -1.348202 c -0.123616,0 -0.224701,-0.09994 -0.224701,-0.222158 v -0.222157 c 0,-0.06383 0.02804,-0.124943 0.07717,-0.166567 l 0.821635,-0.712322 v -0.453989 h -2.022304 v 0.111044 c 0,0.184689 -0.150283,0.333271 -0.337016,0.333271 -0.186803,0 -0.337085,-0.148582 -0.337085,-0.333271 v -0.333202 -0.444316 -0.777518 c 0,-0.184688 0.150282,-0.33327 0.337085,-0.33327 0.186733,0 0.337016,0.148582 0.337016,0.33327 v 0.26099 l 2.022304,-1.166311 v -1.069096 c 0,-0.1208 0.02529,-0.238828 0.07304,-0.3499001 z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.3 KiB |
1
client/public/images/icons/trash-can-regular.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M170.5 51.6L151.5 80h145l-19-28.4c-1.5-2.2-4-3.6-6.7-3.6H177.1c-2.7 0-5.2 1.3-6.7 3.6zm147-26.6L354.2 80H368h48 8c13.3 0 24 10.7 24 24s-10.7 24-24 24h-8V432c0 44.2-35.8 80-80 80H112c-44.2 0-80-35.8-80-80V128H24c-13.3 0-24-10.7-24-24S10.7 80 24 80h8H80 93.8l36.7-55.1C140.9 9.4 158.4 0 177.1 0h93.7c18.7 0 36.2 9.4 46.6 24.9zM80 128V432c0 17.7 14.3 32 32 32H336c17.7 0 32-14.3 32-32V128H80zm80 64V400c0 8.8-7.2 16-16 16s-16-7.2-16-16V192c0-8.8 7.2-16 16-16s16 7.2 16 16zm80 0V400c0 8.8-7.2 16-16 16s-16-7.2-16-16V192c0-8.8 7.2-16 16-16s16 7.2 16 16zm80 0V400c0 8.8-7.2 16-16 16s-16-7.2-16-16V192c0-8.8 7.2-16 16-16s16 7.2 16 16z"/></svg>
|
||||
|
After Width: | Height: | Size: 875 B |
370
client/public/images/reference-system-test.svg
Normal file
@@ -0,0 +1,370 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<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"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
sodipodi:docname="reference-system-test.svg"
|
||||
id="svg8"
|
||||
version="1.1"
|
||||
viewBox="0 0 232.62689 109.65005"
|
||||
height="109.65005mm"
|
||||
width="232.62689mm">
|
||||
<defs
|
||||
id="defs2">
|
||||
<marker
|
||||
inkscape:stockid="TriangleOutM"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="marker3764"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path3762"
|
||||
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#00fff1;stroke-width:1pt;stroke-opacity:1;fill:#00fffb;fill-opacity:1"
|
||||
transform="scale(0.4)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="TriangleOutM"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="marker3754"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path3752"
|
||||
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#00fff1;stroke-width:1pt;stroke-opacity:1;fill:#00fffb;fill-opacity:1"
|
||||
transform="scale(0.4)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Send"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="marker3658"
|
||||
style="overflow:visible;"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path3656"
|
||||
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#00fff1;stroke-opacity:1;fill:#00fffb;fill-opacity:1"
|
||||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
|
||||
transform="scale(0.3) rotate(180) translate(-2.3,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Send"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="marker3648"
|
||||
style="overflow:visible;"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path3646"
|
||||
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#00fff1;stroke-opacity:1;fill:#00fffb;fill-opacity:1"
|
||||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
|
||||
transform="scale(0.3) rotate(180) translate(-2.3,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="Arrow2Mend"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow2Mend">
|
||||
<path
|
||||
transform="scale(-0.6)"
|
||||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
|
||||
id="path1088" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="Arrow2Lend"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow2Lend">
|
||||
<path
|
||||
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
|
||||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
|
||||
id="path1082" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="Arrow1Lend"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow1Lend">
|
||||
<path
|
||||
transform="matrix(-0.8,0,0,-0.8,-10,0)"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
id="path1064" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow2Mend-7"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path1088-1"
|
||||
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||
transform="scale(-0.6)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="Arrow2Mend-7-8"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow2Mend">
|
||||
<path
|
||||
transform="scale(-0.6)"
|
||||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
|
||||
id="path1088-1-6" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow2Mend-7-8-0"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path1088-1-6-8"
|
||||
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||
transform="scale(-0.6)" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-width="1920"
|
||||
fit-margin-bottom="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-top="0"
|
||||
showgrid="false"
|
||||
inkscape:document-rotation="0"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:cy="180.46845"
|
||||
inkscape:cx="179.92513"
|
||||
inkscape:zoom="0.70710678"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff"
|
||||
id="base" />
|
||||
<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
|
||||
transform="translate(-9.0472264,-0.3638854)"
|
||||
id="layer1"
|
||||
inkscape:groupmode="layer"
|
||||
inkscape:label="Layer 1">
|
||||
<g
|
||||
transform="matrix(2.7166059,0,0,2.7166059,6.5450533,19.640703)"
|
||||
id="g839"
|
||||
style="fill:none">
|
||||
<path
|
||||
d="m 8.6152043,0.96068491 c -0.070984,-0.1658027 -0.2358263,-0.272592 -0.4178212,-0.272592 -0.1818565,0 -0.346698,0.106789 -0.4178225,0.272592 L 6.5262355,3.8523252 C 6.4294515,4.0771272 6.3784085,4.3160075 6.3784085,4.560499 V 6.7242759 L 2.2854009,9.0848093 V 8.5565855 c 0,-0.3737975 -0.304161,-0.6745171 -0.682098,-0.6745171 -0.378076,0 -0.68223699,0.3007196 -0.68223699,0.6745171 v 1.5736425 0.899265 0.674379 c 0,0.373797 0.30416099,0.674518 0.68223699,0.674518 0.377937,0 0.682098,-0.300721 0.682098,-0.674518 v -0.224747 h 4.0930076 v 0.918844 L 4.7156289,13.83966 c -0.09944,0.08425 -0.156335,0.207925 -0.156335,0.337121 v 0.449631 c 0,0.24736 0.204588,0.449631 0.454779,0.449631 h 2.7286708 v -1.798527 c 0,-0.247222 0.2045879,-0.449495 0.4546394,-0.449495 0.2501899,0 0.4547778,0.202273 0.4547778,0.449495 v 1.798527 h 2.7286701 c 0.250191,0 0.454779,-0.202271 0.454779,-0.449631 v -0.449631 c 0,-0.129196 -0.05676,-0.252876 -0.156195,-0.337121 l -1.662919,-1.441691 v -0.918844 h 4.093006 v 0.224747 c 0,0.373797 0.304162,0.674518 0.682098,0.674518 0.378076,0 0.682238,-0.300721 0.682238,-0.674518 V 11.029493 10.130228 8.5565855 c 0,-0.3737975 -0.304162,-0.6745171 -0.682238,-0.6745171 -0.377936,0 -0.682098,0.3007196 -0.682098,0.6745171 V 9.0848093 L 10.016496,6.7242759 V 4.560499 c 0,-0.2444915 -0.051184,-0.4833718 -0.1478275,-0.7081738 z"
|
||||
fill="#202831"
|
||||
id="path2"
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:1.38669" />
|
||||
</g>
|
||||
<g
|
||||
style="fill:none"
|
||||
id="g839-2"
|
||||
transform="matrix(2.7166059,0,0,2.7166059,59.782498,69.058264)">
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:1.38669"
|
||||
id="path2-3"
|
||||
fill="#202831"
|
||||
d="m 8.6152043,0.96068491 c -0.070984,-0.1658027 -0.2358263,-0.272592 -0.4178212,-0.272592 -0.1818565,0 -0.346698,0.106789 -0.4178225,0.272592 L 6.5262355,3.8523252 C 6.4294515,4.0771272 6.3784085,4.3160075 6.3784085,4.560499 V 6.7242759 L 2.2854009,9.0848093 V 8.5565855 c 0,-0.3737975 -0.304161,-0.6745171 -0.682098,-0.6745171 -0.378076,0 -0.68223699,0.3007196 -0.68223699,0.6745171 v 1.5736425 0.899265 0.674379 c 0,0.373797 0.30416099,0.674518 0.68223699,0.674518 0.377937,0 0.682098,-0.300721 0.682098,-0.674518 v -0.224747 h 4.0930076 v 0.918844 L 4.7156289,13.83966 c -0.09944,0.08425 -0.156335,0.207925 -0.156335,0.337121 v 0.449631 c 0,0.24736 0.204588,0.449631 0.454779,0.449631 h 2.7286708 v -1.798527 c 0,-0.247222 0.2045879,-0.449495 0.4546394,-0.449495 0.2501899,0 0.4547778,0.202273 0.4547778,0.449495 v 1.798527 h 2.7286701 c 0.250191,0 0.454779,-0.202271 0.454779,-0.449631 v -0.449631 c 0,-0.129196 -0.05676,-0.252876 -0.156195,-0.337121 l -1.662919,-1.441691 v -0.918844 h 4.093006 v 0.224747 c 0,0.373797 0.304162,0.674518 0.682098,0.674518 0.378076,0 0.682238,-0.300721 0.682238,-0.674518 V 11.029493 10.130228 8.5565855 c 0,-0.3737975 -0.304162,-0.6745171 -0.682238,-0.6745171 -0.377936,0 -0.682098,0.3007196 -0.682098,0.6745171 V 9.0848093 L 10.016496,6.7242759 V 4.560499 c 0,-0.2444915 -0.051184,-0.4833718 -0.1478275,-0.7081738 z" />
|
||||
</g>
|
||||
<circle
|
||||
r="0"
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.225344;stroke-linecap:round"
|
||||
id="path865-3"
|
||||
cx="29.19866"
|
||||
cy="80.130951" />
|
||||
<g
|
||||
transform="translate(140.21868,-45.703089)"
|
||||
id="g1019">
|
||||
<circle
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.0680267;stroke-linecap:round"
|
||||
id="path859"
|
||||
cx="29.259609"
|
||||
cy="85.105995"
|
||||
r="4.9218788" />
|
||||
<rect
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.122238;stroke-linecap:round"
|
||||
id="rect861"
|
||||
width="39.215027"
|
||||
height="1.5119048"
|
||||
x="9.5438986"
|
||||
y="84.477676"
|
||||
ry="0.42838952" />
|
||||
<circle
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.122238;stroke-linecap:round"
|
||||
id="path865"
|
||||
cx="10.866816"
|
||||
cy="85.139137"
|
||||
r="1.5119048" />
|
||||
<circle
|
||||
r="1.5119048"
|
||||
cy="85.139137"
|
||||
cx="48.097469"
|
||||
id="path865-5"
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.122238;stroke-linecap:round" />
|
||||
<rect
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.122238;stroke-linecap:round"
|
||||
id="rect888"
|
||||
width="1.0394346"
|
||||
height="5.1971726"
|
||||
x="28.726191"
|
||||
y="73.232887"
|
||||
ry="0.42838952" />
|
||||
<rect
|
||||
ry="0.35266024"
|
||||
y="82.231239"
|
||||
x="19.213385"
|
||||
height="1.2446353"
|
||||
width="19.704351"
|
||||
id="rect861-3"
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.0786176;stroke-linecap:round" />
|
||||
<circle
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.212007;stroke-linecap:round"
|
||||
id="path865-5-8"
|
||||
cx="29.175037"
|
||||
cy="80.674294"
|
||||
r="2.6222098" />
|
||||
</g>
|
||||
<g
|
||||
id="g1019-5"
|
||||
transform="translate(192.06475,5.3360099)">
|
||||
<circle
|
||||
r="4.9218788"
|
||||
cy="85.105995"
|
||||
cx="29.259609"
|
||||
id="path859-5"
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.0680267;stroke-linecap:round" />
|
||||
<rect
|
||||
ry="0.42838952"
|
||||
y="84.477676"
|
||||
x="9.5438986"
|
||||
height="1.5119048"
|
||||
width="39.215027"
|
||||
id="rect861-1"
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.122238;stroke-linecap:round" />
|
||||
<circle
|
||||
r="1.5119048"
|
||||
cy="85.139137"
|
||||
cx="10.866816"
|
||||
id="path865-6"
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.122238;stroke-linecap:round" />
|
||||
<circle
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.122238;stroke-linecap:round"
|
||||
id="path865-5-6"
|
||||
cx="48.097469"
|
||||
cy="85.139137"
|
||||
r="1.5119048" />
|
||||
<rect
|
||||
ry="0.42838952"
|
||||
y="73.232887"
|
||||
x="28.726191"
|
||||
height="5.1971726"
|
||||
width="1.0394346"
|
||||
id="rect888-2"
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.122238;stroke-linecap:round" />
|
||||
<rect
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.0786176;stroke-linecap:round"
|
||||
id="rect861-3-0"
|
||||
width="19.704351"
|
||||
height="1.2446353"
|
||||
x="19.213385"
|
||||
y="82.231239"
|
||||
ry="0.35266024" />
|
||||
<circle
|
||||
r="2.6222098"
|
||||
cy="80.674294"
|
||||
cx="29.175037"
|
||||
id="path865-5-8-9"
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.212007;stroke-linecap:round" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:none;fill-opacity:1;stroke:#00fff1;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3754)"
|
||||
d="m 28.820683,45.262649 46.641256,42.10261"
|
||||
id="path1059-0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
id="path1059-0-0"
|
||||
d="M 169.40181,40.337642 V 90.041518"
|
||||
style="fill:#00fffb;fill-opacity:1;stroke:#00fff1;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3764)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16.5205px;line-height:1.25;font-family:sans-serif;fill:#00fffb;fill-opacity:1;stroke:#00fff1;stroke-width:0.619518;stroke-opacity:1"
|
||||
x="148.62083"
|
||||
y="97.970039"
|
||||
id="text2102-4"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2100-0"
|
||||
x="148.62083"
|
||||
y="97.970039"
|
||||
style="font-size:16.5205px;fill:#00fffb;fill-opacity:1;stroke:#00fff1;stroke-width:0.619518;stroke-opacity:1">+</tspan></text>
|
||||
<path
|
||||
sodipodi:open="true"
|
||||
d="m 30.431293,14.137878 a 29.450657,29.450657 0 0 1 27.20886,18.180379 29.450657,29.450657 0 0 1 -6.3841,32.095037"
|
||||
sodipodi:arc-type="arc"
|
||||
sodipodi:end="0.78539816"
|
||||
sodipodi:start="4.712389"
|
||||
sodipodi:ry="29.450657"
|
||||
sodipodi:rx="29.450657"
|
||||
sodipodi:cy="43.588535"
|
||||
sodipodi:cx="30.431293"
|
||||
sodipodi:type="arc"
|
||||
id="path3121"
|
||||
style="fill:none;fill-opacity:1;stroke:#00fff1;stroke-width:3;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:1;stroke:#00fff1;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 28.820683,1.8638854 V 45.262649"
|
||||
id="path1059-0-0-2"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 16 KiB |
218
client/public/images/reference-system.svg
Normal file
@@ -0,0 +1,218 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<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"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
sodipodi:docname="reference-system.svg"
|
||||
id="svg8"
|
||||
version="1.1"
|
||||
viewBox="0 0 13.229166 13.229167"
|
||||
height="50"
|
||||
width="50">
|
||||
<defs
|
||||
id="defs2">
|
||||
<marker
|
||||
inkscape:stockid="TriangleOutM"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="marker3764"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path3762"
|
||||
d="M 5.77,0 -2.88,5 V -5 Z"
|
||||
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:1pt;stroke-opacity:1"
|
||||
transform="scale(0.4)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="TriangleOutM"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="marker3754"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path3752"
|
||||
d="M 5.77,0 -2.88,5 V -5 Z"
|
||||
style="fill:#00fff1;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:1pt;stroke-opacity:1"
|
||||
transform="scale(0.4)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Send"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="marker3658"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path3656"
|
||||
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||
transform="matrix(-0.3,0,0,-0.3,0.69,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Send"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="marker3648"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path3646"
|
||||
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||
transform="matrix(-0.3,0,0,-0.3,0.69,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="Arrow2Mend"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow2Mend">
|
||||
<path
|
||||
transform="scale(-0.6)"
|
||||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
|
||||
id="path1088" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="Arrow2Lend"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow2Lend">
|
||||
<path
|
||||
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
|
||||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
|
||||
id="path1082" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="Arrow1Lend"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow1Lend">
|
||||
<path
|
||||
transform="matrix(-0.8,0,0,-0.8,-10,0)"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
id="path1064" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow2Mend-7"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path1088-1"
|
||||
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||
transform="scale(-0.6)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="Arrow2Mend-7-8"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow2Mend">
|
||||
<path
|
||||
transform="scale(-0.6)"
|
||||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
|
||||
id="path1088-1-6" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow2Mend-7-8-0"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path1088-1-6-8"
|
||||
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||
transform="scale(-0.6)" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
units="px"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-width="1920"
|
||||
fit-margin-bottom="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-top="0"
|
||||
showgrid="false"
|
||||
inkscape:document-rotation="0"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:cy="24.946043"
|
||||
inkscape:cx="23.906148"
|
||||
inkscape:zoom="11.313708"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff"
|
||||
id="base" />
|
||||
<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
|
||||
transform="translate(-9.0472264,-21.50998)"
|
||||
id="layer1"
|
||||
inkscape:groupmode="layer"
|
||||
inkscape:label="Layer 1">
|
||||
<g
|
||||
transform="matrix(0.90904788,0,0,0.91946153,8.2333194,20.900691)"
|
||||
id="g839"
|
||||
style="fill:none">
|
||||
<path
|
||||
d="m 8.6152043,0.96068491 c -0.070984,-0.1658027 -0.2358263,-0.272592 -0.4178212,-0.272592 -0.1818565,0 -0.346698,0.106789 -0.4178225,0.272592 L 6.5262355,3.8523252 C 6.4294515,4.0771272 6.3784085,4.3160075 6.3784085,4.560499 V 6.7242759 L 2.2854009,9.0848093 V 8.5565855 c 0,-0.3737975 -0.304161,-0.6745171 -0.682098,-0.6745171 -0.378076,0 -0.68223699,0.3007196 -0.68223699,0.6745171 v 1.5736425 0.899265 0.674379 c 0,0.373797 0.30416099,0.674518 0.68223699,0.674518 0.377937,0 0.682098,-0.300721 0.682098,-0.674518 v -0.224747 h 4.0930076 v 0.918844 L 4.7156289,13.83966 c -0.09944,0.08425 -0.156335,0.207925 -0.156335,0.337121 v 0.449631 c 0,0.24736 0.204588,0.449631 0.454779,0.449631 h 2.7286708 v -1.798527 c 0,-0.247222 0.2045879,-0.449495 0.4546394,-0.449495 0.2501899,0 0.4547778,0.202273 0.4547778,0.449495 v 1.798527 h 2.7286701 c 0.250191,0 0.454779,-0.202271 0.454779,-0.449631 v -0.449631 c 0,-0.129196 -0.05676,-0.252876 -0.156195,-0.337121 l -1.662919,-1.441691 v -0.918844 h 4.093006 v 0.224747 c 0,0.373797 0.304162,0.674518 0.682098,0.674518 0.378076,0 0.682238,-0.300721 0.682238,-0.674518 V 11.029493 10.130228 8.5565855 c 0,-0.3737975 -0.304162,-0.6745171 -0.682238,-0.6745171 -0.377936,0 -0.682098,0.3007196 -0.682098,0.6745171 V 9.0848093 L 10.016496,6.7242759 V 4.560499 c 0,-0.2444915 -0.051184,-0.4833718 -0.1478275,-0.7081738 z"
|
||||
fill="#202831"
|
||||
id="path2"
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:1.38669" />
|
||||
</g>
|
||||
<circle
|
||||
r="0"
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.225344;stroke-linecap:round"
|
||||
id="path865-3"
|
||||
cx="29.19866"
|
||||
cy="80.130951" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.6 KiB |
@@ -1,211 +1,195 @@
|
||||
/*** Control panel ***/
|
||||
|
||||
#atc-control-panel {
|
||||
align-self: flex-end;
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
display:flex;
|
||||
margin: 0 0 50px 100px;
|
||||
padding:5px;
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.atc-tool {
|
||||
align-self: center;
|
||||
border-radius: 10px;
|
||||
display:none;
|
||||
justify-self: center;
|
||||
padding: 10px;
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
|
||||
.atc-enabled .atc-tool {
|
||||
display:flex;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#atc-flight-list {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#atc-flight-list table {
|
||||
color:white;
|
||||
}
|
||||
|
||||
#atc-flight-list table td {
|
||||
padding:0 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#atc-flight-list table td:first-of-type {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#atc-flight-list table tr[data-status='checkedIn'] td {
|
||||
background-color:goldenrod;
|
||||
}
|
||||
|
||||
#atc-flight-list table tr[data-status='readyToTaxi'] td {
|
||||
background-color:darkgreen;
|
||||
}
|
||||
|
||||
#atc-flight-list table button {
|
||||
background-color: #666;
|
||||
border:1px solid white;
|
||||
color:white;
|
||||
font-weight: bold;
|
||||
margin:2px 0;
|
||||
}
|
||||
|
||||
|
||||
.atc-strip-board {
|
||||
align-self: center;
|
||||
display:flex;
|
||||
justify-self: center;
|
||||
position: absolute;
|
||||
z-index: 9999 ;
|
||||
}
|
||||
|
||||
.atc-strip-board-header {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.atc-strip-board-strips {
|
||||
.ol-strip-board-strips {
|
||||
display:flex;
|
||||
flex-direction: column;
|
||||
row-gap: 4px;
|
||||
}
|
||||
|
||||
.atc-strip-board-strip {
|
||||
display:flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
.atc-strip-board-header {
|
||||
background:black;
|
||||
color:white;
|
||||
display:none;
|
||||
justify-content: right;
|
||||
}
|
||||
|
||||
|
||||
.atc-strip-board {
|
||||
display:flex;
|
||||
flex-direction: column;
|
||||
row-gap: 5px;
|
||||
}
|
||||
|
||||
.atc-strip-board-strips {
|
||||
display:flex;
|
||||
flex-direction: column;
|
||||
padding:10px;
|
||||
row-gap: 5px;
|
||||
}
|
||||
|
||||
.atc-strip-board-strips > div {
|
||||
.ol-strip-board-strip {
|
||||
align-items: center;
|
||||
border-radius: var( --border-radius-sm );
|
||||
column-gap: 4px;
|
||||
display:flex;
|
||||
flex-flow: row nowrap;
|
||||
row-gap:4px;
|
||||
}
|
||||
|
||||
.ol-strip-board-strip[data-flight-status="checkedin"] {
|
||||
background-color: #ffffff2A;
|
||||
}
|
||||
|
||||
.ol-strip-board-strip[data-flight-status="readytotaxi"] {
|
||||
background-color: #ffff0063;
|
||||
}
|
||||
|
||||
.ol-strip-board-strip[data-flight-status="clearedtotaxi"] {
|
||||
background-color: #00ff0030;
|
||||
}
|
||||
|
||||
.ol-strip-board-strip[data-flight-status="halted"] {
|
||||
background-color: #FF000040;
|
||||
}
|
||||
|
||||
.ol-strip-board-strip[data-flight-status="terminated"] {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.ol-strip-board-headers {
|
||||
column-gap: 4px;
|
||||
display:flex;
|
||||
flex-flow:row nowrap;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ol-strip-board-headers > *, .ol-strip-board-strip > [data-point] {
|
||||
padding: 4px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width:80px;
|
||||
}
|
||||
|
||||
.ol-strip-board-strip input[type="text"] {
|
||||
appearance: none;
|
||||
background-color: transparent;
|
||||
border:1px solid #ffffff30;
|
||||
border-radius: var( --border-radius-sm );
|
||||
color:white;
|
||||
column-gap: 2px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.atc-strip-board-header > div, .atc-strip-board-strips > div > div {
|
||||
text-align: center;
|
||||
width: 75px;
|
||||
}
|
||||
|
||||
.atc-strip-board-header > .name {
|
||||
width:150px;
|
||||
}
|
||||
|
||||
.atc-strip-board-header > div, .atc-strip-board-strips > div > div {
|
||||
text-align: center;
|
||||
width: 75px;
|
||||
}
|
||||
|
||||
.atc-strip-board-strips > div > .name {
|
||||
text-align: left;
|
||||
width:150px;
|
||||
}
|
||||
|
||||
.atc-strip-board-strips > div {
|
||||
align-items: center;
|
||||
column-gap: 5px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
font-size:12px;
|
||||
font-weight: 600;
|
||||
padding: 5px;
|
||||
row-gap: 5px;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
.atc-strip-board-header, .atc-strip-board-strips > div {
|
||||
align-items: center;
|
||||
background:#FFF3;
|
||||
color:white;
|
||||
column-gap: 5px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
font-size:12px;
|
||||
font-weight: 600;
|
||||
padding: 5px;
|
||||
row-gap: 5px;
|
||||
}
|
||||
|
||||
.atc-strip-board-header {
|
||||
background:black;
|
||||
color:white;
|
||||
display:none;
|
||||
justify-content: right;
|
||||
}
|
||||
|
||||
.atc-strip-board-strips > div {
|
||||
border-bottom:1px solid black;
|
||||
}
|
||||
|
||||
.atc-strip-board-header > div, .atc-strip-board-strips > div > div {
|
||||
font-weight:normal;
|
||||
outline:none;
|
||||
padding: 4px 0;
|
||||
text-align: center;
|
||||
width: 75px;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.atc-strip-board-header > .name {
|
||||
width:150px;
|
||||
.ol-strip-board-strip[data-time-warning="level-1"] [data-point="timeToGo"] {
|
||||
border:1px solid #cc0000;
|
||||
}
|
||||
|
||||
.atc-strip-board-strips > div > .handle {
|
||||
background: black;
|
||||
border-radius: 50%;
|
||||
cursor:grab;
|
||||
height:10px;
|
||||
width:10px;
|
||||
.ol-strip-board-headers :nth-child(1) {
|
||||
width:12px;
|
||||
}
|
||||
|
||||
.atc-strip-board-strips > div > .name {
|
||||
.ol-strip-board-headers :nth-child(2),
|
||||
.ol-strip-board-strip :nth-child(2),
|
||||
[data-board-type="ground"] .ol-strip-board-headers :nth-child(3),
|
||||
[data-board-type="ground"] .ol-strip-board-strip :nth-child(3) {
|
||||
width:130px;
|
||||
}
|
||||
|
||||
[data-board-type="ground"] .ol-strip-board-strip :nth-child(5) {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.ol-strip-board-headers :last-child,
|
||||
.ol-strip-board-strip :last-child {
|
||||
width:20px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[data-board-type="tower"] .ol-strip-board-strip > * {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
[data-board-type="tower"] .ol-strip-board-strip a {
|
||||
color:white;
|
||||
}
|
||||
|
||||
[data-board-type="tower"] .ol-strip-board-strip > :nth-child(2) {
|
||||
text-align: left;
|
||||
width:150px;
|
||||
}
|
||||
|
||||
.atc-strip-board-strips > div > .warning {
|
||||
background:red;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
[data-board-type="tower"] .ol-strip-board-strip :nth-child(3) input,
|
||||
[data-board-type="tower"] .ol-strip-board-strip :nth-child(5) input {
|
||||
width:30px;
|
||||
}
|
||||
|
||||
.atc-strip-board-strips > div > .link-warning {
|
||||
border: 1px solid red;
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
|
||||
[data-board-type="tower"] .ol-strip-board-strip :nth-child(3) {
|
||||
font-size:10px;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
[data-altitude-assigned] [data-point="assignedAltitude"] input,
|
||||
[data-speed-assigned] [data-point="assignedSpeed"] input {
|
||||
background-color:#ffffffbb;
|
||||
color: black;
|
||||
font-weight: var( --font-weight-bolder );
|
||||
}
|
||||
|
||||
[data-warning-altitude] [data-point="altitude"],
|
||||
[data-warning-speed] [data-point="speed"] {
|
||||
background:#cc0000;
|
||||
border-radius: var( --border-radius-sm );
|
||||
}
|
||||
|
||||
|
||||
|
||||
.ol-strip-board-strip > [data-point="name"] {
|
||||
text-overflow: ellipsis;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
.ol-strip-board-strip .ol-select-value {
|
||||
opacity: .85;
|
||||
}
|
||||
|
||||
|
||||
.ol-strip-board-add-flight {
|
||||
display:flex;
|
||||
flex-flow: row nowrap;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
|
||||
.ol-strip-board-add-flight > * {
|
||||
border:none;
|
||||
outline: none;
|
||||
padding:4px 8px;
|
||||
}
|
||||
|
||||
.add-flight-by-click img {
|
||||
filter:invert();
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.ol-strip-board-add-flight input {
|
||||
border-radius: var( --border-radius-sm );
|
||||
}
|
||||
|
||||
.ol-strip-board-add-flight .ol-auto-suggest {
|
||||
background:white;
|
||||
border-radius: var(--border-radius-sm );
|
||||
color:black;
|
||||
display:none;
|
||||
flex-direction: column;
|
||||
left:0;
|
||||
margin:0;
|
||||
position:absolute;
|
||||
translate:0 -100%;
|
||||
top:0;
|
||||
}
|
||||
|
||||
.ol-strip-board-add-flight .ol-auto-suggest[data-has-suggestions] {
|
||||
display:flex;
|
||||
}
|
||||
|
||||
.ol-strip-board-add-flight .ol-auto-suggest[data-has-suggestions] a {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
[data-board-type="ground"] {
|
||||
bottom:20px;
|
||||
}
|
||||
|
||||
[data-board-type="tower"] {
|
||||
right:10px;
|
||||
top:10px;
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
position: absolute;
|
||||
row-gap: 5px;
|
||||
width: 230px;
|
||||
z-index: 1000;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
#aircraft-spawn-menu {
|
||||
@@ -207,10 +207,117 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: fit-content;
|
||||
width: fit-content;
|
||||
position: absolute;
|
||||
row-gap: 5px;
|
||||
width: 150px;
|
||||
z-index: 1000;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
#unit-contextmenu button {
|
||||
border: 1px solid var(--background-offwhite);
|
||||
border-radius: var(--border-radius-sm);
|
||||
padding: 12px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
#unit-contextmenu div {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
#unit-contextmenu div:before {
|
||||
display: inline-block;
|
||||
filter: invert(100%);
|
||||
height: 16px;
|
||||
margin-right: 15px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
#center-map::before {
|
||||
content: url( /images/icons/arrows-to-eye-solid.svg );
|
||||
}
|
||||
|
||||
#refuel::before {
|
||||
content: url( /images/icons/fuel.svg );
|
||||
}
|
||||
|
||||
#attack::before {
|
||||
content: url( /images/icons/sword.svg );
|
||||
}
|
||||
|
||||
#follow::before {
|
||||
content: url( /images/icons/follow.svg );
|
||||
}
|
||||
|
||||
#trail::before {
|
||||
content: url( /images/icons/trail.svg );
|
||||
}
|
||||
|
||||
#echelon-lh::before {
|
||||
content: url( /images/icons/echelon-lh.svg );
|
||||
}
|
||||
|
||||
#echelon-rh::before {
|
||||
content: url( /images/icons/echelon-rh.svg );
|
||||
}
|
||||
|
||||
#line-abreast::before {
|
||||
content: url( /images/icons/line-abreast.svg );
|
||||
}
|
||||
|
||||
#front::before {
|
||||
content: url( /images/icons/front.svg );
|
||||
}
|
||||
|
||||
#custom::before {
|
||||
content: url( /images/icons/custom.svg );
|
||||
}
|
||||
|
||||
#custom-formation-dialog {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
#custom-formation-dialog > .ol-dialog-content {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
row-gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#custom-formation-dialog > .ol-dialog-content > .ol-group {
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#reference-system {
|
||||
content: url( /images/reference-system.svg );
|
||||
display: inline-block;
|
||||
filter: invert(100%);
|
||||
width: 50px;
|
||||
transform: translate(-50%, -50%);
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.formation-position-clock {
|
||||
position: relative;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
margin: 15px;
|
||||
}
|
||||
|
||||
.formation-position-clock > .clock-hand {
|
||||
transform: translate(-50%, -50%);
|
||||
display: flex;
|
||||
position: absolute;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
/* Airbase context menu */
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/* Page style */
|
||||
#map-container {
|
||||
height: 100%;
|
||||
@@ -7,6 +6,8 @@
|
||||
}
|
||||
|
||||
#primary-toolbar {
|
||||
align-items: center;
|
||||
display:flex;
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 10px;
|
||||
@@ -14,32 +15,30 @@
|
||||
}
|
||||
|
||||
#olympus-toolbar-summary {
|
||||
background-image: url( "/images/icon-round.png" );
|
||||
background-image: url("/images/icon-round.png");
|
||||
background-position: 25px 20px;
|
||||
background-repeat: no-repeat;
|
||||
background-size:36px 36px;
|
||||
background-size: 36px 36px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-indent: 44px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
dl.ol-data-grid {
|
||||
align-items: center;
|
||||
display:flex;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
margin:0;
|
||||
margin: 0;
|
||||
row-gap: 4px;
|
||||
}
|
||||
|
||||
dl.ol-data-grid dt {
|
||||
width:60%;
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
dl.ol-data-grid dd {
|
||||
width:40%;
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,24 +47,23 @@ dl.ol-data-grid dt.icon {
|
||||
}
|
||||
|
||||
dl.ol-data-grid dt.icon::before {
|
||||
content: url( /images/icons/speed.svg );
|
||||
display:inline-block;
|
||||
filter:invert(100%);
|
||||
content: url(/images/icons/speed.svg );
|
||||
display: inline-block;
|
||||
filter: invert(100%);
|
||||
width: 20px;
|
||||
translate:-20px 2px;
|
||||
translate: -20px 2px;
|
||||
}
|
||||
|
||||
|
||||
dl.ol-data-grid dt.icon-speed::before {
|
||||
content: url( /images/icons/speed.svg );
|
||||
content: url(/images/icons/speed.svg );
|
||||
}
|
||||
|
||||
|
||||
dl.ol-data-grid dt.icon-altitude::before {
|
||||
content: url( /images/icons/altitude.svg );
|
||||
content: url(/images/icons/altitude.svg );
|
||||
}
|
||||
|
||||
|
||||
dl.ol-data-grid dd {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
@@ -73,59 +71,53 @@ dl.ol-data-grid dd {
|
||||
}
|
||||
|
||||
.br-info::after {
|
||||
content: attr( data-bearing ) '\00B0 / ' attr( data-distance ) attr( data-distance-units );
|
||||
content: attr(data-bearing) '\00B0 / ' attr(data-distance) attr(data-distance-units);
|
||||
}
|
||||
|
||||
.br-info[data-message]::after {
|
||||
content: attr( data-message );
|
||||
content: attr(data-message);
|
||||
}
|
||||
|
||||
.coordinates::after {
|
||||
content: attr( data-dd ) "\00b0 " attr( data-mm ) "'" attr( data-ss ) "." attr( data-sss ) '"' attr( data-label );
|
||||
content: attr(data-dd) "\00b0 " attr(data-mm) "'" attr(data-ss) "." attr(data-sss) '"' attr(data-label);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.ol-button-box {
|
||||
column-gap: 6px;
|
||||
display:flex;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
margin:5px 0;
|
||||
margin: 5px 0;
|
||||
row-gap: 5px;
|
||||
}
|
||||
|
||||
.ol-button-box button {
|
||||
background-repeat: no-repeat;;
|
||||
border:1px solid var( --accent-light-blue );
|
||||
color: var( --accent-light-blue );
|
||||
background-repeat: no-repeat;
|
||||
;
|
||||
border: 1px solid var(--accent-light-blue);
|
||||
color: var(--accent-light-blue);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.ol-dialog {
|
||||
align-self: center;
|
||||
background-color: var( --background-slate-blue );
|
||||
color:white;
|
||||
background-color: var(--background-slate-blue);
|
||||
color: white;
|
||||
justify-self: center;
|
||||
position: absolute;
|
||||
z-index:1000;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.ol-panel.ol-dialog {
|
||||
padding:20px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.ol-dialog-close {
|
||||
cursor: pointer;
|
||||
font-size:16px;
|
||||
font-weight: var( --font-weight-bolder );
|
||||
font-size: 16px;
|
||||
font-weight: var(--font-weight-bolder);
|
||||
position: absolute;
|
||||
right: 25px;
|
||||
top: 25px;
|
||||
right: 20px;
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
.ol-dialog-close::before {
|
||||
@@ -133,21 +125,25 @@ dl.ol-data-grid dd {
|
||||
}
|
||||
|
||||
.ol-dialog-header {
|
||||
border-bottom:1px solid var( --background-grey );
|
||||
padding-bottom:10px;
|
||||
border-bottom: 1px solid var(--background-grey);
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.ol-dialog-content {
|
||||
margin:4px 0;
|
||||
}
|
||||
|
||||
.ol-dialog-footer {
|
||||
border-top:1px solid var( --background-grey );
|
||||
padding-top:15px;
|
||||
border-top: 1px solid var(--background-grey);
|
||||
padding-top: 15px;
|
||||
display: flex;
|
||||
row-gap: 10px;
|
||||
}
|
||||
|
||||
.ol-dialog.scrollable .ol-dialog-content {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.ol-checkbox label {
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
@@ -157,63 +153,93 @@ dl.ol-data-grid dd {
|
||||
}
|
||||
|
||||
.ol-checkbox input[type="checkbox"] {
|
||||
appearance:none;
|
||||
appearance: none;
|
||||
background-color: transparent;
|
||||
border:none;
|
||||
margin:0;
|
||||
border: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.ol-checkbox input[type="checkbox"]::before {
|
||||
align-self:center;
|
||||
background-image: url( "/images/icons/square-check-solid.svg" );
|
||||
align-self: center;
|
||||
background-image: url("/images/icons/square-regular.svg");
|
||||
background-repeat: no-repeat;
|
||||
content: "";
|
||||
filter: invert( 100% );
|
||||
display:flex;
|
||||
height:16px;
|
||||
margin-right:10px;
|
||||
width:16px;
|
||||
filter: invert(100%);
|
||||
display: flex;
|
||||
height: 16px;
|
||||
margin-right: 10px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
|
||||
.ol-checkbox input[type="checkbox"]:checked::before {
|
||||
background-image: url( "/images/icons/square-regular.svg" );
|
||||
background-image: url("/images/icons/square-check-solid.svg");
|
||||
}
|
||||
|
||||
.ol-text-input input {
|
||||
height: 40px;
|
||||
border-radius: 5px;
|
||||
color: var(--background-offwhite);
|
||||
background-color: var(--background-grey);
|
||||
border: 1px solid var(--background-grey);
|
||||
border-radius: var(--border-radius-sm);
|
||||
text-align: center;
|
||||
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
input[type=number] {
|
||||
-moz-appearance: textfield;
|
||||
appearance: textfield;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
input[type=number]::-webkit-inner-spin-button,
|
||||
input[type=number]::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
[class|="ol-button"] {
|
||||
align-items: center;
|
||||
background-repeat: no-repeat;
|
||||
display:flex;
|
||||
display: flex;
|
||||
font-weight: normal;
|
||||
padding:8px 10px;
|
||||
padding: 8px 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
[class|="ol-button"]::before {
|
||||
margin-right:8px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.ol-button-close {
|
||||
background: transparent;
|
||||
border:1px solid white;
|
||||
border: 1px solid white;
|
||||
}
|
||||
|
||||
.ol-button-close::before {
|
||||
content: "\d7";
|
||||
}
|
||||
|
||||
.ol-button-apply {
|
||||
background: transparent;
|
||||
border: 1px solid white;
|
||||
}
|
||||
|
||||
.ol-button-apply::before {
|
||||
content: "\2713";
|
||||
}
|
||||
|
||||
.ol-button-settings {
|
||||
background-color: var( --background-slate-blue );
|
||||
background-color: var(--background-slate-blue);
|
||||
}
|
||||
|
||||
.ol-button-settings::before {
|
||||
background-image: url( "/images/icons/gears-solid.svg" );
|
||||
background-position:0 50%;
|
||||
background-size:24px 24px;
|
||||
background-image: url("/images/icons/gears-solid.svg");
|
||||
background-position: 0 50%;
|
||||
background-size: 24px 24px;
|
||||
content: "";
|
||||
display:flex;
|
||||
filter: invert( 100% );
|
||||
display: flex;
|
||||
filter: invert(100%);
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
@import url("layout.css");
|
||||
@import url("airbase.css");
|
||||
@import url("atc.css");
|
||||
@import url("connectionstatuspanel.css");
|
||||
@import url("contextmenus.css");
|
||||
@import url("mouseinfopanel.css");
|
||||
@@ -7,7 +8,7 @@
|
||||
@import url("unitdatatable.css");
|
||||
@import url("unitcontrolpanel.css");
|
||||
@import url("unitinfopanel.css");
|
||||
|
||||
@import url("popup.css");
|
||||
|
||||
|
||||
* {
|
||||
@@ -53,6 +54,10 @@ button {
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: var(--background-hover);
|
||||
}
|
||||
|
||||
button[disabled="disabled"] {
|
||||
color: var(--highlight-color);
|
||||
cursor: not-allowed;
|
||||
@@ -76,6 +81,23 @@ form > div {
|
||||
}
|
||||
|
||||
|
||||
.ol-scrollable::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
.ol-scrollable::-webkit-scrollbar-track {
|
||||
background-color: transparent;
|
||||
border-radius: 100px;
|
||||
}
|
||||
|
||||
.ol-scrollable::-webkit-scrollbar-thumb {
|
||||
background-color: white;
|
||||
border-radius: 100px;
|
||||
opacity: 0.8;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
|
||||
.ol-panel {
|
||||
background-color: var(--background-steel);
|
||||
border-radius: 15px;
|
||||
@@ -123,14 +145,17 @@ form > div {
|
||||
align-items: center;
|
||||
background-color: var(--background-grey);
|
||||
border-radius: var(--border-radius-sm);
|
||||
padding: 1em;
|
||||
padding: 1em 30px 1em 20px;
|
||||
width: 100%;
|
||||
padding-left: 20px;
|
||||
padding-right: 30px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.ol-select.narrow:not(.ol-select-image)>.ol-select-value {
|
||||
opacity: .9;
|
||||
padding:4px 30px 4px 15px;
|
||||
}
|
||||
|
||||
.ol-select:not(.ol-select-image)>.ol-select-value svg {
|
||||
margin-right: 10px;
|
||||
}
|
||||
@@ -142,8 +167,9 @@ form > div {
|
||||
}
|
||||
|
||||
.ol-select>.ol-select-options {
|
||||
position: absolute;
|
||||
border-radius: var( --border-radius-md );
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
max-height: 0;
|
||||
translate: 0 -2px;
|
||||
z-index: 1000;
|
||||
@@ -155,14 +181,20 @@ form > div {
|
||||
|
||||
|
||||
.ol-select.is-open > .ol-select-options {
|
||||
max-height: fit-content;
|
||||
max-height: 382px;
|
||||
overflow: visible;
|
||||
overflow-y: auto;
|
||||
padding: 8px 0;
|
||||
min-width: 100%;
|
||||
z-index:9999;
|
||||
}
|
||||
|
||||
|
||||
.ol-select.is-open[data-position="top"] > .ol-select-options {
|
||||
top:0;
|
||||
translate:0 -100%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.ol-select>.ol-select-options > div {
|
||||
@@ -170,7 +202,7 @@ form > div {
|
||||
box-shadow: 0 4px 4px rgba(0, 0, 0, 0.25);
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
padding: 6px 25px;
|
||||
padding: 4px 25px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -210,22 +242,6 @@ form > div {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.ol-select>.ol-select-options::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
.ol-select>.ol-select-options::-webkit-scrollbar-track {
|
||||
background-color: transparent;
|
||||
border-radius: 100px;
|
||||
}
|
||||
|
||||
.ol-select>.ol-select-options::-webkit-scrollbar-thumb {
|
||||
background-color: white;
|
||||
border-radius: 100px;
|
||||
opacity: 0.8;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
|
||||
.ol-panel-list {
|
||||
border-radius: var(--border-radius-sm);
|
||||
@@ -340,6 +356,12 @@ nav.ol-panel> :last-child {
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
row-gap: 4px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ol-group-header {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ol-panel .ol-group.wrap {
|
||||
@@ -428,8 +450,6 @@ nav.ol-panel> :last-child {
|
||||
font-weight: var(--font-weight-bolder);
|
||||
}
|
||||
|
||||
|
||||
|
||||
.hide {
|
||||
display: none !important;
|
||||
}
|
||||
@@ -517,6 +537,15 @@ nav.ol-panel> :last-child {
|
||||
}
|
||||
|
||||
|
||||
.ol-sortable .handle {
|
||||
background-image: url( "/images/icons/grip-lines-solid.svg" );
|
||||
cursor:ns-resize;
|
||||
filter:invert();
|
||||
height:12px;
|
||||
width:12px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#unit-selection {
|
||||
display: flex;
|
||||
@@ -541,30 +570,6 @@ nav.ol-panel> :last-child {
|
||||
width: 28px;
|
||||
}
|
||||
|
||||
#unit-selection #unit-identification [data-object|="unit"] .unit-short-label {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
#unit-selection #unit-identification #unit-name {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
font-weight: var(--font-weight-bolder);
|
||||
outline: none;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
#edit-unit-name {
|
||||
background-image: url("/images/buttons/edit.svg");
|
||||
background-repeat: no-repeat;
|
||||
height: 14px;
|
||||
margin-left: 10px;
|
||||
width: 15px;
|
||||
}
|
||||
|
||||
#unit-visibility-control {
|
||||
align-items: center;
|
||||
}
|
||||
@@ -615,6 +620,18 @@ body[data-hide-navyunit] #unit-visibility-control-navyunit {
|
||||
background-image: var(--visibility-control-navyunit-hidden-url);
|
||||
}
|
||||
|
||||
#atc-navbar-control {
|
||||
align-items: center;
|
||||
display:flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#atc-navbar-control button {
|
||||
background:#ffffff20;
|
||||
border-radius: var( --border-radius-sm );
|
||||
padding:4px;
|
||||
}
|
||||
|
||||
|
||||
.toggle {
|
||||
--width: 40px;
|
||||
|
||||
23
client/public/stylesheets/popup.css
Normal file
@@ -0,0 +1,23 @@
|
||||
#info-popup {
|
||||
position: absolute;
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
top: 100px;
|
||||
left: 50%;
|
||||
translate: -50% 0%;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.ol-popup > div {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.visible {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.invisible {
|
||||
opacity: 0;
|
||||
transition: opacity 2s linear;
|
||||
}
|
||||
@@ -12,11 +12,17 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
#unit-control-panel h3 {
|
||||
margin-bottom:8px;
|
||||
}
|
||||
|
||||
#unit-control-panel #selected-units-container {
|
||||
align-items: left;
|
||||
border-radius: var( --border-radius-md );
|
||||
display:flex;
|
||||
flex-direction: column;
|
||||
max-height: 136px;
|
||||
overflow-y:auto;
|
||||
row-gap: 4px;
|
||||
}
|
||||
|
||||
@@ -85,5 +91,26 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
|
||||
|
||||
#unit-control-panel h4 {
|
||||
margin-bottom:8px;
|
||||
margin-top:20px;
|
||||
}
|
||||
|
||||
#unit-control-panel #threat,
|
||||
#unit-control-panel #roe {
|
||||
margin-top:12px;
|
||||
}
|
||||
|
||||
#advanced-settings-dialog {
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
#advanced-settings-dialog > .ol-dialog-content {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
row-gap: 10px;
|
||||
}
|
||||
|
||||
#advanced-settings-dialog > .ol-dialog-content > .ol-group {
|
||||
justify-content: space-between;
|
||||
}
|
||||
@@ -26,19 +26,16 @@
|
||||
}
|
||||
|
||||
|
||||
#loadout-container {
|
||||
width:250px;
|
||||
}
|
||||
|
||||
#loadout {
|
||||
display:flex;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
#loadout-silhouette {
|
||||
align-items: center;
|
||||
display:flex;
|
||||
justify-content: center;
|
||||
width:55%;
|
||||
width:100px;
|
||||
}
|
||||
|
||||
#loadout-silhouette::before {
|
||||
@@ -58,8 +55,6 @@
|
||||
display:flex;
|
||||
flex-flow: column nowrap;
|
||||
row-gap: 8px;
|
||||
text-align: center;
|
||||
width:45%;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,27 +62,29 @@
|
||||
align-items: center;
|
||||
column-gap: 8px;
|
||||
display:flex;
|
||||
justify-content: flex-end;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#loadout-items > *::before {
|
||||
align-items: center;
|
||||
background-color: var( --secondary-light-grey );
|
||||
border-radius: 50%;
|
||||
border-radius: var( --border-radius-sm );
|
||||
content: attr( data-qty );
|
||||
display:flex;
|
||||
font-weight: var( --font-weight-bolder );
|
||||
justify-content: center;
|
||||
height:20px;
|
||||
width:20px;
|
||||
padding:1px 4px;
|
||||
}
|
||||
|
||||
#loadout-items > *::after {
|
||||
content: attr( data-item );
|
||||
overflow: hidden;
|
||||
position:relative;
|
||||
text-overflow: ellipsis;
|
||||
width:80px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#fuel-percentage {
|
||||
align-items: center;
|
||||
display:flex;
|
||||
@@ -113,7 +110,6 @@
|
||||
height:6px;
|
||||
margin-top:4px;
|
||||
overflow: hidden;
|
||||
width:90%;
|
||||
}
|
||||
|
||||
#fuel-display #fuel-bar {
|
||||
|
||||
@@ -506,46 +506,38 @@
|
||||
}
|
||||
|
||||
|
||||
[data-object|="unit"] .unit-status {
|
||||
[data-object|="unit"] .unit-state {
|
||||
background-repeat: no-repeat;
|
||||
position:absolute;
|
||||
height:var( --unit-aircraft-status-rtb-height );
|
||||
width:var( --unit-aircraft-status-rtb-width );
|
||||
height:var( --unit-aircraft-state-height );
|
||||
width:var( --unit-aircraft-state-width );
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
[data-object|="unit"][data-status="rtb"] .unit-status {
|
||||
background-image: var( --unit-aircraft-status-rtb-neutral-url );
|
||||
height:var( --unit-aircraft-status-rtb-height );
|
||||
width:var( --unit-aircraft-status-rtb-width );
|
||||
[data-object|="unit"][data-state="rtb"] .unit-state {
|
||||
background-image: var( --unit-aircraft-state-rtb );
|
||||
}
|
||||
|
||||
[data-object|="unit"][data-status="rtb"][data-coalition="blue"] .unit-status {
|
||||
background-image: var( --unit-aircraft-status-rtb-blue-url );
|
||||
[data-object|="unit"][data-state="land"] .unit-state {
|
||||
background-image: var( --unit-aircraft-state-rtb );
|
||||
}
|
||||
|
||||
[data-object|="unit"][data-status="rtb"][data-coalition="red"] .unit-status {
|
||||
background-image: var( --unit-aircraft-status-rtb-red-url );
|
||||
[data-object|="unit"][data-state="idle"] .unit-state {
|
||||
background-image: var( --unit-aircraft-state-idle );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
[data-object|="unit"][data-status="hold"] .unit-status {
|
||||
background-image: var( --unit-aircraft-status-hold-neutral-url );
|
||||
height:var( --unit-aircraft-status-hold-height );
|
||||
width:var( --unit-aircraft-status-hold-width );
|
||||
[data-object|="unit"][data-state="attack"] .unit-state {
|
||||
background-image: var( --unit-aircraft-state-attack );
|
||||
}
|
||||
|
||||
[data-object|="unit"][data-status="hold"][data-coalition="blue"] .unit-status {
|
||||
background-image: var( --unit-aircraft-status-hold-blue-url );
|
||||
[data-object|="unit"][data-state="follow"] .unit-state {
|
||||
background-image: var( --unit-aircraft-state-follow );
|
||||
}
|
||||
|
||||
[data-object|="unit"][data-status="hold"][data-coalition="red"] .unit-status {
|
||||
background-image: var( --unit-aircraft-status-hold-red-url );
|
||||
[data-object|="unit"][data-state="refuel"] .unit-state {
|
||||
background-image: var( --unit-aircraft-state-refuel );
|
||||
}
|
||||
|
||||
|
||||
/*** DEAD ***/
|
||||
[data-object|="unit-aircraft"][ data-is-dead ] {
|
||||
cursor: default;
|
||||
@@ -571,7 +563,7 @@
|
||||
[data-object|="unit-aircraft"][ data-is-dead ] .unit-vvi,
|
||||
[data-object|="unit-aircraft"][ data-is-dead ] .unit-hotgroup,
|
||||
[data-object|="unit-aircraft"][ data-is-dead ] .unit-hotgroup-id,
|
||||
[data-object|="unit-aircraft"][ data-is-dead ] .unit-status,
|
||||
[data-object|="unit-aircraft"][ data-is-dead ] .unit-state,
|
||||
[data-object|="unit-aircraft"][ data-is-dead ] .unit-fuel,
|
||||
[data-object|="unit-aircraft"][ data-is-dead ] .unit-ammo,
|
||||
[data-object|="unit-aircraft"][ data-is-dead ]:hover .unit-fuel,
|
||||
|
||||
53
client/public/themes/olympus/images/state_attack.svg
Normal file
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="19"
|
||||
height="15"
|
||||
viewBox="0 0 19 15"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg6"
|
||||
sodipodi:docname="state_attack.svg"
|
||||
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs10" />
|
||||
<sodipodi:namedview
|
||||
id="namedview8"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="27.733333"
|
||||
inkscape:cx="3.6959135"
|
||||
inkscape:cy="10.258414"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg6" />
|
||||
<path
|
||||
style="fill:none;stroke:#262626;stroke-width:3.6454;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 3.9375571,11.604826 5.4120513,13.142064 8.1100626,10.334251 10.243372,12.373445 9.1610315,11.30679 15.074691,5.314696 14.525677,2.506882 11.81198,1.8794375 5.8198901,7.8087875 4.6748047,6.7891902 6.6826265,8.7499543 Z"
|
||||
id="path2232" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.74012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 3.7087499,11.821755 1.4744947,1.537239 2.926818,-3.024743 c 0.958603,0.899307 1.0509689,0.972539 1.0509689,0.972539 L 14.845884,5.5316249 14.29687,2.7238111 11.583172,2.0963666 5.8198909,7.8087874 c 0,0 -0.1141197,-0.012794 0.8627356,0.9411669 z"
|
||||
id="path2232-9"
|
||||
sodipodi:nodetypes="cccccccccc" />
|
||||
<path
|
||||
style="fill:#262222;fill-opacity:1;stroke-width:0.0124914"
|
||||
d="m 12.8516,4.8268957 c 0.213183,-0.2131845 0.213183,-0.5329611 0,-0.7461455 -0.213185,-0.2131845 -0.532961,-0.2131845 -0.746145,0 L 8.1881937,7.9980144 c -0.2131847,0.2131845 -0.2131847,0.5329612 0,0.7461458 0.1065924,0.106592 0.2398327,0.1598881 0.3730732,0.1598881 0.1332405,0 0.26648,-0.053296 0.3730723,-0.1598881 z"
|
||||
fill="#FFFFFF"
|
||||
id="path4-5" />
|
||||
<path
|
||||
style="fill:none;stroke:#262626;stroke-width:1.19854;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 4.6748047,6.7891902 10.243372,12.373445"
|
||||
id="path2082" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
222
client/public/themes/olympus/images/state_follow.svg
Normal file
@@ -0,0 +1,222 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="19"
|
||||
height="15"
|
||||
viewBox="0 0 19 15"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg6"
|
||||
sodipodi:docname="state_follow.svg"
|
||||
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs10">
|
||||
<marker
|
||||
inkscape:stockid="TriangleOutM"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="marker3764"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path3762"
|
||||
d="M 5.77,0 -2.88,5 V -5 Z"
|
||||
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:1pt;stroke-opacity:1"
|
||||
transform="scale(0.4)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="TriangleOutM"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="marker3754"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path3752"
|
||||
d="M 5.77,0 -2.88,5 V -5 Z"
|
||||
style="fill:#00fff1;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:1pt;stroke-opacity:1"
|
||||
transform="scale(0.4)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Send"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="marker3658"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path3656"
|
||||
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||
transform="matrix(-0.3,0,0,-0.3,0.69,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Send"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="marker3648"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path3646"
|
||||
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||
transform="matrix(-0.3,0,0,-0.3,0.69,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="Arrow2Mend"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow2Mend">
|
||||
<path
|
||||
transform="scale(-0.6)"
|
||||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
|
||||
id="path1088" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="Arrow2Lend"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow2Lend">
|
||||
<path
|
||||
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
|
||||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
|
||||
id="path1082" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="Arrow1Lend"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow1Lend">
|
||||
<path
|
||||
transform="matrix(-0.8,0,0,-0.8,-10,0)"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
||||
id="path1064" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow2Mend-7"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path1088-1"
|
||||
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||
transform="scale(-0.6)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:isstock="true"
|
||||
style="overflow:visible"
|
||||
id="Arrow2Mend-7-8"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow2Mend">
|
||||
<path
|
||||
transform="scale(-0.6)"
|
||||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
|
||||
id="path1088-1-6" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow2Mend-7-8-0"
|
||||
style="overflow:visible"
|
||||
inkscape:isstock="true">
|
||||
<path
|
||||
id="path1088-1-6-8"
|
||||
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
|
||||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||
transform="scale(-0.6)" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="namedview8"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="27.733333"
|
||||
inkscape:cx="4.7776442"
|
||||
inkscape:cy="6.5084135"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg6" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:0.83575px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 9.7400387,13.368089 0.010654,-1.821905"
|
||||
id="path6803" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:2.92331;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 4.4447961,10.874958 V 7.976957"
|
||||
id="path5404"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:2.92331;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 15.077899,10.949537 15.056587,7.9023759"
|
||||
id="path5404-6"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:2.33883;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 5.0092879,8.5461224 3.2885491,-1.9183098 0.025165,-2.0602673 1.4363865,-3.081709 1.3976871,2.9751649 0.0638,2.1668114 3.288548,1.9183098"
|
||||
id="path5844"
|
||||
sodipodi:nodetypes="ccccccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:2.33883;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 5.0092879,10.491885 H 8.297837 v 0.746707 l -1.4877615,1.34107 -0.010655,0.767118 5.8918905,0.03195 -0.02131,-0.905625 -1.449125,-1.234526 v -0.746698 h 3.288549"
|
||||
id="path5912"
|
||||
sodipodi:nodetypes="cccccccccc" />
|
||||
<g
|
||||
transform="matrix(0.88384279,0,0,0.88384279,-4.1038899,-17.309659)"
|
||||
id="layer1-7"
|
||||
inkscape:label="Layer 1"
|
||||
style="fill:#ffffff;fill-opacity:1">
|
||||
<g
|
||||
transform="matrix(0.90904788,0,0,0.91946153,8.2333194,20.900691)"
|
||||
id="g839-1"
|
||||
style="fill:#ffffff;fill-opacity:1">
|
||||
<path
|
||||
d="m 8.6152043,0.96068491 c -0.070984,-0.1658027 -0.2358263,-0.272592 -0.4178212,-0.272592 -0.1818565,0 -0.346698,0.106789 -0.4178225,0.272592 L 6.5262355,3.8523252 C 6.4294515,4.0771272 6.3784085,4.3160075 6.3784085,4.560499 V 6.7242759 L 2.2854009,9.0848093 V 8.5565855 c 0,-0.3737975 -0.304161,-0.6745171 -0.682098,-0.6745171 -0.378076,0 -0.68223699,0.3007196 -0.68223699,0.6745171 v 1.5736425 0.899265 0.674379 c 0,0.373797 0.30416099,0.674518 0.68223699,0.674518 0.377937,0 0.682098,-0.300721 0.682098,-0.674518 v -0.224747 h 4.0930076 v 0.918844 L 4.7156289,13.83966 c -0.09944,0.08425 -0.156335,0.207925 -0.156335,0.337121 v 0.449631 c 0,0.24736 0.204588,0.449631 0.454779,0.449631 h 2.7286708 v -1.798527 c 0,-0.247222 0.2045879,-0.449495 0.4546394,-0.449495 0.2501899,0 0.4547778,0.202273 0.4547778,0.449495 v 1.798527 h 2.7286701 c 0.250191,0 0.454779,-0.202271 0.454779,-0.449631 v -0.449631 c 0,-0.129196 -0.05676,-0.252876 -0.156195,-0.337121 l -1.662919,-1.441691 v -0.918844 h 4.093006 v 0.224747 c 0,0.373797 0.304162,0.674518 0.682098,0.674518 0.378076,0 0.682238,-0.300721 0.682238,-0.674518 V 11.029493 10.130228 8.5565855 c 0,-0.3737975 -0.304162,-0.6745171 -0.682238,-0.6745171 -0.377936,0 -0.682098,0.3007196 -0.682098,0.6745171 V 9.0848093 L 10.016496,6.7242759 V 4.560499 c 0,-0.2444915 -0.051184,-0.4833718 -0.1478275,-0.7081738 z"
|
||||
fill="#202831"
|
||||
id="path2-5"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:1.38669" />
|
||||
</g>
|
||||
<circle
|
||||
r="0"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:0.225344;stroke-linecap:round"
|
||||
id="path865-3-0"
|
||||
cx="29.19866"
|
||||
cy="80.130951" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.5 KiB |
4
client/public/themes/olympus/images/state_idle.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.5356 0.900581C9.69508 -0.282964 11.5945 -0.302474 12.778 0.857004L14.5643 2.607C15.1403 3.17128 15.4649 3.94367 15.4649 4.75C15.4649 4.98835 15.4366 5.22373 15.3817 5.45165C15.8245 5.85549 16.151 6.39558 16.2888 7.02558L16.4103 7.58115L16.4103 7.58116C17.2333 11.3434 14.3009 14.75 10.5685 14.75H8.64315C8.50267 15.0566 8.30769 15.3446 8.05807 15.5994C6.89859 16.783 4.99919 16.8025 3.81565 15.643L2.02933 13.893C1.45334 13.3287 1.12875 12.5563 1.12875 11.75C1.12875 11.5117 1.15711 11.2763 1.21194 11.0484C0.769126 10.6445 0.442675 10.1044 0.30487 9.47436L0.183357 8.91882C0.183355 8.91881 0.183354 8.9188 0.183352 8.9188C-0.639549 5.15664 2.29279 1.75 6.02519 1.75H7.95052C8.09101 1.44337 8.28598 1.15538 8.5356 0.900581ZM7.95052 7.75H7.89958C7.93031 7.77715 7.9606 7.80505 7.99045 7.83367C7.97668 7.80595 7.96338 7.77805 7.95052 7.75ZM8.60322 8.66633C8.61699 8.69406 8.6303 8.72195 8.64315 8.75H8.69409C8.66337 8.72285 8.63307 8.69496 8.60322 8.66633Z" fill="#2F2F2F"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.1426 2.47515C10.4325 2.17926 10.9074 2.17438 11.2032 2.46425L12.9896 4.21425C13.1336 4.35532 13.2147 4.54842 13.2147 4.75C13.2147 4.95158 13.1336 5.14468 12.9896 5.28575L11.2032 7.03575C10.9074 7.32562 10.4325 7.32074 10.1426 7.02486C9.85276 6.72897 9.85764 6.25412 10.1535 5.96425L10.6274 5.5H6.02497C4.5888 5.5 3.55582 6.78851 3.84652 8.11751L3.84652 8.11751L3.96804 8.67308C4.05655 9.07772 3.80027 9.4775 3.39562 9.56601C2.99097 9.65452 2.59119 9.39824 2.50268 8.99359L2.38117 8.43803C2.38117 8.43803 2.38117 8.43803 2.38117 8.43802C1.87759 6.13576 3.6703 4 6.02497 4H10.6274L10.1535 3.53575C9.85764 3.24588 9.85276 2.77103 10.1426 2.47515ZM13.1976 6.93399C13.6022 6.84548 14.002 7.10175 14.0905 7.5064L14.2121 8.06196L13.5077 8.21604L14.2121 8.06196C14.7157 10.3642 12.9229 12.5 10.5683 12.5H5.96582L6.4397 12.9643C6.73559 13.2541 6.74047 13.729 6.4506 14.0249C6.16073 14.3207 5.68588 14.3256 5.38999 14.0357L3.60367 12.2857C3.45967 12.1447 3.37853 11.9516 3.37853 11.75C3.37853 11.5484 3.45967 11.3553 3.60367 11.2143L5.38999 9.46425C5.68588 9.17438 6.16073 9.17926 6.4506 9.47515C6.74047 9.77103 6.73559 10.2459 6.4397 10.5357L5.96582 11H10.5683C12.0044 11 13.0374 9.71149 12.7467 8.38251L12.6252 7.82694C12.5367 7.42229 12.7929 7.02251 13.1976 6.93399Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
61
client/public/themes/olympus/images/state_refuel.svg
Normal file
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="19"
|
||||
height="15"
|
||||
viewBox="0 0 19 15"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg6"
|
||||
sodipodi:docname="state_refuel.svg"
|
||||
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs10" />
|
||||
<sodipodi:namedview
|
||||
id="namedview8"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="19.610428"
|
||||
inkscape:cx="9.1532933"
|
||||
inkscape:cy="9.2042866"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg6" />
|
||||
<path
|
||||
style="fill:none;stroke:#262626;stroke-width:2.80114;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 14.109032,5.6203217 14.096876,4.2589893"
|
||||
id="path3134"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;stroke:#262626;stroke-width:4.752;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 11.2162,7.8446415 c 0.611292,0.23067 1.379382,0.1813438 1.567963,1.1668564 l 0.01216,0.9116069 0.948071,1.1060822 c 0.556356,0.0066 1.240492,0.262304 1.17901,-0.935916 L 15.032793,5.7783334 C 15.029293,5.1839171 14.968765,4.6085103 14.485828,4.173906 L 13.075877,2.7761093"
|
||||
id="path2668"
|
||||
sodipodi:nodetypes="cccccccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#262626;stroke-width:5.05323;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 5.5156203,2.6788713 v 9.4807077 l -0.9723803,0.02431 7.122686,0.01216 -1.069619,-0.03646 V 2.6302523 Z"
|
||||
id="path2480"
|
||||
sodipodi:nodetypes="ccccccc" />
|
||||
<path
|
||||
d="M 11.606497,11.523453 H 4.6132695 c -0.1923136,0 -0.3496607,0.157348 -0.3496607,0.349662 v 0.699322 c 0,0.192314 0.1573471,0.349662 0.3496607,0.349662 h 6.9932275 c 0.192314,0 0.349661,-0.157348 0.349661,-0.349662 v -0.699322 c 0,-0.192314 -0.157347,-0.349662 -0.349661,-0.349662 z M 15.04192,4.0778511 13.27176,2.3076902 c -0.135494,-0.1354933 -0.358404,-0.1354933 -0.493897,0 l -0.246948,0.2469485 c -0.135494,0.1354943 -0.135494,0.3584027 0,0.493897 l 0.823889,0.8238892 V 5.229548 c 0,0.6140934 0.456745,1.1211021 1.048985,1.206332 v 3.5140965 c 0,0.2884715 -0.236022,0.5244925 -0.524492,0.5244925 -0.288471,0 -0.524493,-0.236021 -0.524493,-0.5244925 V 9.2506542 c 0,-1.0620966 -0.861041,-1.9231375 -1.923138,-1.9231375 h -0.17483 V 3.1315803 c 0,-0.7714404 -0.627205,-1.3986455 -1.3986454,-1.3986455 h -3.496614 c -0.7714405,0 -1.3986455,0.6272051 -1.3986455,1.3986455 V 10.82413 H 11.256836 V 8.3765006 h 0.17483 c 0.482971,0 0.874154,0.3911839 0.874154,0.8741536 v 0.6075366 c 0,0.8238902 0.590054,1.5734762 1.409573,1.6587062 0.939715,0.09397 1.73738,-0.644688 1.73738,-1.5669205 V 5.0678294 c 0,-0.3715144 -0.148606,-0.7277319 -0.410853,-0.9899783 z M 9.8581906,5.9288713 h -3.496614 v -2.797291 h 3.496614 z"
|
||||
id="path2270"
|
||||
style="fill:#fffffd;fill-opacity:1;stroke-width:0.0218539" />
|
||||
<rect
|
||||
style="fill:#262626;fill-opacity:1;stroke:none;stroke-width:0.100774;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
id="rect3805"
|
||||
width="3.496614"
|
||||
height="2.7972908"
|
||||
x="6.3615766"
|
||||
y="3.1315804" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
4
client/public/themes/olympus/images/state_rtb.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="19" height="15" viewBox="0 0 19 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.83594 4.99219L4.52344 8.55469V12.375C4.52344 12.5859 4.6875 12.75 4.89844 12.75H7.52344C7.71094 12.75 7.875 12.5859 7.875 12.375V10.125C7.875 9.9375 8.0625 9.75 8.25 9.75H9.75C9.96094 9.75 10.125 9.9375 10.125 10.125V12.375C10.125 12.5859 10.3125 12.75 10.5 12.75H13.1484C13.3359 12.75 13.5234 12.5859 13.5234 12.375V8.53125L9.1875 4.99219C9.14062 4.94531 9.07031 4.92188 9.02344 4.92188C8.95312 4.92188 8.88281 4.94531 8.83594 4.99219ZM15.6562 7.40625L13.7109 5.78906V2.55469C13.7109 2.39062 13.5703 2.27344 13.4297 2.27344H12.1172C11.9531 2.27344 11.8359 2.39062 11.8359 2.55469V4.24219L9.72656 2.50781C9.53906 2.36719 9.28125 2.27344 9.02344 2.27344C8.74219 2.27344 8.48438 2.36719 8.29688 2.50781L2.36719 7.40625C2.29688 7.45312 2.25 7.54688 2.25 7.61719C2.25 7.6875 2.29688 7.75781 2.32031 7.80469L2.92969 8.53125C2.97656 8.60156 3.04688 8.625 3.14062 8.625C3.21094 8.625 3.28125 8.60156 3.32812 8.55469L8.83594 4.03125C8.88281 3.98438 8.95312 3.96094 9.02344 3.96094C9.07031 3.96094 9.14062 3.98438 9.1875 4.03125L14.6953 8.55469C14.7422 8.60156 14.8125 8.625 14.8828 8.625C14.9766 8.625 15.0469 8.60156 15.0938 8.53125L15.7031 7.80469C15.75 7.75781 15.7734 7.6875 15.7734 7.61719C15.7734 7.54688 15.7266 7.45312 15.6562 7.40625Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.5234 8.53125V12.375C13.5234 12.5859 13.3359 12.75 13.1484 12.75H10.5C10.3125 12.75 10.125 12.5859 10.125 12.375V10.125C10.125 9.9375 9.96094 9.75 9.75 9.75H8.25C8.0625 9.75 7.875 9.9375 7.875 10.125V12.375C7.875 12.5859 7.71094 12.75 7.52344 12.75H4.89844C4.6875 12.75 4.52344 12.5859 4.52344 12.375V8.55469L8.83594 4.99219C8.88281 4.94531 8.95312 4.92188 9.02344 4.92188C9.07031 4.92188 9.14062 4.94531 9.1875 4.99219L13.5234 8.53125ZM14.6953 8.55469C14.6964 8.55582 14.6976 8.55693 14.6987 8.55803C14.737 8.5945 14.7898 8.61608 14.8452 8.62275C14.8577 8.62425 14.8702 8.625 14.8828 8.625C14.9766 8.625 15.0469 8.60156 15.0938 8.53125L15.7031 7.80469C15.75 7.75781 15.7734 7.6875 15.7734 7.61719C15.7734 7.58321 15.7625 7.54375 15.7432 7.50676C15.7227 7.46721 15.6926 7.43047 15.6562 7.40625L13.7109 5.78906V2.55469C13.7109 2.39062 13.5703 2.27344 13.4297 2.27344H12.1172C11.9531 2.27344 11.8359 2.39062 11.8359 2.55469V4.24219L9.72656 2.50781C9.68416 2.47601 9.63816 2.44661 9.58938 2.42014C9.42246 2.32958 9.22295 2.27344 9.02344 2.27344C8.74219 2.27344 8.48438 2.36719 8.29688 2.50781L2.36719 7.40625C2.34189 7.42312 2.31962 7.44605 2.30148 7.47178C2.29357 7.483 2.28645 7.49475 2.2802 7.50676C2.27782 7.51134 2.27556 7.51595 2.27344 7.52059C2.25841 7.55343 2.25 7.58741 2.25 7.61719C2.25 7.64997 2.26019 7.68274 2.27344 7.71315C2.28332 7.73582 2.29491 7.75718 2.30524 7.77623C2.31078 7.78642 2.31595 7.79596 2.32031 7.80469L2.92969 8.53125C2.93534 8.53973 2.94134 8.54753 2.94767 8.55469C2.99386 8.60688 3.05818 8.625 3.14062 8.625C3.15319 8.625 3.16576 8.62425 3.17819 8.62275C3.23202 8.61627 3.28333 8.59576 3.32129 8.56121C3.32362 8.55909 3.3259 8.55692 3.32812 8.55469L8.83594 4.03125C8.88281 3.98438 8.95312 3.96094 9.02344 3.96094C9.07031 3.96094 9.14062 3.98438 9.1875 4.03125L14.6953 8.55469ZM2.27344 10.7274C1.89755 10.5959 1.49315 10.355 1.16162 9.92451L0.426251 9.04772L0.32017 8.83555C0.319597 8.83449 0.319 8.83338 0.318378 8.83223C0.304066 8.80565 0.267288 8.73712 0.228043 8.65078C0.161627 8.50467 0 8.12434 0 7.61719C0 7.12558 0.148836 6.71911 0.301167 6.4362C0.439348 6.17958 0.654902 5.88605 0.975475 5.63749L6.90462 0.739506L6.94688 0.707813C7.52384 0.275088 8.25535 0.0234375 9.02344 0.0234375C9.62455 0.0234375 10.201 0.186404 10.691 0.458244C11.0961 0.183444 11.5866 0.0234375 12.1172 0.0234375H13.4297C14.6901 0.0234375 15.9609 1.02855 15.9609 2.55469V4.73359L17.0522 5.64079C17.3704 5.88864 17.5847 6.18072 17.7223 6.4362C17.8746 6.71911 18.0234 7.12558 18.0234 7.61719C18.0234 8.10158 17.8785 8.74439 17.3959 9.28773L16.8618 9.92451C16.5372 10.3461 16.1426 10.5858 15.7734 10.719V12.375C15.7734 13.9179 14.4874 15 13.1484 15H10.5C9.9703 15 9.44888 14.8306 9.01208 14.5304C8.60011 14.823 8.09287 15 7.52344 15H4.89844C3.44486 15 2.27344 13.8286 2.27344 12.375V10.7274Z" fill="#262222"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
@@ -31,6 +31,8 @@
|
||||
--secondary-light-grey : #797e83;
|
||||
--secondary-yellow : #ffd46893;
|
||||
|
||||
--background-hover : #f2f2f333;
|
||||
|
||||
--nav-text : #ECECEC;
|
||||
|
||||
|
||||
@@ -120,24 +122,17 @@
|
||||
--unit-aircraft-marker-red-dead-url: url( "/themes/olympus/images/icon_death_red.svg" );
|
||||
|
||||
|
||||
/*** Air units' statuses ***/
|
||||
/*** Air units' states ***/
|
||||
|
||||
--unit-aircraft-status-rtb-height: 50px;
|
||||
--unit-aircraft-status-rtb-width: 50px;
|
||||
--unit-aircraft-state-height: 50px;
|
||||
--unit-aircraft-state-width: 50px;
|
||||
|
||||
--unit-aircraft-status-rtb-blue-url: url( "data:image/svg+xml,%3Csvg width='19' height='15' viewBox='0 0 19 15' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M9.8125 4.99219L5.5 8.55469V12.375C5.5 12.5859 5.66406 12.75 5.875 12.75H8.5C8.6875 12.75 8.85156 12.5859 8.85156 12.375V10.125C8.85156 9.9375 9.03906 9.75 9.22656 9.75H10.7266C10.9375 9.75 11.1016 9.9375 11.1016 10.125V12.375C11.1016 12.5859 11.2891 12.75 11.4766 12.75H14.125C14.3125 12.75 14.5 12.5859 14.5 12.375V8.53125L10.1641 4.99219C10.1172 4.94531 10.0469 4.92188 10 4.92188C9.92969 4.92188 9.85938 4.94531 9.8125 4.99219ZM16.6328 7.40625L14.6875 5.78906V2.55469C14.6875 2.39062 14.5469 2.27344 14.4062 2.27344H13.0938C12.9297 2.27344 12.8125 2.39062 12.8125 2.55469V4.24219L10.7031 2.50781C10.5156 2.36719 10.2578 2.27344 10 2.27344C9.71875 2.27344 9.46094 2.36719 9.27344 2.50781L3.34375 7.40625C3.27344 7.45312 3.22656 7.54688 3.22656 7.61719C3.22656 7.6875 3.27344 7.75781 3.29688 7.80469L3.90625 8.53125C3.95312 8.60156 4.02344 8.625 4.11719 8.625C4.1875 8.625 4.25781 8.60156 4.30469 8.55469L9.8125 4.03125C9.85938 3.98438 9.92969 3.96094 10 3.96094C10.0469 3.96094 10.1172 3.98438 10.1641 4.03125L15.6719 8.55469C15.7188 8.60156 15.7891 8.625 15.8594 8.625C15.9531 8.625 16.0234 8.60156 16.0703 8.53125L16.6797 7.80469C16.7266 7.75781 16.75 7.6875 16.75 7.61719C16.75 7.54688 16.7031 7.45312 16.6328 7.40625Z' fill='white'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M14.5 8.53125V12.375C14.5 12.5859 14.3125 12.75 14.125 12.75H11.4766C11.2891 12.75 11.1016 12.5859 11.1016 12.375V10.125C11.1016 9.9375 10.9375 9.75 10.7266 9.75H9.22656C9.03906 9.75 8.85156 9.9375 8.85156 10.125V12.375C8.85156 12.5859 8.6875 12.75 8.5 12.75H5.875C5.66406 12.75 5.5 12.5859 5.5 12.375V8.55469L9.8125 4.99219C9.85938 4.94531 9.92969 4.92188 10 4.92188C10.0469 4.92188 10.1172 4.94531 10.1641 4.99219L14.5 8.53125ZM15.6719 8.55469C15.673 8.55582 15.6741 8.55693 15.6753 8.55803C15.7136 8.5945 15.7664 8.61608 15.8218 8.62275C15.8342 8.62425 15.8468 8.625 15.8594 8.625C15.9531 8.625 16.0234 8.60156 16.0703 8.53125L16.6797 7.80469C16.7266 7.75781 16.75 7.6875 16.75 7.61719C16.75 7.58321 16.7391 7.54375 16.7198 7.50676C16.6992 7.46721 16.6691 7.43047 16.6328 7.40625L14.6875 5.78906V2.55469C14.6875 2.39062 14.5469 2.27344 14.4062 2.27344H13.0938C12.9297 2.27344 12.8125 2.39062 12.8125 2.55469V4.24219L10.7031 2.50781C10.6607 2.47601 10.6147 2.44661 10.5659 2.42014C10.399 2.32958 10.1995 2.27344 10 2.27344C9.71875 2.27344 9.46094 2.36719 9.27344 2.50781L3.34375 7.40625C3.31845 7.42312 3.29618 7.44605 3.27804 7.47178C3.27013 7.483 3.26301 7.49475 3.25676 7.50676C3.25438 7.51134 3.25212 7.51595 3.25 7.52059C3.23497 7.55343 3.22656 7.58741 3.22656 7.61719C3.22656 7.64997 3.23675 7.68274 3.25 7.71315C3.25988 7.73582 3.27147 7.75718 3.2818 7.77623C3.28734 7.78642 3.29251 7.79596 3.29688 7.80469L3.90625 8.53125C3.9119 8.53973 3.9179 8.54753 3.92423 8.55469C3.97043 8.60688 4.03475 8.625 4.11719 8.625C4.12975 8.625 4.14232 8.62425 4.15475 8.62275C4.20858 8.61627 4.2599 8.59576 4.29785 8.56121C4.30018 8.55909 4.30246 8.55692 4.30469 8.55469L9.8125 4.03125C9.85938 3.98438 9.92969 3.96094 10 3.96094C10.0469 3.96094 10.1172 3.98438 10.1641 4.03125L15.6719 8.55469ZM3.25 10.7274C2.87411 10.5959 2.46972 10.355 2.13819 9.92451L1.40281 9.04772L1.29673 8.83555C1.29616 8.83449 1.29556 8.83338 1.29494 8.83223C1.28063 8.80565 1.24385 8.73712 1.20461 8.65078C1.13819 8.50467 0.976562 8.12434 0.976562 7.61719C0.976562 7.12558 1.1254 6.71911 1.27773 6.4362C1.41591 6.17958 1.63146 5.88605 1.95204 5.63749L7.88118 0.739506L7.92344 0.707813C8.5004 0.275088 9.23192 0.0234375 10 0.0234375C10.6011 0.0234375 11.1776 0.186404 11.6675 0.458244C12.0727 0.183444 12.5631 0.0234375 13.0938 0.0234375H14.4062C15.6666 0.0234375 16.9375 1.02855 16.9375 2.55469V4.73359L18.0288 5.64079C18.347 5.88864 18.5613 6.18072 18.6988 6.4362C18.8512 6.71911 19 7.12558 19 7.61719C19 8.10158 18.8551 8.74439 18.3724 9.28773L17.8384 9.92451C17.5137 10.3461 17.1192 10.5858 16.75 10.719V12.375C16.75 13.9179 15.4639 15 14.125 15H11.4766C10.9469 15 10.4254 14.8306 9.98865 14.5304C9.57667 14.823 9.06944 15 8.5 15H5.875C4.42142 15 3.25 13.8286 3.25 12.375V10.7274Z' fill='%23082E44'/%3E%3C/svg%3E" );
|
||||
--unit-aircraft-status-rtb-neutral-url: url( "data:image/svg+xml,%3Csvg width='19' height='15' viewBox='0 0 19 15' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8.85938 4.99219L4.54688 8.55469V12.375C4.54688 12.5859 4.71094 12.75 4.92188 12.75H7.54688C7.73438 12.75 7.89844 12.5859 7.89844 12.375V10.125C7.89844 9.9375 8.08594 9.75 8.27344 9.75H9.77344C9.98438 9.75 10.1484 9.9375 10.1484 10.125V12.375C10.1484 12.5859 10.3359 12.75 10.5234 12.75H13.1719C13.3594 12.75 13.5469 12.5859 13.5469 12.375V8.53125L9.21094 4.99219C9.16406 4.94531 9.09375 4.92188 9.04688 4.92188C8.97656 4.92188 8.90625 4.94531 8.85938 4.99219ZM15.6797 7.40625L13.7344 5.78906V2.55469C13.7344 2.39062 13.5938 2.27344 13.4531 2.27344H12.1406C11.9766 2.27344 11.8594 2.39062 11.8594 2.55469V4.24219L9.75 2.50781C9.5625 2.36719 9.30469 2.27344 9.04688 2.27344C8.76562 2.27344 8.50781 2.36719 8.32031 2.50781L2.39062 7.40625C2.32031 7.45312 2.27344 7.54688 2.27344 7.61719C2.27344 7.6875 2.32031 7.75781 2.34375 7.80469L2.95312 8.53125C3 8.60156 3.07031 8.625 3.16406 8.625C3.23438 8.625 3.30469 8.60156 3.35156 8.55469L8.85938 4.03125C8.90625 3.98438 8.97656 3.96094 9.04688 3.96094C9.09375 3.96094 9.16406 3.98438 9.21094 4.03125L14.7188 8.55469C14.7656 8.60156 14.8359 8.625 14.9062 8.625C15 8.625 15.0703 8.60156 15.1172 8.53125L15.7266 7.80469C15.7734 7.75781 15.7969 7.6875 15.7969 7.61719C15.7969 7.54688 15.75 7.45312 15.6797 7.40625Z' fill='white'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M13.5469 8.53125V12.375C13.5469 12.5859 13.3594 12.75 13.1719 12.75H10.5234C10.3359 12.75 10.1484 12.5859 10.1484 12.375V10.125C10.1484 9.9375 9.98438 9.75 9.77344 9.75H8.27344C8.08594 9.75 7.89844 9.9375 7.89844 10.125V12.375C7.89844 12.5859 7.73438 12.75 7.54688 12.75H4.92188C4.71094 12.75 4.54688 12.5859 4.54688 12.375V8.55469L8.85938 4.99219C8.90625 4.94531 8.97656 4.92188 9.04688 4.92188C9.09375 4.92188 9.16406 4.94531 9.21094 4.99219L13.5469 8.53125ZM14.7188 8.55469C14.7199 8.55582 14.721 8.55693 14.7222 8.55803C14.7604 8.5945 14.8132 8.61608 14.8687 8.62275C14.8811 8.62425 14.8937 8.625 14.9062 8.625C15 8.625 15.0703 8.60156 15.1172 8.53125L15.7266 7.80469C15.7734 7.75781 15.7969 7.6875 15.7969 7.61719C15.7969 7.58321 15.7859 7.54375 15.7667 7.50676C15.7461 7.46721 15.716 7.43047 15.6797 7.40625L13.7344 5.78906V2.55469C13.7344 2.39062 13.5938 2.27344 13.4531 2.27344H12.1406C11.9766 2.27344 11.8594 2.39062 11.8594 2.55469V4.24219L9.75 2.50781C9.7076 2.47601 9.6616 2.44661 9.61282 2.42014C9.4459 2.32958 9.24639 2.27344 9.04688 2.27344C8.76562 2.27344 8.50781 2.36719 8.32031 2.50781L2.39062 7.40625C2.36532 7.42312 2.34306 7.44605 2.32492 7.47178C2.31701 7.483 2.30989 7.49475 2.30364 7.50676C2.30125 7.51134 2.299 7.51595 2.29688 7.52059C2.28184 7.55343 2.27344 7.58741 2.27344 7.61719C2.27344 7.64997 2.28362 7.68274 2.29688 7.71315C2.30676 7.73582 2.31834 7.75718 2.32868 7.77623C2.33421 7.78642 2.33939 7.79596 2.34375 7.80469L2.95312 8.53125C2.95878 8.53973 2.96477 8.54753 2.97111 8.55469C3.0173 8.60688 3.08162 8.625 3.16406 8.625C3.17663 8.625 3.1892 8.62425 3.20163 8.62275C3.25545 8.61627 3.30677 8.59576 3.34472 8.56121C3.34705 8.55909 3.34933 8.55692 3.35156 8.55469L8.85938 4.03125C8.90625 3.98438 8.97656 3.96094 9.04688 3.96094C9.09375 3.96094 9.16406 3.98438 9.21094 4.03125L14.7188 8.55469ZM2.29688 10.7274C1.92098 10.5959 1.51659 10.355 1.18506 9.92451L0.449688 9.04772L0.343607 8.83555C0.343034 8.83449 0.342438 8.83338 0.341816 8.83223C0.327503 8.80565 0.290725 8.73712 0.25148 8.65078C0.185064 8.50467 0.0234375 8.12434 0.0234375 7.61719C0.0234375 7.12558 0.172273 6.71911 0.324604 6.4362C0.462785 6.17958 0.67834 5.88605 0.998912 5.63749L6.92805 0.739506L6.97031 0.707813C7.54728 0.275088 8.27879 0.0234375 9.04688 0.0234375C9.64799 0.0234375 10.2245 0.186404 10.7144 0.458244C11.1195 0.183444 11.61 0.0234375 12.1406 0.0234375H13.4531C14.7135 0.0234375 15.9844 1.02855 15.9844 2.55469V4.73359L17.0756 5.64079C17.3939 5.88864 17.6081 6.18072 17.7457 6.4362C17.898 6.71911 18.0469 7.12558 18.0469 7.61719C18.0469 8.10158 17.902 8.74439 17.4193 9.28773L16.8852 9.92451C16.5606 10.3461 16.1661 10.5858 15.7969 10.719V12.375C15.7969 13.9179 14.5108 15 13.1719 15H10.5234C9.99374 15 9.47232 14.8306 9.03552 14.5304C8.62355 14.823 8.11631 15 7.54688 15H4.92188C3.4683 15 2.29688 13.8286 2.29688 12.375V10.7274Z' fill='%232F2F2F'/%3E%3C/svg%3E" );
|
||||
--unit-aircraft-status-rtb-red-url: url( "data:image/svg+xml,%3Csvg width='19' height='15' viewBox='0 0 19 15' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8.83594 4.99219L4.52344 8.55469V12.375C4.52344 12.5859 4.6875 12.75 4.89844 12.75H7.52344C7.71094 12.75 7.875 12.5859 7.875 12.375V10.125C7.875 9.9375 8.0625 9.75 8.25 9.75H9.75C9.96094 9.75 10.125 9.9375 10.125 10.125V12.375C10.125 12.5859 10.3125 12.75 10.5 12.75H13.1484C13.3359 12.75 13.5234 12.5859 13.5234 12.375V8.53125L9.1875 4.99219C9.14062 4.94531 9.07031 4.92188 9.02344 4.92188C8.95312 4.92188 8.88281 4.94531 8.83594 4.99219ZM15.6562 7.40625L13.7109 5.78906V2.55469C13.7109 2.39062 13.5703 2.27344 13.4297 2.27344H12.1172C11.9531 2.27344 11.8359 2.39062 11.8359 2.55469V4.24219L9.72656 2.50781C9.53906 2.36719 9.28125 2.27344 9.02344 2.27344C8.74219 2.27344 8.48438 2.36719 8.29688 2.50781L2.36719 7.40625C2.29688 7.45312 2.25 7.54688 2.25 7.61719C2.25 7.6875 2.29688 7.75781 2.32031 7.80469L2.92969 8.53125C2.97656 8.60156 3.04688 8.625 3.14062 8.625C3.21094 8.625 3.28125 8.60156 3.32812 8.55469L8.83594 4.03125C8.88281 3.98438 8.95312 3.96094 9.02344 3.96094C9.07031 3.96094 9.14062 3.98438 9.1875 4.03125L14.6953 8.55469C14.7422 8.60156 14.8125 8.625 14.8828 8.625C14.9766 8.625 15.0469 8.60156 15.0938 8.53125L15.7031 7.80469C15.75 7.75781 15.7734 7.6875 15.7734 7.61719C15.7734 7.54688 15.7266 7.45312 15.6562 7.40625Z' fill='white'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M13.5234 8.53125V12.375C13.5234 12.5859 13.3359 12.75 13.1484 12.75H10.5C10.3125 12.75 10.125 12.5859 10.125 12.375V10.125C10.125 9.9375 9.96094 9.75 9.75 9.75H8.25C8.0625 9.75 7.875 9.9375 7.875 10.125V12.375C7.875 12.5859 7.71094 12.75 7.52344 12.75H4.89844C4.6875 12.75 4.52344 12.5859 4.52344 12.375V8.55469L8.83594 4.99219C8.88281 4.94531 8.95312 4.92188 9.02344 4.92188C9.07031 4.92188 9.14062 4.94531 9.1875 4.99219L13.5234 8.53125ZM14.6953 8.55469C14.6964 8.55582 14.6976 8.55693 14.6987 8.55803C14.737 8.5945 14.7898 8.61608 14.8452 8.62275C14.8577 8.62425 14.8702 8.625 14.8828 8.625C14.9766 8.625 15.0469 8.60156 15.0938 8.53125L15.7031 7.80469C15.75 7.75781 15.7734 7.6875 15.7734 7.61719C15.7734 7.58321 15.7625 7.54375 15.7432 7.50676C15.7227 7.46721 15.6926 7.43047 15.6562 7.40625L13.7109 5.78906V2.55469C13.7109 2.39062 13.5703 2.27344 13.4297 2.27344H12.1172C11.9531 2.27344 11.8359 2.39062 11.8359 2.55469V4.24219L9.72656 2.50781C9.68416 2.47601 9.63816 2.44661 9.58938 2.42014C9.42246 2.32958 9.22295 2.27344 9.02344 2.27344C8.74219 2.27344 8.48438 2.36719 8.29688 2.50781L2.36719 7.40625C2.34189 7.42312 2.31962 7.44605 2.30148 7.47178C2.29357 7.483 2.28645 7.49475 2.2802 7.50676C2.27782 7.51134 2.27556 7.51595 2.27344 7.52059C2.25841 7.55343 2.25 7.58741 2.25 7.61719C2.25 7.64997 2.26019 7.68274 2.27344 7.71315C2.28332 7.73582 2.29491 7.75718 2.30524 7.77623C2.31078 7.78642 2.31595 7.79596 2.32031 7.80469L2.92969 8.53125C2.93534 8.53973 2.94134 8.54753 2.94767 8.55469C2.99386 8.60688 3.05818 8.625 3.14062 8.625C3.15319 8.625 3.16576 8.62425 3.17819 8.62275C3.23202 8.61627 3.28333 8.59576 3.32129 8.56121C3.32362 8.55909 3.3259 8.55692 3.32812 8.55469L8.83594 4.03125C8.88281 3.98438 8.95312 3.96094 9.02344 3.96094C9.07031 3.96094 9.14062 3.98438 9.1875 4.03125L14.6953 8.55469ZM2.27344 10.7274C1.89755 10.5959 1.49315 10.355 1.16162 9.92451L0.426251 9.04772L0.32017 8.83555C0.319597 8.83449 0.319 8.83338 0.318378 8.83223C0.304066 8.80565 0.267288 8.73712 0.228043 8.65078C0.161627 8.50467 0 8.12434 0 7.61719C0 7.12558 0.148836 6.71911 0.301167 6.4362C0.439348 6.17958 0.654902 5.88605 0.975475 5.63749L6.90462 0.739506L6.94688 0.707813C7.52384 0.275088 8.25535 0.0234375 9.02344 0.0234375C9.62455 0.0234375 10.201 0.186404 10.691 0.458244C11.0961 0.183444 11.5866 0.0234375 12.1172 0.0234375H13.4297C14.6901 0.0234375 15.9609 1.02855 15.9609 2.55469V4.73359L17.0522 5.64079C17.3704 5.88864 17.5847 6.18072 17.7223 6.4362C17.8746 6.71911 18.0234 7.12558 18.0234 7.61719C18.0234 8.10158 17.8785 8.74439 17.3959 9.28773L16.8618 9.92451C16.5372 10.3461 16.1426 10.5858 15.7734 10.719V12.375C15.7734 13.9179 14.4874 15 13.1484 15H10.5C9.9703 15 9.44888 14.8306 9.01208 14.5304C8.60011 14.823 8.09287 15 7.52344 15H4.89844C3.44486 15 2.27344 13.8286 2.27344 12.375V10.7274Z' fill='%23262222'/%3E%3C/svg%3E" );
|
||||
--unit-aircraft-state-rtb: url( "/themes/olympus/images/state_rtb.svg" );
|
||||
--unit-aircraft-state-idle: url( "/themes/olympus/images/state_idle.svg" );
|
||||
--unit-aircraft-state-attack: url( "/themes/olympus/images/state_attack.svg" );
|
||||
--unit-aircraft-state-follow: url( "/themes/olympus/images/state_follow.svg" );
|
||||
--unit-aircraft-state-refuel: url( "/themes/olympus/images/state_refuel.svg" );
|
||||
|
||||
|
||||
--unit-aircraft-status-hold-height: 50px;
|
||||
--unit-aircraft-status-hold-width: 50px;
|
||||
|
||||
--unit-aircraft-status-hold-blue-url: url( "data:image/svg+xml,%3Csvg width='18' height='17' viewBox='0 0 18 17' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9.48873 0.900581C10.6482 -0.282964 12.5476 -0.302474 13.7311 0.857004L15.5175 2.607C16.0935 3.17128 16.4181 3.94367 16.4181 4.75C16.4181 4.98835 16.3897 5.22373 16.3349 5.45165C16.7777 5.85549 17.1041 6.39558 17.2419 7.02558L17.3634 7.58115L17.3634 7.58116C18.1864 11.3434 15.254 14.75 11.5216 14.75H9.59627C9.45579 15.0566 9.26081 15.3446 9.01119 15.5994C7.85171 16.783 5.95232 16.8025 4.76878 15.643L2.98245 13.893C2.40646 13.3287 2.08187 12.5563 2.08187 11.75C2.08187 11.5117 2.11023 11.2763 2.16507 11.0484C1.72225 10.6445 1.3958 10.1044 1.258 9.47436L1.13648 8.91882C1.13648 8.91881 1.13648 8.9188 1.13648 8.9188C0.313576 5.15664 3.24591 1.75 6.97832 1.75H8.90365C9.04413 1.44337 9.23911 1.15538 9.48873 0.900581ZM8.90365 7.75H8.85271C8.88343 7.77715 8.91372 7.80505 8.94357 7.83367C8.92981 7.80595 8.9165 7.77805 8.90365 7.75ZM9.55635 8.66633C9.57011 8.69406 9.58342 8.72195 9.59627 8.75H9.64721C9.61649 8.72285 9.5862 8.69496 9.55635 8.66633Z' fill='%23082E44'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M11.0958 2.47515C11.3856 2.17926 11.8605 2.17438 12.1564 2.46425L13.9427 4.21425C14.0867 4.35532 14.1678 4.54842 14.1678 4.75C14.1678 4.95158 14.0867 5.14468 13.9427 5.28575L12.1564 7.03575C11.8605 7.32562 11.3856 7.32074 11.0958 7.02486C10.8059 6.72897 10.8108 6.25412 11.1067 5.96425L11.5805 5.5H6.9781C5.54192 5.5 4.50895 6.78851 4.79965 8.11751L4.79965 8.11751L4.92117 8.67308C5.00967 9.07772 4.75339 9.4775 4.34875 9.56601C3.9441 9.65452 3.54432 9.39824 3.45581 8.99359L3.33429 8.43803C3.33429 8.43803 3.33429 8.43803 3.33429 8.43802C2.83071 6.13576 4.62343 4 6.9781 4H11.5805L11.1067 3.53575C10.8108 3.24588 10.8059 2.77103 11.0958 2.47515ZM14.1507 6.93399C14.5554 6.84548 14.9552 7.10175 15.0437 7.5064L15.1652 8.06196L14.4609 8.21604L15.1652 8.06196C15.6688 10.3642 13.8761 12.5 11.5214 12.5H6.91894L7.39283 12.9643C7.68872 13.2541 7.69359 13.729 7.40372 14.0249C7.11385 14.3207 6.63901 14.3256 6.34312 14.0357L4.5568 12.2857C4.4128 12.1447 4.33165 11.9516 4.33165 11.75C4.33165 11.5484 4.4128 11.3553 4.5568 11.2143L6.34312 9.46425C6.63901 9.17438 7.11385 9.17926 7.40372 9.47515C7.69359 9.77103 7.68872 10.2459 7.39283 10.5357L6.91894 11H11.5214C12.9576 11 13.9906 9.71149 13.6998 8.38251L13.5783 7.82694C13.4898 7.42229 13.7461 7.02251 14.1507 6.93399Z' fill='white'/%3E%3C/svg%3E" );
|
||||
--unit-aircraft-status-hold-neutral-url: url( "data:image/svg+xml,%3Csvg width='17' height='17' viewBox='0 0 17 17' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8.5356 0.900581C9.69508 -0.282964 11.5945 -0.302474 12.778 0.857004L14.5643 2.607C15.1403 3.17128 15.4649 3.94367 15.4649 4.75C15.4649 4.98835 15.4366 5.22373 15.3817 5.45165C15.8245 5.85549 16.151 6.39558 16.2888 7.02558L16.4103 7.58115L16.4103 7.58116C17.2333 11.3434 14.3009 14.75 10.5685 14.75H8.64315C8.50267 15.0566 8.30769 15.3446 8.05807 15.5994C6.89859 16.783 4.99919 16.8025 3.81565 15.643L2.02933 13.893C1.45334 13.3287 1.12875 12.5563 1.12875 11.75C1.12875 11.5117 1.15711 11.2763 1.21194 11.0484C0.769126 10.6445 0.442675 10.1044 0.30487 9.47436L0.183357 8.91882C0.183355 8.91881 0.183354 8.9188 0.183352 8.9188C-0.639549 5.15664 2.29279 1.75 6.02519 1.75H7.95052C8.09101 1.44337 8.28598 1.15538 8.5356 0.900581ZM7.95052 7.75H7.89958C7.93031 7.77715 7.9606 7.80505 7.99045 7.83367C7.97668 7.80595 7.96338 7.77805 7.95052 7.75ZM8.60322 8.66633C8.61699 8.69406 8.6303 8.72195 8.64315 8.75H8.69409C8.66337 8.72285 8.63307 8.69496 8.60322 8.66633Z' fill='%232F2F2F'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10.1426 2.47515C10.4325 2.17926 10.9074 2.17438 11.2032 2.46425L12.9896 4.21425C13.1336 4.35532 13.2147 4.54842 13.2147 4.75C13.2147 4.95158 13.1336 5.14468 12.9896 5.28575L11.2032 7.03575C10.9074 7.32562 10.4325 7.32074 10.1426 7.02486C9.85276 6.72897 9.85764 6.25412 10.1535 5.96425L10.6274 5.5H6.02497C4.5888 5.5 3.55582 6.78851 3.84652 8.11751L3.84652 8.11751L3.96804 8.67308C4.05655 9.07772 3.80027 9.4775 3.39562 9.56601C2.99097 9.65452 2.59119 9.39824 2.50268 8.99359L2.38117 8.43803C2.38117 8.43803 2.38117 8.43803 2.38117 8.43802C1.87759 6.13576 3.6703 4 6.02497 4H10.6274L10.1535 3.53575C9.85764 3.24588 9.85276 2.77103 10.1426 2.47515ZM13.1976 6.93399C13.6022 6.84548 14.002 7.10175 14.0905 7.5064L14.2121 8.06196L13.5077 8.21604L14.2121 8.06196C14.7157 10.3642 12.9229 12.5 10.5683 12.5H5.96582L6.4397 12.9643C6.73559 13.2541 6.74047 13.729 6.4506 14.0249C6.16073 14.3207 5.68588 14.3256 5.38999 14.0357L3.60367 12.2857C3.45967 12.1447 3.37853 11.9516 3.37853 11.75C3.37853 11.5484 3.45967 11.3553 3.60367 11.2143L5.38999 9.46425C5.68588 9.17438 6.16073 9.17926 6.4506 9.47515C6.74047 9.77103 6.73559 10.2459 6.4397 10.5357L5.96582 11H10.5683C12.0044 11 13.0374 9.71149 12.7467 8.38251L12.6252 7.82694C12.5367 7.42229 12.7929 7.02251 13.1976 6.93399Z' fill='white'/%3E%3C/svg%3E" );
|
||||
--unit-aircraft-status-hold-red-url: url( "data:image/svg+xml,%3Csvg width='17' height='17' viewBox='0 0 17 17' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8.51217 0.900581C9.67164 -0.282964 11.571 -0.302474 12.7546 0.857004L14.5409 2.607C15.1169 3.17128 15.4415 3.94367 15.4415 4.75C15.4415 4.98835 15.4131 5.22373 15.3583 5.45165C15.8011 5.85549 16.1275 6.39558 16.2654 7.02558L16.3869 7.58115L16.3869 7.58116C17.2098 11.3434 14.2774 14.75 10.5451 14.75H8.61971C8.47923 15.0566 8.28425 15.3446 8.03463 15.5994C6.87515 16.783 4.97576 16.8025 3.79221 15.643L2.00589 13.893C1.4299 13.3287 1.10531 12.5563 1.10531 11.75C1.10531 11.5117 1.13367 11.2763 1.1885 11.0484C0.745688 10.6445 0.419237 10.1044 0.281433 9.47436L0.159919 8.91882C0.159918 8.91881 0.159916 8.9188 0.159915 8.9188C-0.662986 5.15664 2.26935 1.75 6.00175 1.75H7.92709C8.06757 1.44337 8.26255 1.15538 8.51217 0.900581ZM7.92709 7.75H7.87615C7.90687 7.77715 7.93716 7.80505 7.96701 7.83367C7.95325 7.80595 7.93994 7.77805 7.92709 7.75ZM8.57979 8.66633C8.59355 8.69406 8.60686 8.72195 8.61971 8.75H8.67065C8.63993 8.72285 8.60963 8.69496 8.57979 8.66633Z' fill='%23262222'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10.1192 2.47515C10.4091 2.17926 10.8839 2.17438 11.1798 2.46425L12.9661 4.21425C13.1101 4.35532 13.1913 4.54842 13.1913 4.75C13.1913 4.95158 13.1101 5.14468 12.9661 5.28575L11.1798 7.03575C10.8839 7.32562 10.4091 7.32074 10.1192 7.02486C9.82932 6.72897 9.8342 6.25412 10.1301 5.96425L10.604 5.5H6.00153C4.56536 5.5 3.53239 6.78851 3.82309 8.11751L3.82309 8.11751L3.9446 8.67308C4.03311 9.07772 3.77683 9.4775 3.37218 9.56601C2.96754 9.65452 2.56775 9.39824 2.47925 8.99359L2.35773 8.43803C2.35773 8.43803 2.35773 8.43803 2.35773 8.43802C1.85415 6.13576 3.64687 4 6.00153 4H10.604L10.1301 3.53575C9.8342 3.24588 9.82932 2.77103 10.1192 2.47515ZM13.1742 6.93399C13.5788 6.84548 13.9786 7.10175 14.0671 7.5064L14.1886 8.06196L13.4843 8.21604L14.1886 8.06196C14.6922 10.3642 12.8995 12.5 10.5448 12.5H5.94238L6.41627 12.9643C6.71215 13.2541 6.71703 13.729 6.42716 14.0249C6.13729 14.3207 5.66244 14.3256 5.36656 14.0357L3.58023 12.2857C3.43624 12.1447 3.35509 11.9516 3.35509 11.75C3.35509 11.5484 3.43624 11.3553 3.58023 11.2143L5.36656 9.46425C5.66244 9.17438 6.13729 9.17926 6.42716 9.47515C6.71703 9.77103 6.71215 10.2459 6.41627 10.5357L5.94238 11H10.5448C11.981 11 13.014 9.71149 12.7233 8.38251L12.6018 7.82694C12.5132 7.42229 12.7695 7.02251 13.1742 6.93399Z' fill='white'/%3E%3C/svg%3E" );
|
||||
|
||||
|
||||
/*** Ground ***/
|
||||
--unit-groundunit-marker-height: 50px;
|
||||
--unit-groundunit-marker-width: 50px;
|
||||
|
||||
295
client/routes/api/atc.js
Normal file
@@ -0,0 +1,295 @@
|
||||
var express = require('express');
|
||||
var app = express();
|
||||
|
||||
const bodyParser = require('body-parser');
|
||||
app.use(bodyParser.urlencoded({ extended: false}));
|
||||
app.use(bodyParser.json());
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Flight:
|
||||
"name"
|
||||
"take-off time"
|
||||
"priority"
|
||||
"status"
|
||||
|
||||
//*/
|
||||
|
||||
function uuidv4() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
function Flight( name, boardId, unitId ) {
|
||||
this.assignedAltitude = 0;
|
||||
this.assignedSpeed = 0;
|
||||
this.id = uuidv4();
|
||||
this.boardId = boardId;
|
||||
this.name = name;
|
||||
this.status = "unknown";
|
||||
this.takeoffTime = -1;
|
||||
this.unitId = parseInt( unitId );
|
||||
}
|
||||
|
||||
Flight.prototype.getData = function() {
|
||||
return {
|
||||
"assignedAltitude" : this.assignedAltitude,
|
||||
"assignedSpeed" : this.assignedSpeed,
|
||||
"id" : this.id,
|
||||
"boardId" : this.boardId,
|
||||
"name" : this.name,
|
||||
"status" : this.status,
|
||||
"takeoffTime" : this.takeoffTime,
|
||||
"unitId" : this.unitId
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Flight.prototype.setAssignedAltitude = function( assignedAltitude ) {
|
||||
|
||||
if ( isNaN( assignedAltitude ) ) {
|
||||
return "Altitude must be a number"
|
||||
}
|
||||
|
||||
this.assignedAltitude = parseInt( assignedAltitude );
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Flight.prototype.setAssignedSpeed = function( assignedSpeed ) {
|
||||
|
||||
if ( isNaN( assignedSpeed ) ) {
|
||||
return "Speed must be a number"
|
||||
}
|
||||
|
||||
this.assignedSpeed = parseInt( assignedSpeed );
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Flight.prototype.setOrder = function( order ) {
|
||||
|
||||
this.order = order;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Flight.prototype.setStatus = function( status ) {
|
||||
|
||||
if ( [ "unknown", "checkedin", "readytotaxi", "clearedtotaxi", "halted", "terminated" ].indexOf( status ) < 0 ) {
|
||||
return "Invalid status";
|
||||
}
|
||||
|
||||
this.status = status;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Flight.prototype.setTakeoffTime = function( takeoffTime ) {
|
||||
|
||||
if ( takeoffTime === "" || takeoffTime === -1 ) {
|
||||
this.takeoffTime = -1;
|
||||
}
|
||||
|
||||
if ( isNaN( takeoffTime ) ) {
|
||||
return "Invalid takeoff time"
|
||||
}
|
||||
|
||||
this.takeoffTime = parseInt( takeoffTime );
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function ATCDataHandler( data ) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
ATCDataHandler.prototype.addFlight = function( flight ) {
|
||||
|
||||
if ( flight instanceof Flight === false ) {
|
||||
throw new Error( "Given flight is not an instance of Flight" );
|
||||
}
|
||||
|
||||
this.data.flights[ flight.id ] = flight;
|
||||
|
||||
}
|
||||
|
||||
|
||||
ATCDataHandler.prototype.deleteFlight = function( flightId ) {
|
||||
delete this.data.flights[ flightId ];
|
||||
}
|
||||
|
||||
|
||||
ATCDataHandler.prototype.getFlight = function( flightId ) {
|
||||
return this.data.flights[ flightId ] || false;
|
||||
}
|
||||
|
||||
|
||||
ATCDataHandler.prototype.getFlights = function() {
|
||||
return this.data.flights;
|
||||
}
|
||||
|
||||
|
||||
const dataHandler = new ATCDataHandler( {
|
||||
"flights": {}
|
||||
} );
|
||||
|
||||
|
||||
|
||||
/**************************************************************************************************************/
|
||||
// Endpoints
|
||||
/**************************************************************************************************************/
|
||||
|
||||
|
||||
app.get( "/flight", ( req, res ) => {
|
||||
|
||||
let flights = Object.values( dataHandler.getFlights() );
|
||||
|
||||
if ( flights && req.query.boardId ) {
|
||||
|
||||
flights = flights.reduce( ( acc, flight ) => {
|
||||
if ( flight.boardId === req.query.boardId ) {
|
||||
acc[ flight.id ] = flight;
|
||||
}
|
||||
return acc;
|
||||
}, {} );
|
||||
|
||||
}
|
||||
|
||||
res.json( flights );
|
||||
|
||||
});
|
||||
|
||||
|
||||
app.patch( "/flight/:flightId", ( req, res ) => {
|
||||
|
||||
const flightId = req.params.flightId;
|
||||
const flight = dataHandler.getFlight( flightId );
|
||||
|
||||
if ( !flight ) {
|
||||
res.status( 400 ).send( `Unrecognised flight ID (given: "${req.params.flightId}")` );
|
||||
}
|
||||
|
||||
if ( req.body.hasOwnProperty( "assignedAltitude" ) ) {
|
||||
|
||||
const altitudeChangeSuccess = flight.setAssignedAltitude( req.body.assignedAltitude );
|
||||
|
||||
if ( altitudeChangeSuccess !== true ) {
|
||||
res.status( 400 ).send( altitudeChangeSuccess );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( req.body.hasOwnProperty( "assignedSpeed" ) ) {
|
||||
|
||||
const speedChangeSuccess = flight.setAssignedSpeed( req.body.assignedSpeed );
|
||||
|
||||
if ( speedChangeSuccess !== true ) {
|
||||
res.status( 400 ).send( speedChangeSuccess );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( req.body.status ) {
|
||||
|
||||
const statusChangeSuccess = flight.setStatus( req.body.status );
|
||||
|
||||
if ( statusChangeSuccess !== true ) {
|
||||
res.status( 400 ).send( statusChangeSuccess );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( req.body.hasOwnProperty( "takeoffTime" ) ) {
|
||||
|
||||
const takeoffChangeSuccess = flight.setTakeoffTime( req.body.takeoffTime );
|
||||
|
||||
if ( takeoffChangeSuccess !== true ) {
|
||||
res.status( 400 ).send( takeoffChangeSuccess );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
res.json( flight.getData() );
|
||||
|
||||
});
|
||||
|
||||
|
||||
app.post( "/flight/order", ( req, res ) => {
|
||||
|
||||
if ( !req.body.boardId ) {
|
||||
res.status( 400 ).send( "Invalid/missing boardId" );
|
||||
}
|
||||
|
||||
if ( !req.body.order || !Array.isArray( req.body.order ) ) {
|
||||
res.status( 400 ).send( "Invalid/missing boardId" );
|
||||
}
|
||||
|
||||
req.body.order.forEach( ( flightId, i ) => {
|
||||
|
||||
dataHandler.getFlight( flightId ).setOrder( i );
|
||||
|
||||
});
|
||||
|
||||
res.send( "" );
|
||||
|
||||
});
|
||||
|
||||
|
||||
app.post( "/flight", ( req, res ) => {
|
||||
|
||||
if ( !req.body.boardId ) {
|
||||
res.status( 400 ).send( "Invalid/missing boardId" );
|
||||
}
|
||||
|
||||
if ( !req.body.name ) {
|
||||
res.status( 400 ).send( "Invalid/missing flight name" );
|
||||
}
|
||||
|
||||
if ( !req.body.unitId || isNaN( req.body.unitId ) ) {
|
||||
res.status( 400 ).send( "Invalid/missing unitId" );
|
||||
}
|
||||
|
||||
const flight = new Flight( req.body.name, req.body.boardId, req.body.unitId );
|
||||
|
||||
dataHandler.addFlight( flight );
|
||||
|
||||
res.status( 201 );
|
||||
|
||||
res.json( flight.getData() );
|
||||
|
||||
});
|
||||
|
||||
|
||||
app.delete( "/flight/:flightId", ( req, res ) => {
|
||||
|
||||
const flight = dataHandler.getFlight( req.params.flightId );
|
||||
|
||||
if ( !flight ) {
|
||||
res.status( 400 ).send( `Unrecognised flight ID (given: "${req.params.flightId}")` );
|
||||
}
|
||||
|
||||
dataHandler.deleteFlight( req.params.flightId );
|
||||
|
||||
res.status( 204 ).send( "" );
|
||||
|
||||
});
|
||||
|
||||
|
||||
module.exports = app;
|
||||
11
client/src/@types/unit.d.ts
vendored
@@ -37,10 +37,21 @@ interface FormationData {
|
||||
}
|
||||
|
||||
interface TaskData {
|
||||
currentState: string;
|
||||
currentTask: string;
|
||||
activePath: any;
|
||||
targetSpeed: number;
|
||||
targetAltitude: number;
|
||||
isTanker: boolean;
|
||||
isAWACS: boolean;
|
||||
TACANOn: boolean;
|
||||
TACANChannel: number;
|
||||
TACANXY: string;
|
||||
TACANCallsign: string;
|
||||
radioFrequency: number;
|
||||
radioCallsign: number;
|
||||
radioCallsignNumber: number;
|
||||
radioAMFM: string;
|
||||
}
|
||||
|
||||
interface OptionsData {
|
||||
|
||||
@@ -1,86 +1,181 @@
|
||||
import { ToggleableFeature } from "../toggleablefeature";
|
||||
import Sortable from 'sortablejs';
|
||||
import { ATCFLightList } from "./flightlist";
|
||||
import { ATCBoard } from "./atcboard";
|
||||
import { ATCBoardGround } from "./board/ground";
|
||||
import { ATCBoardTower } from "./board/tower";
|
||||
|
||||
export class ATC extends ToggleableFeature {
|
||||
export interface FlightInterface {
|
||||
assignedSpeed: any;
|
||||
assignedAltitude : any;
|
||||
id : string;
|
||||
boardId : string;
|
||||
name : string;
|
||||
order : number;
|
||||
status : "unknown";
|
||||
takeoffTime : number;
|
||||
unitId : number;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
|
||||
super( true );
|
||||
|
||||
//this.#generateFlightList();
|
||||
class ATCDataHandler {
|
||||
|
||||
let $list = document.getElementById( "atc-strip-board-arrivals" );
|
||||
#atc:ATC;
|
||||
#flights:{[key:string]: FlightInterface} = {};
|
||||
|
||||
if ( $list instanceof HTMLElement ) {
|
||||
Sortable.create( $list, {
|
||||
"handle": ".handle"
|
||||
});
|
||||
}
|
||||
#updateInterval:number|undefined = undefined;
|
||||
#updateIntervalDelay:number = 2500; // Wait between unit update requests
|
||||
|
||||
|
||||
constructor( atc:ATC ) {
|
||||
|
||||
this.#atc = atc;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#generateFlightList() {
|
||||
getFlights( boardId:string ) {
|
||||
|
||||
const flightList = new ATCFLightList();
|
||||
const flights:any = flightList.getFlights( true );
|
||||
return Object.values( this.#flights ).reduce( ( acc:{[key:string]: FlightInterface}, flight ) => {
|
||||
|
||||
if ( flight.boardId === boardId ) {
|
||||
acc[ flight.id ] = flight;
|
||||
}
|
||||
|
||||
const $tbody = document.getElementById( "atc-flight-list-table-body" );
|
||||
return acc;
|
||||
}, {} );
|
||||
}
|
||||
|
||||
if ( $tbody instanceof HTMLElement ) {
|
||||
|
||||
if ( flights.length > 0 ) {
|
||||
startUpdates() {
|
||||
|
||||
this.#updateInterval = setInterval( () => {
|
||||
|
||||
let flight:any = {};
|
||||
const aBoardIsVisible = this.#atc.getBoards().some( board => board.boardIsVisible() );
|
||||
|
||||
let $button, i;
|
||||
if ( aBoardIsVisible ) {
|
||||
|
||||
fetch( '/api/atc/flight', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': '*/*',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
.then( response => response.json() )
|
||||
.then( data => {
|
||||
this.setFlights( data );
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}, this.#updateIntervalDelay );
|
||||
|
||||
for ( [ i, flight ] of flights.entries() ) {
|
||||
|
||||
const $row = document.createElement( "tr" );
|
||||
$row.dataset.status = flight.status
|
||||
|
||||
let $td = document.createElement( "td" );
|
||||
$td.innerText = flight.name;
|
||||
$row.appendChild( $td );
|
||||
|
||||
$td = document.createElement( "td" );
|
||||
$td.innerText = flight.takeOffTime;
|
||||
$row.appendChild( $td );
|
||||
|
||||
$td = document.createElement( "td" );
|
||||
$td.innerText = "00:0" + ( 5 + i );
|
||||
$row.appendChild( $td );
|
||||
|
||||
$td = document.createElement( "td" );
|
||||
$td.innerText = flight.status;
|
||||
$row.appendChild( $td );
|
||||
}
|
||||
|
||||
|
||||
setFlights( flights:{[key:string]: any} ) {
|
||||
|
||||
this.#flights = flights;
|
||||
|
||||
}
|
||||
|
||||
|
||||
stopUpdates() {
|
||||
|
||||
clearInterval( this.#updateInterval );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
export class ATC {
|
||||
|
||||
#boards:ATCBoard[] = [];
|
||||
#dataHandler:ATCDataHandler;
|
||||
|
||||
#initDate:Date = new Date();
|
||||
|
||||
constructor() {
|
||||
|
||||
this.#dataHandler = new ATCDataHandler( this );
|
||||
|
||||
this.lookForBoards();
|
||||
|
||||
}
|
||||
|
||||
|
||||
addBoard<T extends ATCBoard>( board:T ) {
|
||||
|
||||
board.startUpdates();
|
||||
|
||||
this.#boards.push( board );
|
||||
|
||||
}
|
||||
|
||||
|
||||
getBoards() {
|
||||
return this.#boards;
|
||||
}
|
||||
|
||||
|
||||
getDataHandler() {
|
||||
return this.#dataHandler;
|
||||
}
|
||||
|
||||
|
||||
getMissionElapsedSeconds() : number {
|
||||
return new Date().getTime() - this.#initDate.getTime();
|
||||
}
|
||||
|
||||
|
||||
getMissionStartDateTime() : Date {
|
||||
return new Date( 1990, 3, 1, 18, 0, 0 );
|
||||
}
|
||||
|
||||
|
||||
getMissionDateTime() : Date {
|
||||
return new Date( this.getMissionStartDateTime().getTime() + this.getMissionElapsedSeconds() );
|
||||
}
|
||||
|
||||
|
||||
lookForBoards() {
|
||||
|
||||
document.querySelectorAll( ".ol-strip-board" ).forEach( board => {
|
||||
|
||||
if ( board instanceof HTMLElement ) {
|
||||
|
||||
switch ( board.dataset.boardType ) {
|
||||
|
||||
case "ground":
|
||||
this.addBoard( new ATCBoardGround( this, board ) );
|
||||
return;
|
||||
|
||||
$td = document.createElement( "td" );
|
||||
$button = document.createElement( "button" );
|
||||
$button.innerText = "...";
|
||||
case "tower":
|
||||
this.addBoard( new ATCBoardTower( this, board ) );
|
||||
return;
|
||||
|
||||
default:
|
||||
console.warn( "Unknown board type for ATC board, got: " + board.dataset.boardType );
|
||||
|
||||
$td.appendChild( $button );
|
||||
|
||||
$row.appendChild( $td );
|
||||
|
||||
|
||||
$tbody.appendChild( $row );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
startUpdates() {
|
||||
|
||||
this.#dataHandler.startUpdates();
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected onStatusUpdate(): void {
|
||||
|
||||
document.body.classList.toggle( "atc-enabled", this.getStatus() );
|
||||
stopUpdates() {
|
||||
|
||||
this.#dataHandler.stopUpdates();
|
||||
|
||||
}
|
||||
|
||||
|
||||
514
client/src/atc/atcboard.ts
Normal file
@@ -0,0 +1,514 @@
|
||||
import { Dropdown } from "../controls/dropdown";
|
||||
import { zeroAppend } from "../other/utils";
|
||||
import { ATC } from "./atc";
|
||||
import { Unit } from "../units/unit";
|
||||
import { getUnitsManager } from "..";
|
||||
import Sortable from "sortablejs";
|
||||
import { FlightInterface } from "./atc";
|
||||
|
||||
export interface StripBoardStripInterface {
|
||||
"id": string,
|
||||
"element": HTMLElement,
|
||||
"dropdowns": {[key:string]: Dropdown},
|
||||
"isDeleted"?: boolean,
|
||||
"unitId": number
|
||||
}
|
||||
|
||||
export abstract class ATCBoard {
|
||||
|
||||
#atc:ATC;
|
||||
#boardId:string = "";
|
||||
#templates: {[key:string]: string} = {};
|
||||
|
||||
|
||||
// Elements
|
||||
#boardElement:HTMLElement;
|
||||
#clockElement:HTMLElement;
|
||||
#stripBoardElement:HTMLElement;
|
||||
|
||||
// Content
|
||||
#isAddFlightByClickEnabled:boolean = false;
|
||||
#strips:{[key:string]: StripBoardStripInterface} = {};
|
||||
#unitIdsBeingMonitored:number[] = [];
|
||||
|
||||
// Update timing
|
||||
#updateInterval:number|undefined = undefined;
|
||||
#updateIntervalDelay:number = 1000;
|
||||
|
||||
|
||||
constructor( atc:ATC, boardElement:HTMLElement, options?:{[key:string]: any} ) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
this.#atc = atc;
|
||||
this.#boardElement = boardElement;
|
||||
this.#stripBoardElement = <HTMLElement>this.getBoardElement().querySelector( ".ol-strip-board-strips" );
|
||||
this.#clockElement = <HTMLElement>this.getBoardElement().querySelector( ".ol-strip-board-clock" );
|
||||
|
||||
|
||||
new MutationObserver( () => {
|
||||
if ( this.boardIsVisible() ) {
|
||||
this.startUpdates();
|
||||
} else {
|
||||
this.stopUpdates();
|
||||
}
|
||||
}).observe( this.getBoardElement(), {
|
||||
"attributes": true,
|
||||
"childList": false,
|
||||
"subtree": false
|
||||
});
|
||||
|
||||
|
||||
new Sortable( this.getStripBoardElement(), {
|
||||
"handle": ".handle",
|
||||
"onUpdate": ev => {
|
||||
|
||||
const order = [].slice.call( this.getStripBoardElement().children ).map( ( strip:HTMLElement ) => {
|
||||
return strip.dataset.flightId
|
||||
});
|
||||
|
||||
fetch( '/api/atc/flight/order', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': '*/*',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
"body": JSON.stringify({
|
||||
"boardId" : this.getBoardId(),
|
||||
"order" : order
|
||||
})
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
setInterval( () => {
|
||||
this.updateClock();
|
||||
}, 1000 );
|
||||
|
||||
|
||||
if ( this.#boardElement.classList.contains( "ol-draggable" ) ) {
|
||||
|
||||
let options:any = {};
|
||||
|
||||
let handle = this.#boardElement.querySelector( ".handle" );
|
||||
|
||||
if ( handle instanceof HTMLElement ) {
|
||||
options.handle = handle;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
this.#setupAddFlight();
|
||||
|
||||
// this.#_setupDemoData();
|
||||
|
||||
}
|
||||
|
||||
|
||||
addFlight( unit:Unit ) {
|
||||
|
||||
const baseData = unit.getBaseData();
|
||||
|
||||
const unitCanBeAdded = () => {
|
||||
|
||||
if ( baseData.category !== "Aircraft" ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( baseData.AI === true ) {
|
||||
// return false;
|
||||
}
|
||||
|
||||
if ( this.#unitIdsBeingMonitored.includes( unit.ID ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( !unitCanBeAdded() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.#unitIdsBeingMonitored.push( unit.ID );
|
||||
|
||||
return fetch( '/api/atc/flight/', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': '*/*',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
"body": JSON.stringify({
|
||||
"boardId" : this.getBoardId(),
|
||||
"name" : baseData.unitName,
|
||||
"unitId" : unit.ID
|
||||
})
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
addStrip( strip:StripBoardStripInterface ) {
|
||||
|
||||
this.#strips[ strip.id ] = strip;
|
||||
|
||||
strip.element.querySelectorAll( "button.deleteFlight" ).forEach( btn => {
|
||||
btn.addEventListener( "click", ev => {
|
||||
ev.preventDefault();
|
||||
this.deleteFlight( strip.id );
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
boardIsVisible() {
|
||||
return ( !this.getBoardElement().classList.contains( "hide" ) );
|
||||
}
|
||||
|
||||
|
||||
calculateTimeToGo( fromTimestamp:number, toTimestamp:number ) {
|
||||
|
||||
let timestamp = ( toTimestamp - fromTimestamp ) / 1000;
|
||||
|
||||
const hasElapsed = ( timestamp < 0 ) ? true : false;
|
||||
|
||||
if ( hasElapsed ) {
|
||||
timestamp = -( timestamp );
|
||||
}
|
||||
|
||||
const hours = ( timestamp < 3600 ) ? "00" : zeroAppend( Math.floor( timestamp / 3600 ), 2 );
|
||||
const rMinutes = timestamp % 3600;
|
||||
|
||||
const minutes = ( timestamp < 60 ) ? "00" : zeroAppend( Math.floor( rMinutes / 60 ), 2 );
|
||||
const seconds = zeroAppend( Math.floor( rMinutes % 60 ), 2 );
|
||||
|
||||
return {
|
||||
"elapsedMarker": ( hasElapsed ) ? "+" : "-",
|
||||
"hasElapsed": hasElapsed,
|
||||
"hours": hours,
|
||||
"minutes": minutes,
|
||||
"seconds": seconds,
|
||||
"time": `${hours}:${minutes}:${seconds}`,
|
||||
"totalSeconds": timestamp
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
deleteStrip( flightId:string ) {
|
||||
|
||||
if ( this.#strips.hasOwnProperty( flightId ) ) {
|
||||
|
||||
this.#strips[ flightId ].element.remove();
|
||||
this.#strips[ flightId ].isDeleted = true;
|
||||
|
||||
setTimeout( () => {
|
||||
delete this.#strips[ flightId ];
|
||||
}, 10000 );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
deleteFlight( flightId:string ) {
|
||||
|
||||
this.deleteStrip( flightId );
|
||||
|
||||
fetch( '/api/atc/flight/' + flightId, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Accept': '*/*',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
"body": JSON.stringify({
|
||||
"boardId": this.getBoardId()
|
||||
})
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
getATC() {
|
||||
return this.#atc;
|
||||
}
|
||||
|
||||
|
||||
getBoardElement() {
|
||||
return this.#boardElement;
|
||||
}
|
||||
|
||||
|
||||
getBoardId(): string {
|
||||
return this.getBoardElement().id;
|
||||
}
|
||||
|
||||
|
||||
getStripBoardElement() {
|
||||
return this.#stripBoardElement;
|
||||
}
|
||||
|
||||
|
||||
getStrips() {
|
||||
return this.#strips;
|
||||
}
|
||||
|
||||
|
||||
getStrip( id:string ) {
|
||||
return this.#strips[ id ] || false;
|
||||
}
|
||||
|
||||
|
||||
getTemplate( key:string ) {
|
||||
|
||||
return this.#templates[ key ] || false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
getUnitIdsBeingMonitored() {
|
||||
|
||||
return this.#unitIdsBeingMonitored;
|
||||
|
||||
}
|
||||
|
||||
|
||||
setTemplates( templates:{[key:string]: string} ) {
|
||||
this.#templates = templates;
|
||||
}
|
||||
|
||||
|
||||
#setupAddFlight() {
|
||||
|
||||
const toggleIsAddFlightByClickEnabled = () => {
|
||||
this.#isAddFlightByClickEnabled = ( !this.#isAddFlightByClickEnabled );
|
||||
this.getBoardElement().classList.toggle( "add-flight-by-click", this.#isAddFlightByClickEnabled );
|
||||
}
|
||||
|
||||
|
||||
document.addEventListener( "unitSelection", ( ev:CustomEventInit ) => {
|
||||
|
||||
if ( this.#isAddFlightByClickEnabled !== true ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.addFlight( ev.detail );
|
||||
|
||||
toggleIsAddFlightByClickEnabled();
|
||||
|
||||
});
|
||||
|
||||
|
||||
const form = <HTMLElement>this.getBoardElement().querySelector( "form.ol-strip-board-add-flight" );
|
||||
const suggestions = <HTMLElement>form.querySelector( ".ol-auto-suggest" );
|
||||
const unitName = <HTMLInputElement>form.querySelector( "input[name='unitName']" );
|
||||
|
||||
const toggleSuggestions = ( bool:boolean ) => {
|
||||
suggestions.toggleAttribute( "data-has-suggestions", bool );
|
||||
}
|
||||
|
||||
let searchTimeout:number|null;
|
||||
|
||||
unitName.addEventListener( "keyup", ev => {
|
||||
|
||||
if ( searchTimeout ) {
|
||||
clearTimeout( searchTimeout );
|
||||
}
|
||||
|
||||
const resetSuggestions = () => {
|
||||
suggestions.innerHTML = "";
|
||||
toggleSuggestions( false );
|
||||
}
|
||||
|
||||
resetSuggestions();
|
||||
|
||||
searchTimeout = setTimeout( () => {
|
||||
|
||||
const searchString = unitName.value.toLowerCase();
|
||||
|
||||
if ( searchString === "" ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const units = getUnitsManager().getSelectableAircraft();
|
||||
const unitIdsBeingMonitored = this.getUnitIdsBeingMonitored();
|
||||
|
||||
const results = Object.keys( units ).reduce( ( acc:Unit[], unitId:any ) => {
|
||||
|
||||
const unit = units[ unitId ];
|
||||
const baseData = unit.getBaseData();
|
||||
|
||||
if ( !unitIdsBeingMonitored.includes( parseInt( unitId ) ) && baseData.unitName.toLowerCase().indexOf( searchString ) > -1 ) {
|
||||
acc.push( unit );
|
||||
}
|
||||
|
||||
return acc;
|
||||
|
||||
}, [] );
|
||||
|
||||
toggleSuggestions( results.length > 0 );
|
||||
|
||||
results.forEach( unit => {
|
||||
|
||||
const baseData = unit.getBaseData();
|
||||
|
||||
const a = document.createElement( "a" );
|
||||
a.innerText = baseData.unitName;
|
||||
|
||||
a.addEventListener( "click", ev => {
|
||||
this.addFlight( unit );
|
||||
resetSuggestions();
|
||||
unitName.value = "";
|
||||
});
|
||||
|
||||
suggestions.appendChild( a );
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
}, 1000 );
|
||||
|
||||
|
||||
});
|
||||
|
||||
form.querySelectorAll( ".add-flight-by-click" ).forEach( el => {
|
||||
el.addEventListener( "click", ev => {
|
||||
ev.preventDefault();
|
||||
toggleIsAddFlightByClickEnabled();
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
sortFlights( flights:FlightInterface[] ) {
|
||||
|
||||
flights.sort( ( a, b ) => {
|
||||
|
||||
const aVal = a.order;
|
||||
const bVal = b.order;
|
||||
|
||||
return ( aVal > bVal ) ? 1 : -1;
|
||||
|
||||
});
|
||||
|
||||
return flights;
|
||||
|
||||
}
|
||||
|
||||
|
||||
startUpdates() {
|
||||
|
||||
if ( !this.boardIsVisible() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.#updateInterval = setInterval( () => {
|
||||
|
||||
this.update();
|
||||
|
||||
}, this.#updateIntervalDelay );
|
||||
|
||||
}
|
||||
|
||||
|
||||
stopUpdates() {
|
||||
|
||||
clearInterval( this.#updateInterval );
|
||||
|
||||
}
|
||||
|
||||
|
||||
timestampToLocaleTime( timestamp:number ) {
|
||||
|
||||
return ( timestamp === -1 ) ? "-" : new Date( timestamp ).toLocaleTimeString();
|
||||
|
||||
}
|
||||
|
||||
|
||||
timeToGo( timestamp:number ) {
|
||||
|
||||
const timeData = this.calculateTimeToGo( this.getATC().getMissionDateTime().getTime(), timestamp );
|
||||
|
||||
return ( timestamp === -1 ) ? "-" : timeData.elapsedMarker + timeData.time;
|
||||
|
||||
}
|
||||
|
||||
protected update() {
|
||||
console.warn( "No custom update method defined." );
|
||||
}
|
||||
|
||||
|
||||
updateClock() {
|
||||
|
||||
const now = this.#atc.getMissionDateTime();
|
||||
this.#clockElement.innerText = now.toLocaleTimeString();
|
||||
|
||||
}
|
||||
|
||||
|
||||
updateFlight( flightId:string, reqBody:object ) {
|
||||
|
||||
return fetch( '/api/atc/flight/' + flightId, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Accept': '*/*',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
"body": JSON.stringify( reqBody )
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
#_setupDemoData() {
|
||||
|
||||
fetch( '/api/atc/flight/', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': '*/*',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
"body": JSON.stringify({
|
||||
"boardId" : this.getBoardId(),
|
||||
"name" : this.getBoardId() + " 1",
|
||||
"unitId" : 1
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
// fetch( '/api/atc/flight/', {
|
||||
// method: 'POST',
|
||||
// headers: {
|
||||
// 'Accept': '*/*',
|
||||
// 'Content-Type': 'application/json'
|
||||
// },
|
||||
// "body": JSON.stringify({
|
||||
// "boardId" : this.getBoardId(),
|
||||
// "name" : this.getBoardId() + " 2",
|
||||
// "unitId" : 2
|
||||
// })
|
||||
// });
|
||||
|
||||
// fetch( '/api/atc/flight/', {
|
||||
// method: 'POST',
|
||||
// headers: {
|
||||
// 'Accept': '*/*',
|
||||
// 'Content-Type': 'application/json'
|
||||
// },
|
||||
// "body": JSON.stringify({
|
||||
// "boardId" : this.getBoardId(),
|
||||
// "name" : this.getBoardId() + " 3",
|
||||
// "unitId" : 9
|
||||
// })
|
||||
// });
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
export abstract class ATCMockAPI {
|
||||
|
||||
constructor() {}
|
||||
|
||||
generateMockData() {}
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
import { ATCMockAPI } from "../atcmockapi";
|
||||
|
||||
export class ATCMockAPI_Flights extends ATCMockAPI {
|
||||
|
||||
|
||||
generateMockData() {
|
||||
|
||||
let data = [];
|
||||
const statuses = [ "unknown", "checkedIn", "readyToTaxi" ]
|
||||
|
||||
for ( const [ i, flightName ] of [ "Shark", "Whale", "Dolphin" ].entries() ) {
|
||||
|
||||
data.push({
|
||||
"name": flightName,
|
||||
"status": statuses[ i ],
|
||||
"takeOffTime": "18:0" + i
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
localStorage.setItem( "flightList", JSON.stringify( data ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
get( generateMockDataIfEmpty?:boolean ) : object {
|
||||
|
||||
generateMockDataIfEmpty = generateMockDataIfEmpty || false;
|
||||
|
||||
let data = localStorage.getItem( "flightList" ) || "[]";
|
||||
|
||||
if ( data === "[]" && generateMockDataIfEmpty ) {
|
||||
this.generateMockData();
|
||||
}
|
||||
|
||||
return JSON.parse( data );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
200
client/src/atc/board/ground.ts
Normal file
@@ -0,0 +1,200 @@
|
||||
import { Dropdown } from "../../controls/dropdown";
|
||||
import { ATC } from "../atc";
|
||||
import { ATCBoard } from "../atcboard";
|
||||
|
||||
|
||||
export class ATCBoardGround extends ATCBoard {
|
||||
|
||||
constructor( atc:ATC, element:HTMLElement ) {
|
||||
|
||||
super( atc, element );
|
||||
|
||||
}
|
||||
|
||||
|
||||
update() {
|
||||
|
||||
const flights = this.sortFlights( Object.values( this.getATC().getDataHandler().getFlights( this.getBoardId() ) ) );
|
||||
const stripBoard = this.getStripBoardElement();
|
||||
|
||||
const missionTime = this.getATC().getMissionDateTime().getTime();
|
||||
|
||||
for( const strip of stripBoard.children ) {
|
||||
strip.toggleAttribute( "data-updating", true );
|
||||
}
|
||||
|
||||
|
||||
flights.forEach( flight => {
|
||||
|
||||
let strip = this.getStrip( flight.id );
|
||||
|
||||
if ( !strip ) {
|
||||
|
||||
const template = `<div class="ol-strip-board-strip" data-flight-id="${flight.id}" data-flight-status="${flight.status}">
|
||||
<div class="handle"></div>
|
||||
<div data-point="name">${flight.name}</div>
|
||||
|
||||
<div id="flight-status-${flight.id}" class="ol-select narrow" data-point="status">
|
||||
<div class="ol-select-value">${flight.status}</div>
|
||||
<div class="ol-select-options"></div>
|
||||
</div>
|
||||
|
||||
<div data-point="takeoffTime"><input type="text" name="takeoffTime" value="${this.timestampToLocaleTime( flight.takeoffTime )}" /></div>
|
||||
|
||||
<div data-point="timeToGo">${this.timeToGo( flight.takeoffTime )}</div>
|
||||
|
||||
<button class="deleteFlight">×</button>
|
||||
</div>`;
|
||||
|
||||
stripBoard.insertAdjacentHTML( "beforeend", template );
|
||||
|
||||
|
||||
strip = {
|
||||
"id": flight.id,
|
||||
"element": <HTMLElement>stripBoard.lastElementChild,
|
||||
"dropdowns": {},
|
||||
"unitId": -1
|
||||
};
|
||||
|
||||
strip.element.querySelectorAll( ".ol-select" ).forEach( select => {
|
||||
|
||||
switch( select.getAttribute( "data-point" ) ) {
|
||||
|
||||
case "status":
|
||||
|
||||
strip.dropdowns.status = new Dropdown( select.id, ( value:string, ev:MouseEvent ) => {
|
||||
|
||||
fetch( '/api/atc/flight/' + flight.id, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Accept': '*/*',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
"body": JSON.stringify({
|
||||
"status": value
|
||||
})
|
||||
});
|
||||
|
||||
}, [
|
||||
"unknown", "checkedin", "readytotaxi", "clearedtotaxi", "halted", "terminated"
|
||||
]);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
strip.element.querySelectorAll( `input[type="text"]` ).forEach( input => {
|
||||
|
||||
if ( input instanceof HTMLInputElement ) {
|
||||
|
||||
input.addEventListener( "blur", ( ev ) => {
|
||||
|
||||
const target = ev.target;
|
||||
|
||||
if ( target instanceof HTMLInputElement ) {
|
||||
|
||||
if ( /^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$/.test( target.value ) ) {
|
||||
target.value += ":00";
|
||||
}
|
||||
|
||||
const value = target.value;
|
||||
|
||||
if ( value === target.dataset.previousValue ) {
|
||||
return;
|
||||
|
||||
} else if ( value === "" ) {
|
||||
|
||||
this.#updateTakeoffTime( flight.id, -1 );
|
||||
|
||||
} else if ( /^([0-1]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/.test( value ) ) {
|
||||
|
||||
let [ hours, minutes, seconds ] = value.split( ":" ).map( str => parseInt( str ) );
|
||||
|
||||
const missionStart = this.getATC().getMissionStartDateTime();
|
||||
|
||||
this.#updateTakeoffTime( flight.id, new Date(
|
||||
missionStart.getFullYear(),
|
||||
missionStart.getMonth(),
|
||||
missionStart.getDate(),
|
||||
hours,
|
||||
minutes,
|
||||
seconds
|
||||
).getTime() );
|
||||
|
||||
} else {
|
||||
|
||||
target.value === target.dataset.previousValue
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
this.addStrip( strip );
|
||||
|
||||
} else {
|
||||
|
||||
if ( flight.status !== strip.element.getAttribute( "data-flight-status" ) ) {
|
||||
strip.element.setAttribute( "data-flight-status", flight.status );
|
||||
strip.dropdowns.status.selectText( flight.status );
|
||||
}
|
||||
|
||||
strip.element.querySelectorAll( `input[name="takeoffTime"]:not(:focus)` ).forEach( el => {
|
||||
if ( el instanceof HTMLInputElement ) {
|
||||
el.value = this.timestampToLocaleTime( flight.takeoffTime );
|
||||
el.dataset.previousValue = el.value;
|
||||
}
|
||||
});
|
||||
|
||||
strip.element.querySelectorAll( `[data-point="timeToGo"]` ).forEach( el => {
|
||||
|
||||
if ( flight.takeoffTime > 0 && this.calculateTimeToGo( missionTime, flight.takeoffTime ).totalSeconds <= 120 ) {
|
||||
strip.element.setAttribute( "data-time-warning", "level-1" );
|
||||
}
|
||||
|
||||
if ( el instanceof HTMLElement ) {
|
||||
el.innerText = this.timeToGo( flight.takeoffTime );
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
strip.element.toggleAttribute( "data-updating", false );
|
||||
|
||||
});
|
||||
|
||||
|
||||
stripBoard.querySelectorAll( `[data-updating]` ).forEach( strip => {
|
||||
this.deleteStrip( strip.getAttribute( "data-flight-id" ) || "" );
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#updateTakeoffTime = function( flightId:string, time:number ) {
|
||||
|
||||
fetch( '/api/atc/flight/' + flightId, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Accept': '*/*',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
"body": JSON.stringify({
|
||||
"takeoffTime": time
|
||||
})
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
193
client/src/atc/board/tower.ts
Normal file
@@ -0,0 +1,193 @@
|
||||
import { getUnitsManager } from "../..";
|
||||
import { Dropdown } from "../../controls/dropdown";
|
||||
import { ATC } from "../atc";
|
||||
import { ATCBoard } from "../atcboard";
|
||||
|
||||
|
||||
export class ATCBoardTower extends ATCBoard {
|
||||
|
||||
constructor( atc:ATC, element:HTMLElement ) {
|
||||
|
||||
super( atc, element );
|
||||
|
||||
}
|
||||
|
||||
|
||||
update() {
|
||||
|
||||
const flights = this.sortFlights( Object.values( this.getATC().getDataHandler().getFlights( this.getBoardId() ) ) );
|
||||
const missionTime = this.getATC().getMissionDateTime().getTime();
|
||||
const selectableUnits = getUnitsManager().getSelectableAircraft();
|
||||
const stripBoard = this.getStripBoardElement();
|
||||
|
||||
for( const strip of stripBoard.children ) {
|
||||
strip.toggleAttribute( "data-updating", true );
|
||||
}
|
||||
|
||||
|
||||
flights.forEach( flight => {
|
||||
|
||||
let strip = this.getStrip( flight.id );
|
||||
|
||||
if ( strip.isDeleted === true ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const flightData:FlightData = {
|
||||
latitude: -1,
|
||||
longitude: -1,
|
||||
altitude: -1,
|
||||
heading: -1,
|
||||
speed: -1,
|
||||
...( selectableUnits.hasOwnProperty( flight.unitId ) ? selectableUnits[flight.unitId].getFlightData() : {} )
|
||||
};
|
||||
|
||||
if ( !strip ) {
|
||||
|
||||
const template = `<div class="ol-strip-board-strip" data-flight-id="${flight.id}" data-flight-status="${flight.status}">
|
||||
<div class="handle"></div>
|
||||
<div data-point="name"><a href="#" class="select-unit">${flight.name}</a></div>
|
||||
|
||||
<div data-point="assignedAltitude"><input type="text" name="assignedAltitude" value="${flight.assignedAltitude}" size="2" /> 000</div>
|
||||
<div data-point="altitude">-</div>
|
||||
|
||||
<div data-point="assignedSpeed"><input type="text" name="assignedSpeed" value="${flight.assignedSpeed}" size="3" /></div>
|
||||
<div data-point="speed">-</div>
|
||||
|
||||
<button class="deleteFlight">×</button>
|
||||
</div>`;
|
||||
|
||||
stripBoard.insertAdjacentHTML( "beforeend", template );
|
||||
|
||||
|
||||
strip = {
|
||||
"id": flight.id,
|
||||
"element": <HTMLElement>stripBoard.lastElementChild,
|
||||
"dropdowns": {},
|
||||
"unitId": flight.unitId
|
||||
};
|
||||
|
||||
|
||||
strip.element.querySelectorAll( `input[type="text"]` ).forEach( input => {
|
||||
|
||||
if ( input instanceof HTMLInputElement ) {
|
||||
|
||||
switch ( input.name ) {
|
||||
|
||||
case "assignedAltitude":
|
||||
|
||||
input.addEventListener( "change", ( ev ) => {
|
||||
|
||||
let val = parseInt( input.value.replace( /[^\d]/g, "" ) );
|
||||
|
||||
if ( isNaN( val ) || val < 0 || val > 40 ) {
|
||||
val = 0;
|
||||
}
|
||||
|
||||
this.updateFlight( flight.id, {
|
||||
"assignedAltitude": val
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
break;
|
||||
|
||||
case "assignedSpeed":
|
||||
|
||||
input.addEventListener( "change", ( ev ) => {
|
||||
|
||||
let val = parseInt( input.value.replace( /[^\d]/g, "" ) );
|
||||
|
||||
if ( isNaN( val ) || val < 0 || val > 750 ) {
|
||||
val = 0;
|
||||
}
|
||||
|
||||
this.updateFlight( flight.id, {
|
||||
"assignedSpeed": val
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
strip.element.querySelectorAll( ".select-unit" ).forEach( el => {
|
||||
|
||||
el.addEventListener( "click", ev => {
|
||||
ev.preventDefault();
|
||||
getUnitsManager().selectUnit( flight.unitId );
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
this.addStrip( strip );
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// Altitude
|
||||
//
|
||||
|
||||
let assignedAltitude = <HTMLInputElement>strip.element.querySelector( `input[name="assignedAltitude"]`);
|
||||
|
||||
if ( !assignedAltitude.matches( ":focus" ) && assignedAltitude.value !== flight.assignedAltitude ) {
|
||||
assignedAltitude.value = flight.assignedAltitude;
|
||||
}
|
||||
|
||||
flightData.altitude = Math.floor( flightData.altitude / 0.3048 );
|
||||
|
||||
strip.element.querySelectorAll( `[data-point="altitude"]` ).forEach( el => {
|
||||
if ( el instanceof HTMLElement ) {
|
||||
el.innerText = "" + flightData.altitude;
|
||||
}
|
||||
});
|
||||
|
||||
const altitudeDelta = ( flight.assignedAltitude === 0 ) ? 0 : ( flight.assignedAltitude * 1000 ) - flightData.altitude;
|
||||
|
||||
strip.element.toggleAttribute( "data-altitude-assigned", ( flight.assignedAltitude > 0 ) );
|
||||
strip.element.toggleAttribute( "data-warning-altitude", ( altitudeDelta >= 300 || altitudeDelta <= -300 ) );
|
||||
|
||||
|
||||
//
|
||||
// Speed
|
||||
//
|
||||
|
||||
let assignedSpeed = <HTMLInputElement>strip.element.querySelector( `input[name="assignedSpeed"]`);
|
||||
|
||||
if ( !assignedSpeed.matches( ":focus" ) && assignedSpeed.value !== flight.assignedSpeed ) {
|
||||
assignedSpeed.value = flight.assignedSpeed;
|
||||
}
|
||||
|
||||
flightData.speed = Math.floor( flightData.speed * 1.94384 );
|
||||
|
||||
strip.element.querySelectorAll( `[data-point="speed"]` ).forEach( el => {
|
||||
if ( el instanceof HTMLElement ) {
|
||||
el.innerText = "" + flightData.speed;
|
||||
}
|
||||
});
|
||||
|
||||
const speedDelta = ( flight.assignedSpeed === 0 ) ? 0 : flight.assignedSpeed - flightData.speed;
|
||||
|
||||
strip.element.toggleAttribute( "data-speed-assigned", ( flight.assignedSpeed > 0 ) );
|
||||
strip.element.toggleAttribute( "data-warning-speed", ( speedDelta >= 25 || speedDelta <= -25 ) );
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
strip.element.toggleAttribute( "data-updating", false );
|
||||
|
||||
});
|
||||
|
||||
stripBoard.querySelectorAll( `[data-updating]` ).forEach( strip => {
|
||||
this.deleteStrip( strip.getAttribute( "data-flight-id" ) || "" );
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import { ATCMockAPI_Flights } from "./atcmockapi/flights";
|
||||
|
||||
export class ATCFLightList {
|
||||
|
||||
|
||||
constructor() {
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
getFlights( generateMockDataIfEmpty?:boolean ) {
|
||||
let api = new ATCMockAPI_Flights();
|
||||
return api.get( generateMockDataIfEmpty );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,46 +5,119 @@ export class Dropdown {
|
||||
#callback: CallableFunction;
|
||||
#defaultValue: string;
|
||||
#optionsList: string[] = [];
|
||||
|
||||
#index: number = 0;
|
||||
|
||||
constructor(ID: string, callback: CallableFunction, options: string[] | null = null)
|
||||
{
|
||||
this.#element = <HTMLElement>document.getElementById(ID);
|
||||
this.#options = <HTMLElement>this.#element.querySelector(".ol-select-options");
|
||||
this.#value = <HTMLElement>this.#element.querySelector(".ol-select-value");
|
||||
this.#element = <HTMLElement>document.getElementById(ID);
|
||||
this.#options = <HTMLElement>this.#element.querySelector(".ol-select-options");
|
||||
this.#value = <HTMLElement>this.#element.querySelector(".ol-select-value");
|
||||
this.#defaultValue = this.#value.innerText;
|
||||
this.#callback = callback;
|
||||
if (options != null)
|
||||
this.#callback = callback;
|
||||
|
||||
if (options != null) {
|
||||
this.setOptions(options);
|
||||
}
|
||||
|
||||
this.#value.addEventListener( "click", ev => {
|
||||
this.#element.classList.toggle( "is-open" );
|
||||
this.#clip();
|
||||
});
|
||||
|
||||
this.#options.classList.add( "ol-scrollable" );
|
||||
|
||||
// Commented out since it is a bit frustrating, particularly when the dropdown opens towards the top and not to the bottom
|
||||
//this.#element.addEventListener("mouseleave", ev => {
|
||||
// this.#close();
|
||||
//});
|
||||
}
|
||||
|
||||
setOptions(optionsList: string[])
|
||||
{
|
||||
this.#optionsList = optionsList;
|
||||
this.#options.replaceChildren(...optionsList.map((option: string) => {
|
||||
this.#options.replaceChildren(...optionsList.map((option: string, idx: number) => {
|
||||
var div = document.createElement("div");
|
||||
var button = document.createElement("button");
|
||||
button.textContent = option;
|
||||
div.appendChild(button);
|
||||
|
||||
if (option === this.#defaultValue)
|
||||
this.#index = idx;
|
||||
|
||||
button.addEventListener("click", (e: MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
this.#value.innerText = option;
|
||||
this.#callback(option);
|
||||
this.#close();
|
||||
this.#callback(option, e);
|
||||
this.#index = idx;
|
||||
});
|
||||
return div;
|
||||
}));
|
||||
}
|
||||
|
||||
selectText( text:string ) {
|
||||
|
||||
const index = [].slice.call( this.#options.children ).findIndex( ( opt:Element ) => opt.querySelector( "button" )?.innerText === text );
|
||||
if ( index > -1 ) {
|
||||
this.selectValue( index );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
selectValue(idx: number)
|
||||
{
|
||||
if (idx < this.#optionsList.length)
|
||||
{
|
||||
var option = this.#optionsList[idx];
|
||||
this.#value.innerText = option;
|
||||
this.#index = idx;
|
||||
this.#close();
|
||||
this.#callback(option);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.#options.replaceChildren();
|
||||
this.#value.innerText = this.#defaultValue;
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return this.#value.innerText;
|
||||
}
|
||||
|
||||
setValue(value: string) {
|
||||
var index = this.#optionsList.findIndex((option) => {return option === value});
|
||||
if (index > -1)
|
||||
this.selectValue(index);
|
||||
}
|
||||
|
||||
getIndex() {
|
||||
return this.#index;
|
||||
}
|
||||
|
||||
#clip() {
|
||||
const options = this.#options;
|
||||
const bounds = options.getBoundingClientRect();
|
||||
this.#element.dataset.position = ( bounds.bottom > window.innerHeight ) ? "top" : "";
|
||||
}
|
||||
|
||||
#close() {
|
||||
this.#element.classList.remove( "is-open" );
|
||||
this.#element.dataset.position = "";
|
||||
}
|
||||
|
||||
#open() {
|
||||
this.#element.classList.add( "is-open" );
|
||||
}
|
||||
|
||||
#toggle() {
|
||||
if ( this.#element.classList.contains( "is-open" ) ) {
|
||||
this.#close();
|
||||
} else {
|
||||
this.#open();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -168,8 +168,12 @@ export class MapContextMenu extends ContextMenu {
|
||||
/********* Ground unit spawn menu *********/
|
||||
#setGroundUnitRole(role: string) {
|
||||
this.#spawnOptions.role = role;
|
||||
this.#resetGroundUnitRole();
|
||||
this.#groundUnitTypeDropdown.setOptions(groundUnitsDatabase.getByRole(role).map((blueprint) => { return blueprint.label }));
|
||||
this.#resetGroundUnitType();
|
||||
|
||||
const types = groundUnitsDatabase.getByRole(role).map((blueprint) => { return blueprint.label } );
|
||||
types.sort();
|
||||
|
||||
this.#groundUnitTypeDropdown.setOptions( types );
|
||||
this.#groundUnitTypeDropdown.selectValue(0);
|
||||
this.clip();
|
||||
}
|
||||
@@ -179,7 +183,11 @@ export class MapContextMenu extends ContextMenu {
|
||||
(<HTMLButtonElement>this.getContainer()?.querySelector("#loadout-list")).replaceChildren();
|
||||
this.#groundUnitRoleDropdown.reset();
|
||||
this.#groundUnitTypeDropdown.reset();
|
||||
this.#groundUnitRoleDropdown.setOptions(groundUnitsDatabase.getRoles());
|
||||
|
||||
const roles = groundUnitsDatabase.getRoles();
|
||||
roles.sort();
|
||||
|
||||
this.#groundUnitRoleDropdown.setOptions( roles );
|
||||
this.clip();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,54 @@
|
||||
import { getUnitsManager } from "..";
|
||||
import { deg2rad } from "../other/utils";
|
||||
import { ContextMenu } from "./contextmenu";
|
||||
|
||||
export class UnitContextMenu extends ContextMenu {
|
||||
#customFormationCallback: CallableFunction | null = null;
|
||||
|
||||
constructor(id: string) {
|
||||
super(id);
|
||||
|
||||
document.addEventListener("applyCustomFormation", () => {
|
||||
var dialog = document.getElementById("custom-formation-dialog");
|
||||
if (dialog)
|
||||
{
|
||||
dialog.classList.add("hide");
|
||||
var clock = 1;
|
||||
while (clock < 8)
|
||||
{
|
||||
if ((<HTMLInputElement> dialog.querySelector(`#formation-${clock}`)).checked)
|
||||
break
|
||||
clock++;
|
||||
}
|
||||
var angleDeg = 360 - (clock - 1) * 45;
|
||||
var angleRad = deg2rad(angleDeg);
|
||||
var distance = parseInt((<HTMLInputElement> dialog.querySelector(`#distance`)?.querySelector("input")).value) * 0.3048;
|
||||
var upDown = parseInt((<HTMLInputElement> dialog.querySelector(`#up-down`)?.querySelector("input")).value) * 0.3048;
|
||||
|
||||
// X: front-rear, positive front
|
||||
// Y: top-bottom, positive top
|
||||
// Z: left-right, positive right
|
||||
|
||||
var x = distance * Math.cos(angleRad);
|
||||
var y = upDown;
|
||||
var z = distance * Math.sin(angleRad);
|
||||
|
||||
if (this.#customFormationCallback)
|
||||
this.#customFormationCallback({"x": x, "y": y, "z": z})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
setOptions(options: string[], callback: CallableFunction)
|
||||
setCustomFormationCallback(callback: CallableFunction) {
|
||||
this.#customFormationCallback = callback;
|
||||
}
|
||||
|
||||
setOptions(options: {[key: string]: string}, callback: CallableFunction)
|
||||
{
|
||||
this.getContainer()?.replaceChildren(...options.map((option: string) =>
|
||||
this.getContainer()?.replaceChildren(...Object.keys(options).map((option: string, idx: number) =>
|
||||
{
|
||||
var button = document.createElement("button");
|
||||
button.innerText = option;
|
||||
button.innerHTML = options[option];
|
||||
button.addEventListener("click", () => callback(option));
|
||||
return (button);
|
||||
}));
|
||||
|
||||
@@ -11,6 +11,9 @@ import { FeatureSwitches } from "./featureswitches";
|
||||
import { LogPanel } from "./panels/logpanel";
|
||||
import { getAirbases, getBullseye as getBullseyes, getConfig, getMission, getUnits, setAddress, toggleDemoEnabled } from "./server/server";
|
||||
import { UnitDataTable } from "./units/unitdatatable";
|
||||
import { keyEventWasInInput } from "./other/utils";
|
||||
import { Popup } from "./popups/popup";
|
||||
import { Dropdown } from "./controls/dropdown";
|
||||
|
||||
var map: Map;
|
||||
|
||||
@@ -26,7 +29,10 @@ var unitControlPanel: UnitControlPanel;
|
||||
var mouseInfoPanel: MouseInfoPanel;
|
||||
var logPanel: LogPanel;
|
||||
|
||||
var infoPopup: Popup;
|
||||
|
||||
var connected: boolean = false;
|
||||
var paused: boolean = false;
|
||||
var activeCoalition: string = "blue";
|
||||
|
||||
var sessionHash: string | null = null;
|
||||
@@ -50,6 +56,9 @@ function setup() {
|
||||
mouseInfoPanel = new MouseInfoPanel("mouse-info-panel");
|
||||
//logPanel = new LogPanel("log-panel");
|
||||
|
||||
/* Popups */
|
||||
infoPopup = new Popup("info-popup");
|
||||
|
||||
unitDataTable = new UnitDataTable("unit-data-table");
|
||||
|
||||
/* AIC */
|
||||
@@ -63,9 +72,12 @@ function setup() {
|
||||
let atcFeatureSwitch = featureSwitches.getSwitch("atc");
|
||||
if (atcFeatureSwitch?.isEnabled()) {
|
||||
atc = new ATC();
|
||||
// TODO: add back buttons
|
||||
atc.startUpdates();
|
||||
}
|
||||
|
||||
|
||||
new Dropdown( "app-icon", () => {} );
|
||||
|
||||
/* Setup event handlers */
|
||||
setupEvents();
|
||||
|
||||
@@ -80,7 +92,7 @@ function readConfig(config: any)
|
||||
const port = config["server"]["port"];
|
||||
if ((typeof address === 'string' || address instanceof String) && typeof port == 'number')
|
||||
{
|
||||
setAddress(<string>address, <number>port);
|
||||
setAddress(window.location.hostname, <number>port);
|
||||
}
|
||||
|
||||
/* On the first connection, force request of full data */
|
||||
@@ -105,8 +117,10 @@ function startPeriodicUpdate() {
|
||||
function requestUpdate() {
|
||||
/* Main update rate = 250ms is minimum time, equal to server update time. */
|
||||
getUnits((data: UnitsData) => {
|
||||
getUnitsManager()?.update(data);
|
||||
checkSessionHash(data.sessionHash);
|
||||
if (!getPaused()){
|
||||
getUnitsManager()?.update(data);
|
||||
checkSessionHash(data.sessionHash);
|
||||
}
|
||||
}, false);
|
||||
setTimeout(() => requestUpdate(), getConnected() ? 250 : 1000);
|
||||
|
||||
@@ -116,15 +130,17 @@ function requestUpdate() {
|
||||
function requestRefresh() {
|
||||
/* Main refresh rate = 5000ms. */
|
||||
getUnits((data: UnitsData) => {
|
||||
getUnitsManager()?.update(data);
|
||||
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
|
||||
getBullseyes((data: BullseyesData) => getMissionData()?.update(data));
|
||||
getMission((data: any) => {getMissionData()?.update(data)});
|
||||
if (!getPaused()){
|
||||
getUnitsManager()?.update(data);
|
||||
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
|
||||
getBullseyes((data: BullseyesData) => getMissionData()?.update(data));
|
||||
getMission((data: any) => {getMissionData()?.update(data)});
|
||||
|
||||
// Update the list of existing units
|
||||
getUnitDataTable()?.update();
|
||||
|
||||
checkSessionHash(data.sessionHash);
|
||||
// Update the list of existing units
|
||||
getUnitDataTable()?.update();
|
||||
|
||||
checkSessionHash(data.sessionHash);
|
||||
}
|
||||
}, true);
|
||||
setTimeout(() => requestRefresh(), 5000);
|
||||
}
|
||||
@@ -141,13 +157,16 @@ function checkSessionHash(newSessionHash: string) {
|
||||
function setupEvents() {
|
||||
/* Generic clicks */
|
||||
document.addEventListener("click", (ev) => {
|
||||
if (ev instanceof PointerEvent && ev.target instanceof HTMLElement) {
|
||||
if (ev instanceof MouseEvent && ev.target instanceof HTMLElement) {
|
||||
|
||||
const target = ev.target;
|
||||
|
||||
if (target.classList.contains("olympus-dialog-close")) {
|
||||
target.closest("div.olympus-dialog")?.classList.add("hide");
|
||||
}
|
||||
|
||||
const triggerElement = target.closest("[data-on-click]");
|
||||
|
||||
if (triggerElement instanceof HTMLElement) {
|
||||
const eventName: string = triggerElement.dataset.onClick || "";
|
||||
let params = JSON.parse(triggerElement.dataset.onClickParams || "{}");
|
||||
@@ -164,23 +183,25 @@ function setupEvents() {
|
||||
|
||||
/* Keyup events */
|
||||
document.addEventListener("keyup", ev => {
|
||||
|
||||
if ( keyEventWasInInput( ev ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ev.code) {
|
||||
|
||||
case "KeyL":
|
||||
document.body.toggleAttribute("data-hide-labels");
|
||||
break;
|
||||
|
||||
case "KeyD":
|
||||
toggleDemoEnabled();
|
||||
break;
|
||||
|
||||
case "Minus": // For Veltro's italian layout keyboard, which lacks a quote
|
||||
case "Quote":
|
||||
unitDataTable.toggle();
|
||||
break
|
||||
case "Space":
|
||||
setPaused(!getPaused());
|
||||
break;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
/*
|
||||
@@ -211,26 +232,6 @@ function setupEvents() {
|
||||
})
|
||||
});
|
||||
|
||||
/** Olympus UI ***/
|
||||
document.querySelectorAll(".ol-select").forEach(select => {
|
||||
|
||||
// Do open/close toggle
|
||||
select.addEventListener("click", ev => {
|
||||
|
||||
if ( ev.target instanceof HTMLElement && ev.target.nodeName !== "A" ) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
|
||||
ev.stopPropagation();
|
||||
select.classList.toggle("is-open");
|
||||
});
|
||||
|
||||
// Autoclose on mouseleave
|
||||
select.addEventListener("mouseleave", ev => {
|
||||
select.classList.remove("is-open");
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
export function getMap() {
|
||||
@@ -279,11 +280,26 @@ export function getActiveCoalition() {
|
||||
}
|
||||
|
||||
export function setConnected(newConnected: boolean) {
|
||||
connected = newConnected
|
||||
if (connected != newConnected)
|
||||
newConnected? getInfoPopup().setText("Connected to DCS Olympus server"): getInfoPopup().setText("Disconnected from DCS Olympus server");
|
||||
connected = newConnected;
|
||||
}
|
||||
|
||||
export function getConnected() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
export function setPaused(newPaused: boolean) {
|
||||
paused = newPaused;
|
||||
paused? getInfoPopup().setText("Paused"): getInfoPopup().setText("Unpaused");
|
||||
}
|
||||
|
||||
export function getPaused() {
|
||||
return paused;
|
||||
}
|
||||
|
||||
export function getInfoPopup() {
|
||||
return infoPopup;
|
||||
}
|
||||
|
||||
window.onload = setup;
|
||||
@@ -19,6 +19,7 @@ export class Map extends L.Map {
|
||||
#preventLeftClick: boolean = false;
|
||||
#leftClickTimer: number = 0;
|
||||
#lastMousePosition: L.Point = new L.Point(0, 0);
|
||||
#centerUnit: Unit | null = null;
|
||||
|
||||
#mapContextMenu: MapContextMenu = new MapContextMenu("map-contextmenu");
|
||||
#unitContextMenu: UnitContextMenu = new UnitContextMenu("unit-contextmenu");
|
||||
@@ -29,7 +30,7 @@ export class Map extends L.Map {
|
||||
constructor(ID: string) {
|
||||
/* Init the leaflet map */
|
||||
//@ts-ignore
|
||||
super(ID, { doubleClickZoom: false, zoomControl: false, boxZoom: false, boxSelect: true });
|
||||
super(ID, { doubleClickZoom: false, zoomControl: false, boxZoom: false, boxSelect: true, zoomAnimation: false });
|
||||
this.setView([37.23, -115.8], 12);
|
||||
|
||||
this.setLayer("ArcGIS Satellite");
|
||||
@@ -39,7 +40,9 @@ export class Map extends L.Map {
|
||||
|
||||
/* Register event handles */
|
||||
this.on("click", (e: any) => this.#onClick(e));
|
||||
this.on("dblclick", (e: any) => this.#onDoubleClick(e));
|
||||
this.on("dblclick", (e: any) => this.#onDoubleClick(e));
|
||||
this.on("zoomstart", (e: any) => this.#onZoom(e));
|
||||
this.on("drag", (e: any) => this.centerOnUnit(null));
|
||||
this.on("contextmenu", (e: any) => this.#onContextMenu(e));
|
||||
this.on('selectionend', (e: any) => this.#onSelectionEnd(e));
|
||||
this.on('mousedown', (e: any) => this.#onMouseDown(e));
|
||||
@@ -56,6 +59,11 @@ export class Map extends L.Map {
|
||||
document.body.toggleAttribute("data-hide-" + ev.detail.category);
|
||||
Object.values(getUnitsManager().getUnits()).forEach((unit: Unit) => unit.updateVisibility());
|
||||
});
|
||||
|
||||
document.addEventListener("unitUpdated", (ev: CustomEvent) => {
|
||||
if (this.#centerUnit != null && ev.detail == this.#centerUnit)
|
||||
this.#panToUnit(this.#centerUnit);
|
||||
});
|
||||
|
||||
this.#mapSourceDropdown = new Dropdown("map-type", (layerName: string) => this.setLayer(layerName), this.getLayers())
|
||||
}
|
||||
@@ -195,6 +203,18 @@ export class Map extends L.Map {
|
||||
//this.#aircraftSpawnMenu(e);
|
||||
}
|
||||
|
||||
centerOnUnit(ID: number | null){
|
||||
if (ID != null)
|
||||
{
|
||||
this.options.scrollWheelZoom = 'center';
|
||||
this.#centerUnit = getUnitsManager().getUnitByID(ID);
|
||||
}
|
||||
else {
|
||||
this.options.scrollWheelZoom = undefined;
|
||||
this.#centerUnit = null;
|
||||
}
|
||||
}
|
||||
|
||||
/* Event handlers */
|
||||
#onClick(e: any) {
|
||||
if (!this.#preventLeftClick) {
|
||||
@@ -256,4 +276,16 @@ export class Map extends L.Map {
|
||||
this.#lastMousePosition.x = e.originalEvent.x;
|
||||
this.#lastMousePosition.y = e.originalEvent.y;
|
||||
}
|
||||
|
||||
#onZoom(e: any)
|
||||
{
|
||||
if (this.#centerUnit != null)
|
||||
this.#panToUnit(this.#centerUnit);
|
||||
}
|
||||
|
||||
#panToUnit(unit: Unit)
|
||||
{
|
||||
var unitPosition = new L.LatLng(unit.getFlightData().latitude, unit.getFlightData().longitude);
|
||||
this.setView(unitPosition, this.getZoom(), {animate: false});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Marker, LatLng, Icon } from "leaflet";
|
||||
import { getMap, getUnitsManager } from "..";
|
||||
import { getInfoPopup, getMap, getUnitsManager } from "..";
|
||||
import { Airbase } from "./airbase";
|
||||
|
||||
var bullseyeIcons = [
|
||||
@@ -58,6 +58,8 @@ export class MissionHandler
|
||||
getMap().setView(new LatLng(-50.6, -42.7), 7);
|
||||
else if (this.#theatre == "Caucasus")
|
||||
getMap().setView(new LatLng(42.1, 42.3), 8);
|
||||
|
||||
getInfoPopup().setText("Map set to " + this.#theatre);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,8 +95,8 @@ export class MissionHandler
|
||||
{
|
||||
this.#airbasesMarkers[idx].setLatLng(new LatLng(airbase.latitude, airbase.longitude));
|
||||
this.#airbasesMarkers[idx].setCoalition(airbase.coalition);
|
||||
this.#airbasesMarkers[idx].setProperties(["Runway 1: 31L / 13R", "Runway 2: 31R / 13L", "TCN: 17X", "ILS: ---" ]);
|
||||
this.#airbasesMarkers[idx].setParkings(["2x big", "5x small"]);
|
||||
//this.#airbasesMarkers[idx].setProperties(["Runway 1: 31L / 13R", "Runway 2: 31R / 13L", "TCN: 17X", "ILS: ---" ]);
|
||||
//this.#airbasesMarkers[idx].setParkings(["2x big", "5x small"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,23 @@ export function distance(lat1: number, lon1: number, lat2: number, lon2: number)
|
||||
}
|
||||
|
||||
|
||||
export function generateUUIDv4() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function keyEventWasInInput( event:KeyboardEvent ) {
|
||||
|
||||
const target = event.target;
|
||||
|
||||
return ( target instanceof HTMLElement && ( [ "INPUT", "TEXTAREA" ].includes( target.nodeName ) ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
export function rad2deg(rad: number) {
|
||||
var pi = Math.PI;
|
||||
return rad / (pi / 180);
|
||||
|
||||
@@ -18,7 +18,7 @@ export class MouseInfoPanel extends Panel {
|
||||
this.#measureMarker = new Marker([0, 0], {icon: this.#measureIcon, interactive: false});
|
||||
|
||||
this.#measureBox = document.createElement("div");
|
||||
this.#measureBox.classList.add("ol-measure-box");
|
||||
this.#measureBox.classList.add("ol-measure-box", "hide");
|
||||
document.body.appendChild(this.#measureBox);
|
||||
|
||||
getMap()?.on("click", (e: any) => this.#onMapClick(e));
|
||||
@@ -36,10 +36,17 @@ export class MouseInfoPanel extends Panel {
|
||||
var el = <HTMLElement>this.getElement().querySelector(`#bullseye-${idx}`);
|
||||
|
||||
if ( el != null ) {
|
||||
|
||||
var dist = distance(bullseyes[idx].latitude, bullseyes[idx].longitude, mousePosition.lat, mousePosition.lng);
|
||||
var bear = bearing(bullseyes[idx].latitude, bullseyes[idx].longitude, mousePosition.lat, mousePosition.lng);
|
||||
|
||||
el.dataset.bearing = zeroAppend(Math.floor(bear), 3);
|
||||
let bng = zeroAppend(Math.floor(bear), 3);
|
||||
|
||||
if ( bng === "000" ) {
|
||||
bng = "360";
|
||||
}
|
||||
|
||||
el.dataset.bearing = bng;
|
||||
el.dataset.distance = zeroAppend(Math.floor(dist*0.000539957), 3);
|
||||
el.dataset.distanceUnits = "NM";
|
||||
}
|
||||
|
||||
@@ -11,9 +11,13 @@ export class Panel {
|
||||
this.#visible = true;
|
||||
}
|
||||
|
||||
protected onHide() {}
|
||||
|
||||
hide() {
|
||||
this.#element.classList.toggle("hide", true);
|
||||
this.#visible = false;
|
||||
|
||||
this.onHide();
|
||||
}
|
||||
|
||||
toggle() {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { getUnitsManager } from "..";
|
||||
import { Dropdown } from "../controls/dropdown";
|
||||
import { Slider } from "../controls/slider";
|
||||
import { dataPointMap } from "../other/utils";
|
||||
import { aircraftDatabase } from "../units/aircraftdatabase";
|
||||
@@ -7,30 +8,47 @@ import { Aircraft, GroundUnit, Unit } from "../units/unit";
|
||||
import { UnitDatabase } from "../units/unitdatabase";
|
||||
import { Panel } from "./panel";
|
||||
|
||||
// const ROEs: string[] = ["Free", "Designated free", "Designated", "Return", "Hold"]; // Full list
|
||||
// const reactionsToThreat: string[] = ["None", "Passive", "Evade", "Escape", "Abort"]; // Full list
|
||||
|
||||
const ROEs: string[] = [ "Hold", "Return", "Designated", "Free" ];
|
||||
const reactionsToThreat: string[] = [ "None", "Passive", "Evade" ];
|
||||
const ROEs: string[] = ["Hold", "Return", "Designated", "Free"];
|
||||
const reactionsToThreat: string[] = ["None", "Passive", "Evade"];
|
||||
|
||||
const minSpeedValues: { [key: string]: number } = { Aircraft: 100, Helicopter: 0, NavyUnit: 0, GroundUnit: 0 };
|
||||
const maxSpeedValues: { [key: string]: number } = { Aircraft: 800, Helicopter: 300, NavyUnit: 60, GroundUnit: 60 };
|
||||
const speedIncrements: { [key: string]: number } = { Aircraft: 25, Helicopter: 10, NavyUnit: 5, GroundUnit: 5 };
|
||||
const minAltitudeValues: { [key: string]: number } = { Aircraft: 0, Helicopter: 0 };
|
||||
const maxAltitudeValues: { [key: string]: number } = { Aircraft: 50000, Helicopter: 10000 };
|
||||
const altitudeIncrements: { [key: string]: number } = { Aircraft: 2500, Helicopter: 1000 };
|
||||
const altitudeIncrements: { [key: string]: number } = { Aircraft: 500, Helicopter: 100 };
|
||||
|
||||
export class UnitControlPanel extends Panel {
|
||||
#altitudeSlider: Slider;
|
||||
#airspeedSlider: Slider;
|
||||
#TACANXYDropdown: Dropdown;
|
||||
#radioDecimalsDropdown: Dropdown;
|
||||
#radioCallsignDropdown: Dropdown;
|
||||
#expectedAltitude: number = -1;
|
||||
#expectedSpeed: number = -1;
|
||||
#optionButtons: { [key: string]: HTMLButtonElement[] } = {}
|
||||
#advancedSettingsDialog: HTMLElement;
|
||||
|
||||
constructor(ID: string) {
|
||||
super(ID);
|
||||
|
||||
/* Unit control sliders */
|
||||
this.#altitudeSlider = new Slider("altitude-slider", 0, 100, "ft", (value: number) => getUnitsManager().selectedUnitsSetAltitude(value * 0.3048));
|
||||
this.#airspeedSlider = new Slider("airspeed-slider", 0, 100, "kts", (value: number) => getUnitsManager().selectedUnitsSetSpeed(value / 1.94384));
|
||||
this.#altitudeSlider = new Slider("altitude-slider", 0, 100, "ft", (value: number) => {
|
||||
this.#expectedAltitude = value;
|
||||
getUnitsManager().selectedUnitsSetAltitude(value * 0.3048)
|
||||
});
|
||||
|
||||
this.#airspeedSlider = new Slider("airspeed-slider", 0, 100, "kts", (value: number) => {
|
||||
this.#expectedSpeed = value;
|
||||
getUnitsManager().selectedUnitsSetSpeed(value / 1.94384)
|
||||
});
|
||||
|
||||
/* Advanced settings dropdowns */
|
||||
this.#TACANXYDropdown = new Dropdown("TACAN-XY", () => {});
|
||||
this.#TACANXYDropdown.setOptions(["X", "Y"]);
|
||||
this.#radioDecimalsDropdown = new Dropdown("radio-decimals", () => {});
|
||||
this.#radioDecimalsDropdown.setOptions([".000", ".250", ".500", ".750"]);
|
||||
this.#radioCallsignDropdown = new Dropdown("radio-callsign", () => {});
|
||||
|
||||
/* Option buttons */
|
||||
this.#optionButtons["ROE"] = ROEs.map((option: string, index: number) => {
|
||||
@@ -52,15 +70,50 @@ export class UnitControlPanel extends Panel {
|
||||
this.getElement().querySelector("#roe-buttons-container")?.append(...this.#optionButtons["ROE"]);
|
||||
this.getElement().querySelector("#reaction-to-threat-buttons-container")?.append(...this.#optionButtons["reactionToThreat"]);
|
||||
|
||||
this.#advancedSettingsDialog = <HTMLElement> document.querySelector("#advanced-settings-dialog");
|
||||
|
||||
document.addEventListener("unitUpdated", (e: CustomEvent<Unit>) => { if (e.detail.getSelected()) this.update() });
|
||||
document.addEventListener("unitsSelection", (e: CustomEvent<Unit[]>) => { this.show(); this.update() });
|
||||
document.addEventListener("clearSelection", () => { this.hide() });
|
||||
document.addEventListener("applyAdvancedSettings", () => {this.#applyAdvancedSettings();})
|
||||
document.addEventListener("showAdvancedSettings", () => {
|
||||
this.#updateAdvancedSettingsDialog(getUnitsManager().getSelectedUnits());
|
||||
this.#advancedSettingsDialog.classList.remove("hide");
|
||||
})
|
||||
|
||||
this.hide();
|
||||
}
|
||||
|
||||
|
||||
// Do this after panel is hidden (make sure there's a reset)
|
||||
protected onHide() {
|
||||
this.#expectedAltitude = -1;
|
||||
this.#expectedSpeed = -1;
|
||||
}
|
||||
|
||||
|
||||
// Update function will only be allowed to update the sliders once it's matched the expected value for the first time (due to lag of Ajax request)
|
||||
#updateCanSetAltitudeSlider(altitude: number) {
|
||||
if (this.#expectedAltitude < 0 || altitude === this.#expectedAltitude) {
|
||||
this.#expectedAltitude = -1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#updateCanSetSpeedSlider(altitude: number) {
|
||||
if (this.#expectedSpeed < 0 || altitude === this.#expectedSpeed) {
|
||||
this.#expectedSpeed = -1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
update() {
|
||||
var units = getUnitsManager().getSelectedUnits();
|
||||
|
||||
this.getElement().querySelector("#advanced-settings-div")?.classList.toggle("hide", units.length != 1);
|
||||
|
||||
if (this.getElement() != null && units.length > 0) {
|
||||
this.#showFlightControlSliders(units);
|
||||
|
||||
@@ -73,23 +126,9 @@ export class UnitControlPanel extends Panel {
|
||||
else
|
||||
database = null; // TODO add databases for other unit types
|
||||
|
||||
if (index === 0) {
|
||||
this.getElement().querySelectorAll(`[data-object|="unit"]`).forEach(marker => {
|
||||
|
||||
marker.setAttribute("data-coalition", unit.getMissionData().coalition);
|
||||
|
||||
dataPointMap( this.getElement(), {
|
||||
"shortLabel" : database?.getByName(unit.getBaseData().name)?.shortLabel,
|
||||
"unitName": unit.getBaseData().unitName
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
var button = document.createElement("button");
|
||||
var callsign = unit.getBaseData().unitName || "";
|
||||
|
||||
button.innerText = unit.getBaseData().unitName;
|
||||
button.setAttribute("data-short-label", database?.getByName(unit.getBaseData().name)?.shortLabel || "");
|
||||
button.setAttribute("data-callsign", callsign);
|
||||
|
||||
@@ -110,15 +149,14 @@ export class UnitControlPanel extends Panel {
|
||||
}
|
||||
}
|
||||
|
||||
#showFlightControlSliders(units: Unit[])
|
||||
{
|
||||
if (getUnitsManager().getSelectedUnitsType() !== undefined)
|
||||
this.#airspeedSlider.show()
|
||||
#showFlightControlSliders(units: Unit[]) {
|
||||
if (getUnitsManager().getSelectedUnitsType() !== undefined)
|
||||
this.#airspeedSlider.show()
|
||||
else
|
||||
this.#airspeedSlider.hide();
|
||||
|
||||
if (getUnitsManager().getSelectedUnitsType() === "Aircraft" || getUnitsManager().getSelectedUnitsType() === "Helicopter")
|
||||
this.#altitudeSlider.show()
|
||||
|
||||
if (getUnitsManager().getSelectedUnitsType() === "Aircraft" || getUnitsManager().getSelectedUnitsType() === "Helicopter")
|
||||
this.#altitudeSlider.show()
|
||||
else
|
||||
this.#altitudeSlider.hide();
|
||||
|
||||
@@ -138,16 +176,111 @@ export class UnitControlPanel extends Panel {
|
||||
this.#altitudeSlider.setIncrement(altitudeIncrements[unitsType]);
|
||||
|
||||
this.#airspeedSlider.setActive(targetSpeed != undefined);
|
||||
if (targetSpeed != undefined)
|
||||
this.#airspeedSlider.setValue(targetSpeed * 1.94384);
|
||||
if (targetSpeed != undefined) {
|
||||
|
||||
targetSpeed *= 1.94384;
|
||||
|
||||
if (this.#updateCanSetSpeedSlider(targetSpeed)) {
|
||||
this.#airspeedSlider.setValue(targetSpeed);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.#altitudeSlider.setActive(targetAltitude != undefined);
|
||||
if (targetAltitude != undefined)
|
||||
this.#altitudeSlider.setValue(targetAltitude / 0.3048);
|
||||
if (targetAltitude != undefined) {
|
||||
targetAltitude /= 0.3048;
|
||||
|
||||
if (this.#updateCanSetAltitudeSlider(targetAltitude)) {
|
||||
this.#altitudeSlider.setValue(targetAltitude);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.#airspeedSlider.setActive(false);
|
||||
this.#altitudeSlider.setActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
#updateAdvancedSettingsDialog(units: Unit[])
|
||||
{
|
||||
if (units.length == 1)
|
||||
{
|
||||
const unit = units[0];
|
||||
(<HTMLElement>this.#advancedSettingsDialog.querySelector("#unit-name")).innerText = unit.getBaseData().unitName;
|
||||
|
||||
if (getUnitsManager().getSelectedUnits().length == 1)
|
||||
{
|
||||
var radioMHz = Math.floor(unit.getTaskData().radioFrequency / 1000000);
|
||||
var radioDecimals = (unit.getTaskData().radioFrequency / 1000000 - radioMHz) * 1000;
|
||||
|
||||
// Default values for "normal" units
|
||||
this.#radioCallsignDropdown.setOptions(["Enfield", "Springfield", "Uzi", "Colt", "Dodge", "Ford", "Chevy", "Pontiac"]);
|
||||
this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign);
|
||||
|
||||
// Input values
|
||||
var tankerCheckbox = this.#advancedSettingsDialog.querySelector("#tanker-checkbox")?.querySelector("input")
|
||||
var AWACSCheckbox = this.#advancedSettingsDialog.querySelector("#AWACS-checkbox")?.querySelector("input")
|
||||
|
||||
var TACANChannelInput = this.#advancedSettingsDialog.querySelector("#TACAN-channel")?.querySelector("input");
|
||||
var TACANCallsignInput = this.#advancedSettingsDialog.querySelector("#tacan-callsign")?.querySelector("input");
|
||||
var radioMhzInput = this.#advancedSettingsDialog.querySelector("#radio-mhz")?.querySelector("input");
|
||||
var radioCallsignNumberInput = this.#advancedSettingsDialog.querySelector("#radio-callsign-number")?.querySelector("input");
|
||||
|
||||
if (tankerCheckbox) tankerCheckbox.checked = unit.getTaskData().isTanker;
|
||||
if (AWACSCheckbox) AWACSCheckbox.checked = unit.getTaskData().isAWACS;
|
||||
if (TACANChannelInput) TACANChannelInput.value = String(unit.getTaskData().TACANChannel);
|
||||
if (TACANCallsignInput) TACANCallsignInput.value = String(unit.getTaskData().TACANCallsign);
|
||||
if (radioMhzInput) radioMhzInput.value = String(radioMHz);
|
||||
if (radioCallsignNumberInput) radioCallsignNumberInput.value = String(unit.getTaskData().radioCallsignNumber);
|
||||
|
||||
this.#TACANXYDropdown.setValue(unit.getTaskData().TACANXY);
|
||||
this.#radioDecimalsDropdown.setValue("." + radioDecimals);
|
||||
|
||||
// Make sure its in the valid range
|
||||
if (!this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign))
|
||||
this.#radioCallsignDropdown.selectValue(0);
|
||||
|
||||
// Set options for tankers
|
||||
var roles = aircraftDatabase.getByName(unit.getBaseData().name)?.loadouts.map((loadout) => {return loadout.roles})
|
||||
if (roles != undefined && Array.prototype.concat.apply([], roles)?.includes("Tanker")){
|
||||
this.#advancedSettingsDialog.querySelector("#tanker-checkbox")?.classList.remove("hide");
|
||||
this.#radioCallsignDropdown.setOptions(["Texaco", "Arco", "Shell"]);
|
||||
this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign);
|
||||
}
|
||||
else {
|
||||
this.#advancedSettingsDialog.querySelector("#tanker-checkbox")?.classList.add("hide");
|
||||
}
|
||||
|
||||
// Set options for AWACS
|
||||
if (roles != undefined && Array.prototype.concat.apply([], roles)?.includes("AWACS")){
|
||||
this.#advancedSettingsDialog.querySelector("#AWACS-checkbox")?.classList.remove("hide");
|
||||
this.#radioCallsignDropdown.setOptions(["Overlord", "Magic", "Wizard", "Focus", "Darkstar"]);
|
||||
this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign);
|
||||
} else {
|
||||
this.#advancedSettingsDialog.querySelector("#AWACS-checkbox")?.classList.add("hide");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#applyAdvancedSettings()
|
||||
{
|
||||
const isTanker = this.#advancedSettingsDialog.querySelector("#tanker-checkbox")?.querySelector("input")?.checked? true: false;
|
||||
const isAWACS = this.#advancedSettingsDialog.querySelector("#AWACS-checkbox")?.querySelector("input")?.checked? true: false;
|
||||
const TACANChannel = Number(this.#advancedSettingsDialog.querySelector("#TACAN-channel")?.querySelector("input")?.value);
|
||||
const TACANXY = this.#TACANXYDropdown.getValue();
|
||||
const TACANCallsign = <string> this.#advancedSettingsDialog.querySelector("#tacan-callsign")?.querySelector("input")?.value
|
||||
const radioMHz = Number(this.#advancedSettingsDialog.querySelector("#radio-mhz")?.querySelector("input")?.value);
|
||||
const radioDecimals = this.#radioDecimalsDropdown.getValue();
|
||||
const radioCallsign = this.#radioCallsignDropdown.getIndex();
|
||||
const radioCallsignNumber = Number(this.#advancedSettingsDialog.querySelector("#radio-callsign-number")?.querySelector("input")?.value);
|
||||
|
||||
var radioFrequency = (radioMHz * 1000 + Number(radioDecimals.substring(1))) * 1000;
|
||||
|
||||
var units = getUnitsManager().getSelectedUnits();
|
||||
if (units.length > 0)
|
||||
units[0].setAdvancedOptions(isTanker, isAWACS, TACANChannel, TACANXY, TACANCallsign, radioFrequency, radioCallsign, radioCallsignNumber);
|
||||
|
||||
this.#advancedSettingsDialog.classList.add("hide");
|
||||
}
|
||||
}
|
||||
26
client/src/popups/popup.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Panel } from "../panels/panel";
|
||||
|
||||
export class Popup extends Panel {
|
||||
#fadeTime: number = 2000; // Milliseconds
|
||||
#hideTimer: number | undefined = undefined;
|
||||
#visibilityTimer: number | undefined = undefined;
|
||||
|
||||
setFadeTime(fadeTime: number) {
|
||||
this.#fadeTime = fadeTime;
|
||||
}
|
||||
|
||||
setText(text: string) {
|
||||
(<HTMLElement> this.getElement().querySelector("div")).innerText = text;
|
||||
this.show();
|
||||
this.getElement().classList.remove("invisible");
|
||||
this.getElement().classList.add("visible");
|
||||
|
||||
clearTimeout(this.#visibilityTimer);
|
||||
clearTimeout(this.#hideTimer);
|
||||
this.#visibilityTimer = setTimeout(() => {
|
||||
this.getElement().classList.remove("visible");
|
||||
this.getElement().classList.add("invisible");
|
||||
this.#hideTimer = setTimeout(() => this.hide(), 2000);
|
||||
}, this.#fadeTime);
|
||||
}
|
||||
}
|
||||
@@ -23,9 +23,14 @@ export function GET(callback: CallableFunction, uri: string){
|
||||
xmlHttp.open("GET", `${demoEnabled? DEMO_ADDRESS: REST_ADDRESS}/${uri}`, true);
|
||||
xmlHttp.onload = function (e) {
|
||||
var data = JSON.parse(xmlHttp.responseText);
|
||||
callback(data);
|
||||
lastUpdateTime = parseInt(data.time);
|
||||
setConnected(true);
|
||||
if (parseInt(data.time) > lastUpdateTime)
|
||||
{
|
||||
callback(data);
|
||||
lastUpdateTime = parseInt(data.time);
|
||||
if (isNaN(lastUpdateTime))
|
||||
lastUpdateTime = 0;
|
||||
setConnected(true);
|
||||
}
|
||||
};
|
||||
xmlHttp.onerror = function () {
|
||||
console.error("An error occurred during the XMLHttpRequest");
|
||||
@@ -50,7 +55,6 @@ export function getConfig(callback: CallableFunction) {
|
||||
xmlHttp.onload = function (e) {
|
||||
var data = JSON.parse(xmlHttp.responseText);
|
||||
callback(data);
|
||||
lastUpdateTime = parseInt(data.time);
|
||||
};
|
||||
xmlHttp.onerror = function () {
|
||||
console.error("An error occurred during the XMLHttpRequest, could not retrieve configuration file");
|
||||
@@ -113,6 +117,16 @@ export function attackUnit(ID: number, targetID: number) {
|
||||
POST(data, () => { });
|
||||
}
|
||||
|
||||
export function followUnit(ID: number, targetID: number, offset: {"x": number, "y": number, "z": number}) {
|
||||
// X: front-rear, positive front
|
||||
// Y: top-bottom, positive bottom
|
||||
// Z: left-right, positive right
|
||||
|
||||
var command = { "ID": ID, "targetID": targetID, "offsetX": offset["x"], "offsetY": offset["y"], "offsetZ": offset["z"]};
|
||||
var data = { "followUnit": command }
|
||||
POST(data, () => { });
|
||||
}
|
||||
|
||||
export function cloneUnit(ID: number, latlng: L.LatLng) {
|
||||
var command = { "ID": ID, "location": latlng };
|
||||
var data = { "cloneUnit": command }
|
||||
@@ -172,3 +186,26 @@ export function setReactionToThreat(ID: number, reactionToThreat: string) {
|
||||
var data = {"setReactionToThreat": command}
|
||||
POST(data, () => { });
|
||||
}
|
||||
|
||||
export function refuel(ID: number) {
|
||||
var command = { "ID": ID };
|
||||
var data = { "refuel": command }
|
||||
POST(data, () => { });
|
||||
}
|
||||
|
||||
export function setAdvacedOptions(ID: number, isTanker: boolean, isAWACS: boolean, TACANChannel: number, TACANXY: string, TACANCallsign: string, radioFrequency: number, radioCallsign: number, radioCallsignNumber: number)
|
||||
{
|
||||
var command = { "ID": ID,
|
||||
"isTanker": isTanker,
|
||||
"isAWACS": isAWACS,
|
||||
"TACANChannel": TACANChannel,
|
||||
"TACANXY": TACANXY,
|
||||
"TACANCallsign": TACANCallsign,
|
||||
"radioFrequency": radioFrequency,
|
||||
"radioCallsign": radioCallsign,
|
||||
"radioCallsignNumber": radioCallsignNumber
|
||||
};
|
||||
|
||||
var data = { "setAdvancedOptions": command };
|
||||
POST(data, () => { });
|
||||
}
|
||||
@@ -4,7 +4,6 @@ export class AircraftDatabase extends UnitDatabase {
|
||||
constructor() {
|
||||
super();
|
||||
this.blueprints = {
|
||||
|
||||
"A-10C": {
|
||||
"name": "A-10C",
|
||||
"label": "A-10CII",
|
||||
@@ -444,7 +443,7 @@ export class AircraftDatabase extends UnitDatabase {
|
||||
},
|
||||
"F-16C bl.52d": {
|
||||
"name": "F-16C bl.52d",
|
||||
"label": "F-16C bl.52d",
|
||||
"label": "F-16C",
|
||||
"shortLabel": "16",
|
||||
"loadouts": [
|
||||
{
|
||||
@@ -708,9 +707,180 @@ export class AircraftDatabase extends UnitDatabase {
|
||||
],
|
||||
"filename": "kc-135.png"
|
||||
},
|
||||
"KC135MPRS": {
|
||||
"name": "KC135MPRS",
|
||||
"label": "KC-135 MPRS",
|
||||
"shortLabel": "135M",
|
||||
"loadouts": [
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
|
||||
],
|
||||
"roles": [
|
||||
"Tanker"
|
||||
],
|
||||
"code": "",
|
||||
"name": "Default Tanker"
|
||||
}
|
||||
],
|
||||
"filename": "kc-135.png"
|
||||
},
|
||||
"I-16": {
|
||||
"name": "I-16",
|
||||
"label": "I-16",
|
||||
"shortLabel": "I16",
|
||||
"loadouts": [
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
|
||||
],
|
||||
"roles": [
|
||||
"CAP"
|
||||
],
|
||||
"code": "",
|
||||
"name": "Empty Loadout"
|
||||
}
|
||||
],
|
||||
"filename": "i-16.png"
|
||||
},
|
||||
"MiG-15bis": {
|
||||
"name": "MiG-15bis",
|
||||
"label": "MiG-15",
|
||||
"shortLabel": "M15",
|
||||
"loadouts": [
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
|
||||
],
|
||||
"roles": [
|
||||
"CAP"
|
||||
],
|
||||
"code": "",
|
||||
"name": "Empty Loadout"
|
||||
}
|
||||
],
|
||||
"filename": "mig-15.png"
|
||||
},
|
||||
"MiG-19P": {
|
||||
"name": "MiG-19P",
|
||||
"label": "MiG-19",
|
||||
"shortLabel": "19",
|
||||
"loadouts": [
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
|
||||
],
|
||||
"roles": [
|
||||
"CAP"
|
||||
],
|
||||
"code": "",
|
||||
"name": "Empty Loadout"
|
||||
},
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "K-13A Atoll",
|
||||
"quantity": 2
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"CAP"
|
||||
],
|
||||
"code": "K-13A x 2",
|
||||
"name": "Light / Fox-2 / Short range"
|
||||
},
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "K-13A Atoll",
|
||||
"quantity": 2
|
||||
},
|
||||
{
|
||||
"name": "167 gal tanks",
|
||||
"quantity": 2
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"CAP"
|
||||
],
|
||||
"code": "K-13A x 2, PTB-760 x 2",
|
||||
"name": "Medium / Fox-2 / Medium range"
|
||||
}
|
||||
],
|
||||
"filename": "mig-19.png"
|
||||
},
|
||||
"MiG-21Bis": {
|
||||
"name": "MiG-21Bis",
|
||||
"label": "MiG-21",
|
||||
"shortLabel": "21",
|
||||
"loadouts": [
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
|
||||
],
|
||||
"roles": [
|
||||
"CAP"
|
||||
],
|
||||
"code": "",
|
||||
"name": "Empty Loadout"
|
||||
},
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "R-3 Atoll",
|
||||
"quantity": 2
|
||||
},
|
||||
{
|
||||
"name": "R-60 Aphid",
|
||||
"quantity": 2
|
||||
},
|
||||
{
|
||||
"name": "130 gal tanks",
|
||||
"quantity": 1
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"CAP"
|
||||
],
|
||||
"code": "Patrol, short range",
|
||||
"name": "Light / Fox-2 / Short range"
|
||||
},
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "R-3 Atoll",
|
||||
"quantity": 2
|
||||
},
|
||||
{
|
||||
"name": "R-60 Aphid",
|
||||
"quantity": 2
|
||||
},
|
||||
{
|
||||
"name": "210 gal tanks",
|
||||
"quantity": 1
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"CAP"
|
||||
],
|
||||
"code": "Patrol, medium range",
|
||||
"name": "Medium / Fox-2 / Medium range"
|
||||
}
|
||||
],
|
||||
"filename": "mig-21.png"
|
||||
},
|
||||
"MiG-23MLD": {
|
||||
"name": "MiG-23MLD",
|
||||
"label": "MiG-23MLD",
|
||||
"label": "MiG-23",
|
||||
"shortLabel": "23",
|
||||
"loadouts": [
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Marker, LatLng, Polyline, Icon, DivIcon } from 'leaflet';
|
||||
import { getMap, getUnitsManager } from '..';
|
||||
import { rad2deg } from '../other/utils';
|
||||
import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, getUnits, landAt, setAltitude, setReactionToThreat, setROE, setSpeed } from '../server/server';
|
||||
import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, getUnits, landAt, setAltitude, setReactionToThreat, setROE, setSpeed, refuel, setAdvacedOptions, followUnit } from '../server/server';
|
||||
import { aircraftDatabase } from './aircraftdatabase';
|
||||
import { groundUnitsDatabase } from './groundunitsdatabase';
|
||||
|
||||
@@ -46,10 +46,21 @@ export class Unit extends Marker {
|
||||
wingmenIDs: [],
|
||||
},
|
||||
taskData: {
|
||||
currentState: "IDLE",
|
||||
currentTask: "",
|
||||
activePath: {},
|
||||
targetSpeed: 0,
|
||||
targetAltitude: 0,
|
||||
isTanker: false,
|
||||
isAWACS: false,
|
||||
TACANOn: false,
|
||||
TACANChannel: 0,
|
||||
TACANXY: "X",
|
||||
TACANCallsign: "",
|
||||
radioFrequency: 0,
|
||||
radioCallsign: 0,
|
||||
radioCallsignNumber: 0,
|
||||
radioAMFM: "AM"
|
||||
},
|
||||
optionsData: {
|
||||
ROE: "",
|
||||
@@ -131,7 +142,6 @@ export class Unit extends Marker {
|
||||
}
|
||||
|
||||
setData(data: UpdateData) {
|
||||
document.dispatchEvent(new CustomEvent("unitUpdated", { detail: this }));
|
||||
var updateMarker = false;
|
||||
|
||||
if ((data.flightData.latitude != undefined && data.flightData.longitude != undefined && (this.getFlightData().latitude != data.flightData.latitude || this.getFlightData().longitude != data.flightData.longitude))
|
||||
@@ -201,6 +211,8 @@ export class Unit extends Marker {
|
||||
}
|
||||
else
|
||||
this.#clearPath();
|
||||
|
||||
document.dispatchEvent(new CustomEvent("unitUpdated", { detail: this }));
|
||||
}
|
||||
|
||||
getData() {
|
||||
@@ -318,7 +330,6 @@ export class Unit extends Marker {
|
||||
}
|
||||
|
||||
attackUnit(targetID: number) {
|
||||
/* Call DCS attackUnit function */
|
||||
if (this.ID != targetID) {
|
||||
attackUnit(this.ID, targetID);
|
||||
}
|
||||
@@ -327,6 +338,15 @@ export class Unit extends Marker {
|
||||
}
|
||||
}
|
||||
|
||||
followUnit(targetID: number, offset: {"x": number, "y": number, "z": number}) {
|
||||
if (this.ID != targetID) {
|
||||
followUnit(this.ID, targetID, offset);
|
||||
}
|
||||
else {
|
||||
// TODO: show a message
|
||||
}
|
||||
}
|
||||
|
||||
landAt(latlng: LatLng) {
|
||||
landAt(this.ID, latlng);
|
||||
}
|
||||
@@ -363,6 +383,14 @@ export class Unit extends Marker {
|
||||
deleteUnit(this.ID);
|
||||
}
|
||||
|
||||
refuel() {
|
||||
refuel(this.ID);
|
||||
}
|
||||
|
||||
setAdvancedOptions(isTanker: boolean, isAWACS: boolean, TACANChannel: number, TACANXY: string, TACANcallsign: string, radioFrequency: number, radioCallsign: number, radioCallsignNumber: number) {
|
||||
setAdvacedOptions(this.ID, isTanker, isAWACS, TACANChannel, TACANXY, TACANcallsign, radioFrequency, radioCallsign, radioCallsignNumber);
|
||||
}
|
||||
|
||||
#onClick(e: any) {
|
||||
this.#timer = setTimeout(() => {
|
||||
if (!this.#preventClick) {
|
||||
@@ -383,22 +411,107 @@ export class Unit extends Marker {
|
||||
}
|
||||
|
||||
#onContextMenu(e: any) {
|
||||
var options = [
|
||||
'Attack'
|
||||
]
|
||||
var options: {[key: string]: string} = {};
|
||||
|
||||
options["Center"] = `<div id="center-map">Center map</div>`;
|
||||
|
||||
if (getUnitsManager().getSelectedUnits().length > 0 && !(getUnitsManager().getSelectedUnits().includes(this)))
|
||||
{
|
||||
options = {
|
||||
'Attack': `<div id="attack">Attack</div>`,
|
||||
'Follow': `<div id="follow">Follow</div>`,
|
||||
}
|
||||
}
|
||||
else if ((getUnitsManager().getSelectedUnits().length > 0 && (getUnitsManager().getSelectedUnits().includes(this))) || getUnitsManager().getSelectedUnits().length == 0)
|
||||
{
|
||||
if (this.getBaseData().category == "Aircraft")
|
||||
{
|
||||
options["Refuel"] = `<div id="refuel">Refuel</div>`; // TODO Add some way of knowing which aircraft can AAR
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(options).length > 0)
|
||||
{
|
||||
getMap().showUnitContextMenu(e);
|
||||
getMap().getUnitContextMenu().setOptions(options, (option: string) => {
|
||||
getMap().hideUnitContextMenu();
|
||||
this.#executeAction(option);
|
||||
this.#executeAction(e, option);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#executeAction(action: string) {
|
||||
#executeAction(e: any, action: string) {
|
||||
if (action === "Center")
|
||||
getMap().centerOnUnit(this.ID);
|
||||
if (action === "Attack")
|
||||
getUnitsManager().selectedUnitsAttackUnit(this.ID);
|
||||
else if (action === "Refuel")
|
||||
getUnitsManager().selectedUnitsRefuel();
|
||||
else if (action === "Follow")
|
||||
this.#showFollowOptions(e);
|
||||
}
|
||||
|
||||
#showFollowOptions(e: any) {
|
||||
var options: {[key: string]: string} = {};
|
||||
|
||||
options = {
|
||||
'Trail': `<div id="trail">Trail</div>`,
|
||||
'Echelon (LH)': `<div id="echelon-lh">Echelon (left)</div>`,
|
||||
'Echelon (RH)': `<div id="echelon-rh">Echelon (right)</div>`,
|
||||
'Line abreast (LH)': `<div id="line-abreast">Line abreast (left)</div>`,
|
||||
'Line abreast (RH)': `<div id="line-abreast">Line abreast (right)</div>`,
|
||||
'Front': `<div id="front">In front</div>`,
|
||||
'Custom': `<div id="custom">Custom</div>`
|
||||
}
|
||||
|
||||
getMap().getUnitContextMenu().setOptions(options, (option: string) => {
|
||||
getMap().hideUnitContextMenu();
|
||||
this.#applyFollowOptions(option);
|
||||
});
|
||||
getMap().showUnitContextMenu(e);
|
||||
}
|
||||
|
||||
#applyFollowOptions(action: string)
|
||||
{
|
||||
if (action === "Custom")
|
||||
{
|
||||
document.getElementById("custom-formation-dialog")?.classList.remove("hide");
|
||||
getMap().getUnitContextMenu().setCustomFormationCallback((offset: {x: number, y: number, z: number}) => {
|
||||
getUnitsManager().selectedUnitsFollowUnit(this.ID, offset);
|
||||
})
|
||||
}
|
||||
else {
|
||||
// X: front-rear, positive front
|
||||
// Y: top-bottom, positive top
|
||||
// Z: left-right, positive right
|
||||
|
||||
var offset = {"x": 0, "y": 0, "z": 0};
|
||||
if (action == "Trail")
|
||||
{
|
||||
offset.x = -50; offset.y = -30; offset.z = 0;
|
||||
}
|
||||
else if (action == "Echelon (LH)")
|
||||
{
|
||||
offset.x = -50; offset.y = -10; offset.z = -50;
|
||||
}
|
||||
else if (action == "Echelon (RH)")
|
||||
{
|
||||
offset.x = -50; offset.y = -10; offset.z = 50;
|
||||
}
|
||||
else if (action == "Line abreast (RH)")
|
||||
{
|
||||
offset.x = 0; offset.y = 0; offset.z = 50;
|
||||
}
|
||||
else if (action == "Line abreast (LH)")
|
||||
{
|
||||
offset.x = 0; offset.y = 0; offset.z = -50;
|
||||
}
|
||||
else if (action == "Front")
|
||||
{
|
||||
offset.x = 100; offset.y = 0; offset.z = 0;
|
||||
}
|
||||
getUnitsManager().selectedUnitsFollowUnit(this.ID, offset);
|
||||
}
|
||||
}
|
||||
|
||||
#updateMarker() {
|
||||
@@ -417,6 +530,8 @@ export class Unit extends Marker {
|
||||
|
||||
element.querySelector(".unit")?.toggleAttribute("data-is-dead", !this.getBaseData().alive);
|
||||
|
||||
element.querySelector(".unit")?.setAttribute("data-state", this.getTaskData().currentState.toLowerCase());
|
||||
|
||||
var unitHeadingDiv = element.querySelector(".unit-heading");
|
||||
if (unitHeadingDiv != null)
|
||||
unitHeadingDiv.innerHTML = String(Math.floor(rad2deg(this.getFlightData().heading)));
|
||||
@@ -469,6 +584,9 @@ export class Unit extends Marker {
|
||||
points.push(new LatLng(destination.lat, destination.lng));
|
||||
this.#pathPolyline.setLatLngs(points);
|
||||
}
|
||||
|
||||
if (points.length == 1)
|
||||
this.#clearPath();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,10 +642,10 @@ export class Aircraft extends AirUnit {
|
||||
|
||||
getMarkerHTML()
|
||||
{
|
||||
return `<div class="unit" data-object="unit-aircraft" data-status="" data-coalition="${this.getMissionData().coalition}">
|
||||
return `<div class="unit" data-object="unit-aircraft" data-coalition="${this.getMissionData().coalition}">
|
||||
<div class="unit-selected-spotlight"></div>
|
||||
<div class="unit-marker-border"></div>
|
||||
<div class="unit-status"></div>
|
||||
<div class="unit-state"></div>
|
||||
<div class="unit-vvi" data-rotate-to-heading></div>
|
||||
<div class="unit-hotgroup">
|
||||
<div class="unit-hotgroup-id"></div>
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { LatLng, LatLngBounds } from "leaflet";
|
||||
import { getMap, getUnitDataTable } from "..";
|
||||
import { getInfoPopup, getMap, getUnitDataTable } from "..";
|
||||
import { Unit } from "./unit";
|
||||
import { cloneUnit } from "../server/server";
|
||||
import { IDLE, MOVE_UNIT } from "../map/map";
|
||||
import { keyEventWasInInput } from "../other/utils";
|
||||
|
||||
export class UnitsManager {
|
||||
#units: { [ID: number]: Unit };
|
||||
#copiedUnits: Unit[];
|
||||
#selectionEventDisabled: boolean = false;
|
||||
#pasteDisabled: boolean = false;
|
||||
|
||||
constructor() {
|
||||
this.#units = {};
|
||||
@@ -21,6 +23,24 @@ export class UnitsManager {
|
||||
document.addEventListener('deleteSelectedUnits', () => this.selectedUnitsDelete() )
|
||||
}
|
||||
|
||||
getSelectableAircraft() {
|
||||
|
||||
const units = this.getUnits();
|
||||
|
||||
return Object.keys( units ).reduce( ( acc:{[key:number]: Unit}, unitId:any ) => {
|
||||
|
||||
const baseData = units[ unitId ].getBaseData();
|
||||
|
||||
if ( baseData.category === "Aircraft" && baseData.alive === true ) {
|
||||
acc[ unitId ] = units[ unitId ];
|
||||
}
|
||||
|
||||
return acc;
|
||||
|
||||
}, {});
|
||||
|
||||
}
|
||||
|
||||
getUnits() {
|
||||
return this.#units;
|
||||
}
|
||||
@@ -174,6 +194,7 @@ export class UnitsManager {
|
||||
var commandedUnit = selectedUnits[idx];
|
||||
commandedUnit.addDestination(latlng);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, " new destination added");
|
||||
}
|
||||
|
||||
selectedUnitsClearDestinations() {
|
||||
@@ -191,6 +212,7 @@ export class UnitsManager {
|
||||
{
|
||||
selectedUnits[idx].landAt(latlng);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, " landing");
|
||||
}
|
||||
|
||||
selectedUnitsChangeSpeed(speedChange: string)
|
||||
@@ -218,6 +240,8 @@ export class UnitsManager {
|
||||
{
|
||||
selectedUnits[idx].setSpeed(speed);
|
||||
}
|
||||
|
||||
this.#showActionMessage(selectedUnits, `setting speed to ${speed * 1.94384} kts`);
|
||||
}
|
||||
|
||||
selectedUnitsSetAltitude(altitude: number)
|
||||
@@ -227,6 +251,7 @@ export class UnitsManager {
|
||||
{
|
||||
selectedUnits[idx].setAltitude(altitude);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `setting altitude to ${altitude / 0.3048} ft`);
|
||||
}
|
||||
|
||||
selectedUnitsSetROE(ROE: string)
|
||||
@@ -236,6 +261,7 @@ export class UnitsManager {
|
||||
{
|
||||
selectedUnits[idx].setROE(ROE);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `ROE set to ${ROE}`);
|
||||
}
|
||||
|
||||
selectedUnitsSetReactionToThreat(reactionToThreat: string)
|
||||
@@ -245,73 +271,15 @@ export class UnitsManager {
|
||||
{
|
||||
selectedUnits[idx].setReactionToThreat(reactionToThreat);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `reaction to threat set to ${reactionToThreat}`);
|
||||
}
|
||||
|
||||
selectedUnitsAttackUnit(ID: number) {
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits) {
|
||||
/* If a unit is a wingman, send the command to its leader */
|
||||
var commandedUnit = selectedUnits[idx];
|
||||
//if (selectedUnits[idx].wingman)
|
||||
//{
|
||||
// commandedUnit = this.getLeader(selectedUnits[idx].ID);
|
||||
//}
|
||||
commandedUnit.attackUnit(ID);
|
||||
}
|
||||
}
|
||||
|
||||
selectedUnitsCreateFormation(ID: number | null = null)
|
||||
{
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
if (selectedUnits.length >= 2)
|
||||
{
|
||||
if (ID == null)
|
||||
ID = selectedUnits[0].ID
|
||||
|
||||
var wingmenIDs = [];
|
||||
for (let idx in selectedUnits)
|
||||
{
|
||||
if (selectedUnits[idx].getFormationData().isWingman)
|
||||
{
|
||||
//console.log(selectedUnits[idx].unitName + " is already in a formation.");
|
||||
return;
|
||||
}
|
||||
else if (selectedUnits[idx].getFormationData().isLeader)
|
||||
{
|
||||
//console.log(selectedUnits[idx].unitName + " is already in a formation.");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO
|
||||
if (selectedUnits[idx].category !== this.getUnitByID(ID).category)
|
||||
{
|
||||
showMessage("All units must be of the same category to create a formation.");
|
||||
}
|
||||
*/
|
||||
if (selectedUnits[idx].ID != ID)
|
||||
{
|
||||
wingmenIDs.push(selectedUnits[idx].ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (wingmenIDs.length > 0)
|
||||
{
|
||||
this.getUnitByID(ID)?.setLeader(true, wingmenIDs);
|
||||
}
|
||||
else
|
||||
{
|
||||
//console.log("At least 2 units must be selected to create a formation.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
selectedUnitsUndoFormation()
|
||||
{
|
||||
for (let leader of this.getSelectedLeaders())
|
||||
{
|
||||
leader.setLeader(false);
|
||||
selectedUnits[idx].attackUnit(ID);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `attacking unit ${this.getUnitByID(ID)?.getBaseData().unitName}`);
|
||||
}
|
||||
|
||||
selectedUnitsDelete()
|
||||
@@ -321,25 +289,54 @@ export class UnitsManager {
|
||||
{
|
||||
selectedUnits[idx].delete();
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `deleted`);
|
||||
}
|
||||
|
||||
selectedUnitsRefuel()
|
||||
{
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits)
|
||||
{
|
||||
selectedUnits[idx].refuel();
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `sent to nearest tanker`);
|
||||
}
|
||||
|
||||
selectedUnitsFollowUnit(ID: number, offset: {"x": number, "y": number, "z": number}) {
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
var count = 1;
|
||||
for (let idx in selectedUnits) {
|
||||
var commandedUnit = selectedUnits[idx];
|
||||
commandedUnit.followUnit(ID, {"x": offset.x * count, "y": offset.y * count, "z": offset.z * count} );
|
||||
count++;
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `following unit ${this.getUnitByID(ID)?.getBaseData().unitName}`);
|
||||
}
|
||||
|
||||
copyUnits()
|
||||
{
|
||||
this.#copiedUnits = this.getSelectedUnits();
|
||||
this.#showActionMessage(this.#copiedUnits, `copied`);
|
||||
}
|
||||
|
||||
pasteUnits()
|
||||
{
|
||||
for (let idx in this.#copiedUnits)
|
||||
if (!this.#pasteDisabled)
|
||||
{
|
||||
var unit = this.#copiedUnits[idx];
|
||||
cloneUnit(unit.ID, getMap().getMouseCoordinates());
|
||||
for (let idx in this.#copiedUnits)
|
||||
{
|
||||
var unit = this.#copiedUnits[idx];
|
||||
cloneUnit(unit.ID, getMap().getMouseCoordinates());
|
||||
this.#showActionMessage(this.#copiedUnits, `pasted`);
|
||||
}
|
||||
this.#pasteDisabled = true;
|
||||
setTimeout(() => this.#pasteDisabled = false, 250);
|
||||
}
|
||||
}
|
||||
|
||||
#onKeyDown(event: KeyboardEvent)
|
||||
{
|
||||
if (event.key === "Delete")
|
||||
if ( !keyEventWasInInput( event ) && event.key === "Delete")
|
||||
{
|
||||
this.selectedUnitsDelete();
|
||||
}
|
||||
@@ -354,7 +351,7 @@ export class UnitsManager {
|
||||
setTimeout(() => {
|
||||
document.dispatchEvent(new CustomEvent("unitsSelection", {detail: this.getSelectedUnits()}));
|
||||
this.#selectionEventDisabled = false;
|
||||
}, 300);
|
||||
}, 100);
|
||||
this.#selectionEventDisabled = true;
|
||||
}
|
||||
}
|
||||
@@ -372,4 +369,11 @@ export class UnitsManager {
|
||||
else
|
||||
document.dispatchEvent(new CustomEvent("unitsDeselection", {detail: this.getSelectedUnits()}));
|
||||
}
|
||||
|
||||
#showActionMessage(units: Unit[], message: string) {
|
||||
if (units.length == 1)
|
||||
getInfoPopup().setText(`${units[0].getBaseData().unitName} ${message}`);
|
||||
else
|
||||
getInfoPopup().setText(`${units[0].getBaseData().unitName} and ${units.length - 1} other units ${message}`);
|
||||
}
|
||||
}
|
||||
@@ -1,106 +1,11 @@
|
||||
<div id="atc-control-panel" data-feature-switch="atc">
|
||||
<div class="ol-button" id="atc-toggle-button"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="atc-flight-list" class="atc-tool hide" data-feature-switch="atc">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Flight</th>
|
||||
<th>T/O</th>
|
||||
<th>TTG</th>
|
||||
<th>Status</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="atc-flight-list-table-body"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="atc-strip-board" data-feature-switch="atc">
|
||||
|
||||
<div class="atc-strip-board-header">
|
||||
<div class="name">Name</div>
|
||||
<div class="bearing-range">BR</div>
|
||||
<div class="target-altitude">t. Alt</div>
|
||||
<div class="current-altitude">Alt</div>
|
||||
<div class="target-speed">t. Spd</div>
|
||||
<div class="current-speed">Speed</div>
|
||||
<div class="runway">RWY</div>
|
||||
<div class="line">Line</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="atc-strip-board-arrivals" class="atc-strip-board-strips ol-panel">
|
||||
<div class="atc-strip-board-strip">
|
||||
<div class="handle"></div>
|
||||
<div class="rectangular-container">
|
||||
<div class="name">Shark 3</div>
|
||||
<div class="bearing-range">250 / 28</div>
|
||||
<div class="target-altitude">-</div>
|
||||
<div class="current-altitude">10000</div>
|
||||
<div class="target-speed">-</div>
|
||||
<div class="current-speed">421</div>
|
||||
<div class="runway">-</div>
|
||||
<div class="line">-</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="atc-strip-board-strip">
|
||||
<div class="handle"></div>
|
||||
<div class="rectangular-container">
|
||||
<div class="name">Shark 2</div>
|
||||
<div class="bearing-range">250 / 24</div>
|
||||
<div class="target-altitude">6000</div>
|
||||
<div class="current-altitude">6000</div>
|
||||
<div class="target-speed">-</div>
|
||||
<div class="current-speed">400</div>
|
||||
<div class="runway">-</div>
|
||||
<div class="line">-</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="atc-strip-board-strip">
|
||||
<div class="handle"></div>
|
||||
<div class="rectangular-container">
|
||||
<div class="name">Shark 1</div>
|
||||
<div class="bearing-range link-warning">262 / 12</div>
|
||||
<div class="target-altitude">5000</div>
|
||||
<div class="current-altitude">5100</div>
|
||||
<div class="target-speed">-</div>
|
||||
<div class="current-speed">367</div>
|
||||
<div class="runway warning">-</div>
|
||||
<div class="line">-</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="atc-strip-board-strip">
|
||||
<div class="handle"></div>
|
||||
<div class="rectangular-container">
|
||||
<div class="name">Dolphin 1</div>
|
||||
<div class="bearing-range">250 / 4</div>
|
||||
<div class="target-altitude link-warning">3000</div>
|
||||
<div class="current-altitude warning">4100</div>
|
||||
<div class="target-speed">-</div>
|
||||
<div class="current-speed">511</div>
|
||||
<div class="runway">25L</div>
|
||||
<div class="line">2nd</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="atc-strip-board-strip">
|
||||
<div class="handle"></div>
|
||||
<div class="rectangular-container">
|
||||
<div class="name">Whale 1</div>
|
||||
<div class="bearing-range">070 / 2</div>
|
||||
<div class="target-altitude">1500</div>
|
||||
<div class="current-altitude">1650</div>
|
||||
<div class="target-speed link-warning">350</div>
|
||||
<div class="current-speed warning">312</div>
|
||||
<div class="runway">25L</div>
|
||||
<div class="line">1st</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<%- include('atc/board.ejs', {
|
||||
"boardId": "strip-board-tower",
|
||||
"boardType": "tower",
|
||||
"headers": [ "Flight", "a. Alt", "alt", "a. Speed", "Speed" ]
|
||||
}) %>
|
||||
|
||||
<%- include('atc/board.ejs', {
|
||||
"boardId": "strip-board-ground",
|
||||
"boardType": "ground",
|
||||
"headers": [ "Flight", "Status", "T/O Time", "TTG" ]
|
||||
}) %>
|
||||
5
client/views/atc/addflight.ejs
Normal file
@@ -0,0 +1,5 @@
|
||||
<form class="ol-strip-board-add-flight">
|
||||
<div class="ol-auto-suggest"></div>
|
||||
<input type="text" name="unitName" placeholder="Flight search" />
|
||||
<button class="add-flight-by-click" title="Add unit via click"><img src="/images/icons/bullseye-solid.svg" /></button>
|
||||
</form>
|
||||
25
client/views/atc/board.ejs
Normal file
@@ -0,0 +1,25 @@
|
||||
<div id="<%= boardId %>" class="ol-panel ol-dialog ol-strip-board ol-draggable" data-board-type="<%= boardType %>" data-feature-switch="atc">
|
||||
|
||||
<div class="ol-dialog-close" data-on-click="closeDialog"></div>
|
||||
|
||||
<div class="ol-dialog-header">
|
||||
<h3><%= boardType %></h3>
|
||||
<div class="ol-strip-board-clock"></div>
|
||||
</div>
|
||||
|
||||
<div class="ol-dialog-content">
|
||||
<div class="ol-strip-board-headers">
|
||||
<div><!-- handles --></div>
|
||||
<% headers.forEach( header => { %>
|
||||
<div><%= header %></div>
|
||||
<% }); %>
|
||||
<div><!-- delete --></div>
|
||||
</div>
|
||||
<div class="ol-strip-board-strips ol-sortable"></div>
|
||||
</div>
|
||||
|
||||
<div class="ol-dialog-footer">
|
||||
<%- include('addflight.ejs') %>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -5,7 +5,7 @@
|
||||
<div id="app-summary">
|
||||
<h2>DCS Olympus</h2>
|
||||
<h4>Dynamic Unit Command</h4>
|
||||
<div class="app-version">Version <span class="app-version-number">v0.1.0</span></div>
|
||||
<div class="app-version">Version <span class="app-version-number">v0.2.0</span></div>
|
||||
</div>
|
||||
|
||||
<div id="legal-stuff">
|
||||
@@ -17,165 +17,175 @@
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div id="aircraft-settings-dialog" class="ol-panel ol-dialog hide" >
|
||||
|
||||
<div id="advanced-settings-dialog" class="ol-panel ol-dialog olympus-dialog-close hide">
|
||||
<div class="ol-dialog-close" data-on-click="closeDialog"></div>
|
||||
|
||||
<div class="ol-dialog-header">
|
||||
<h3>Olympus 1-1</h3>
|
||||
<h3 id="unit-name">Olympus 1-1</h3>
|
||||
</div>
|
||||
|
||||
<div class="ol-dialog-content">
|
||||
<!--
|
||||
<div class="ol-checkbox">
|
||||
<label>
|
||||
<input type="checkbox" />
|
||||
Use ECM when available
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="ol-checkbox">
|
||||
<label>
|
||||
<input type="checkbox" />
|
||||
Prohibit jettison
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="ol-checkbox">
|
||||
<label>
|
||||
<input type="checkbox" />
|
||||
Prohibit afterburner
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="ol-checkbox">
|
||||
<label>
|
||||
<input type="checkbox" />
|
||||
Prohibit A/A
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="ol-checkbox">
|
||||
<label>
|
||||
<input type="checkbox" />
|
||||
Prohibit A/G
|
||||
</label>
|
||||
</div>
|
||||
-->
|
||||
|
||||
<form>
|
||||
<div id="tanker-checkbox" class="ol-checkbox">
|
||||
<label>
|
||||
<input type="checkbox" />
|
||||
Operate as AAR tanker
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="ol-checkbox">
|
||||
<label>
|
||||
<input type="checkbox" />
|
||||
Use ECM when available
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="ol-checkbox">
|
||||
<label>
|
||||
<input type="checkbox" />
|
||||
Prohibit jettison
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="ol-checkbox">
|
||||
<label>
|
||||
<input type="checkbox" />
|
||||
Prohibit afterburner
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="ol-checkbox">
|
||||
<label>
|
||||
<input type="checkbox" />
|
||||
Prohibit A/A
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="ol-checkbox">
|
||||
<label>
|
||||
<input type="checkbox" />
|
||||
Prohibit A/G
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="ol-checkbox">
|
||||
<label>
|
||||
<input type="checkbox" />
|
||||
Enable TACAN:
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div id="AWACS-checkbox" class="ol-checkbox">
|
||||
<label>
|
||||
<input type="checkbox" />
|
||||
Operate as AWACS
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="ol-group">
|
||||
<label>A/A TACAN: </label>
|
||||
|
||||
<div class="ol-group">
|
||||
|
||||
<div class="ol-select">
|
||||
<div class="ol-select-value">40</div>
|
||||
<div class="ol-select-options">
|
||||
<div>
|
||||
<button>40</button>
|
||||
</div>
|
||||
<div>
|
||||
<button>41</button>
|
||||
</div>
|
||||
<div>
|
||||
<button>42</button>
|
||||
</div>
|
||||
<div>
|
||||
<button>43</button>
|
||||
</div>
|
||||
<div>
|
||||
<button>44</button>
|
||||
</div>
|
||||
<div>
|
||||
<button>45</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="TACAN-channel" class="ol-text-input">
|
||||
<input type="number" min="1" max="126" step="1" value="40">
|
||||
</div>
|
||||
|
||||
<div class="ol-select">
|
||||
|
||||
<div id="TACAN-XY" class="ol-select">
|
||||
<div class="ol-select-value">X</div>
|
||||
<div class="ol-select-options">
|
||||
<div>
|
||||
<button>X</button>
|
||||
</div>
|
||||
<div>
|
||||
<button>Y</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="ol-checkbox">
|
||||
<label>
|
||||
<input type="checkbox" />
|
||||
Use radio frequency:
|
||||
</label>
|
||||
|
||||
<div id="TACAN-callsign" class="ol-text-input">
|
||||
<input type="text" maxlength="3" value="TKR" style="width: 50px">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ol-group">
|
||||
<label> Radio frequency: </label>
|
||||
|
||||
<div class="ol-group">
|
||||
|
||||
<div class="ol-select">
|
||||
<div class="ol-select-value">120</div>
|
||||
<div id="radio-mhz" class="ol-text-input">
|
||||
<input type="number" min="1" max="999" step="1" value="260">
|
||||
</div>
|
||||
|
||||
<div id="radio-decimals" class="ol-select">
|
||||
<div class="ol-select-value">.000</div>
|
||||
<div class="ol-select-options">
|
||||
<div>
|
||||
<button>120</button>
|
||||
</div>
|
||||
<div>
|
||||
<button>121</button>
|
||||
</div>
|
||||
<div>
|
||||
<button>122</button>
|
||||
</div>
|
||||
<div>
|
||||
<button>123</button>
|
||||
</div>
|
||||
<div>
|
||||
<button>124</button>
|
||||
</div>
|
||||
<div>
|
||||
<button>125</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ol-select">
|
||||
<div class="ol-select-value">.750</div>
|
||||
<div class="ol-select-options">
|
||||
<div>
|
||||
<button>.000</button>
|
||||
</div>
|
||||
<div>
|
||||
<button>.250</button>
|
||||
</div>
|
||||
<div>
|
||||
<button>.500</button>
|
||||
</div>
|
||||
<div>
|
||||
<button>.750</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ol-group">
|
||||
<label> Radio callsign: </label>
|
||||
|
||||
</form>
|
||||
<div class="ol-group">
|
||||
<div id="radio-callsign" class="ol-select">
|
||||
<div class="ol-select-value"></div>
|
||||
<div class="ol-select-options">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label>
|
||||
-
|
||||
</label>
|
||||
|
||||
<div id="radio-callsign-number" class="ol-text-input">
|
||||
<input type="number" min="1" max="999" step="1" value="1">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ol-dialog-footer">
|
||||
|
||||
<div class="ol-dialog-footer ol-group">
|
||||
<button class="ol-button-apply" data-on-click="applyAdvancedSettings">Apply</button>
|
||||
<button class="ol-button-close" data-on-click="closeDialog">Close</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="custom-formation-dialog" class="ol-panel ol-dialog olympus-dialog-close hide">
|
||||
<div class="ol-dialog-close" data-on-click="closeDialog"></div>
|
||||
|
||||
<div class="ol-dialog-header">
|
||||
<h3 id="unit-name">Custom formation</h3>
|
||||
</div>
|
||||
|
||||
<div class="ol-dialog-content">
|
||||
<div class="formation-position-clock">
|
||||
<div class="clock-hand" style="top: 0px; left: 50px;"><input type="radio" id="formation-1" name="formation-position" value="1"></div>
|
||||
<div class="clock-hand" style="top: 14px; left: 14px;"><input type="radio" id="formation-2" name="formation-position" value="2"></div>
|
||||
<div class="clock-hand" style="top: 50px; left: 0px; "><input type="radio" id="formation-3" name="formation-position" value="3"></div>
|
||||
<div class="clock-hand" style="top: 86px; left: 14px;"><input type="radio" id="formation-4" name="formation-position" value="4"></div>
|
||||
<div class="clock-hand" style="top: 100px; left: 50px;"><input type="radio" id="formation-5" name="formation-position" value="5"></div>
|
||||
<div class="clock-hand" style="top: 86px; left: 86px;"><input type="radio" id="formation-6" name="formation-position" value="6" checked></div>
|
||||
<div class="clock-hand" style="top: 50px; left: 100px"><input type="radio" id="formation-7" name="formation-position" value="7"></div>
|
||||
<div class="clock-hand" style="top: 14px; left: 86px;"><input type="radio" id="formation-8" name="formation-position" value="8"></div>
|
||||
<div style="top: 50px; left: 50px;" id="reference-system"></div>
|
||||
</div>
|
||||
|
||||
<div class="ol-group">
|
||||
<label>Distance: </label>
|
||||
|
||||
<div class="ol-group">
|
||||
<div id="distance" class="ol-text-input">
|
||||
<input type="number" min="0" max="999999" step="1" value="150">
|
||||
</div>
|
||||
<label>ft</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ol-group">
|
||||
<label>Up-down: </label>
|
||||
|
||||
<div class="ol-group">
|
||||
<div id="up-down" class="ol-text-input">
|
||||
<input type="number" min="-99999" max="99999" step="1" value="30">
|
||||
</div>
|
||||
<label>ft</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ol-dialog-footer ol-group">
|
||||
<button class="ol-button-apply" data-on-click="applyCustomFormation">Apply</button>
|
||||
<button class="ol-button-close" data-on-click="closeDialog">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -33,6 +33,7 @@
|
||||
<%- include('connectionstatuspanel.ejs') %>
|
||||
<%- include('dialogs.ejs') %>
|
||||
<%- include('unitdatatable.ejs') %>
|
||||
<%- include('popups.ejs') %>
|
||||
|
||||
<% /* %>
|
||||
<%- include('log.ejs') %>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<div class="ol-select-options">
|
||||
<div id="olympus-toolbar-summary">
|
||||
<h3>Olympus</h3>
|
||||
<div class="accent-green app-version-number">v0.1.1</div>
|
||||
<div class="accent-green app-version-number">v0.2.0</div>
|
||||
</div>
|
||||
<div>
|
||||
<a href="https://www.discord.com" target="_blank">Discord</a>
|
||||
@@ -50,4 +50,13 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="atc-navbar-control" class="ol-group-container" data-feature-switch="atc">
|
||||
<div class="ol-group-header">ATC</div>
|
||||
<div class="ol-group">
|
||||
<button data-on-click="toggleElements" data-on-click-params='{"selector": "#strip-board-ground"}'>GND</button>
|
||||
<button data-on-click="toggleElements" data-on-click-params='{"selector": "#strip-board-tower"}'>TWR</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
5
client/views/popups.ejs
Normal file
@@ -0,0 +1,5 @@
|
||||
<div id="info-popup" class="ol-panel ol-popup hide">
|
||||
<div>
|
||||
<!-- Here the content of the popup will be shown -->
|
||||
</div>
|
||||
</div>
|
||||
@@ -502,9 +502,9 @@
|
||||
|
||||
<div class="example">
|
||||
|
||||
<div data-object="unit-aircraft" data-status="rtb" data-pilot="ai">
|
||||
<div data-object="unit-aircraft" data-state="rtb" data-pilot="ai">
|
||||
<div class="unit-selected-spotlight"></div>
|
||||
<div class="unit-status"></div>
|
||||
<div class="unit-state"></div>
|
||||
<div class="unit-vvi" style="height: 50px; transform:rotate(135deg);"></div>
|
||||
<div class="unit-hotgroup">
|
||||
<div class="unit-hotgroup-id">4</div>
|
||||
@@ -532,9 +532,9 @@
|
||||
|
||||
<div class="example">
|
||||
|
||||
<div data-object="unit-aircraft" data-status="rtb" data-coalition="blue" data-is-in-hotgroup data-is-selected>
|
||||
<div data-object="unit-aircraft" data-state="rtb" data-coalition="blue" data-is-in-hotgroup data-is-selected>
|
||||
<div class="unit-selected-spotlight"></div>
|
||||
<div class="unit-status"></div>
|
||||
<div class="unit-state"></div>
|
||||
<div class="unit-vvi" style="height: 50px; transform:rotate(315deg);"></div>
|
||||
<div class="unit-hotgroup">
|
||||
<div class="unit-hotgroup-id">4</div>
|
||||
@@ -561,9 +561,9 @@
|
||||
|
||||
<div class="example">
|
||||
|
||||
<div data-object="unit-aircraft" data-status="rtb" data-pilot="ai" data-coalition="red" data-is-in-hotgroup>
|
||||
<div data-object="unit-aircraft" data-state="rtb" data-pilot="ai" data-coalition="red" data-is-in-hotgroup>
|
||||
<div class="unit-selected-spotlight"></div>
|
||||
<div class="unit-status"></div>
|
||||
<div class="unit-state"></div>
|
||||
<div class="unit-vvi" style="height: 50px; transform:rotate(270deg);"></div>
|
||||
<div class="unit-hotgroup">
|
||||
<div class="unit-hotgroup-id">4</div>
|
||||
@@ -591,9 +591,9 @@
|
||||
|
||||
<div class="example">
|
||||
|
||||
<div data-object="unit-aircraft" data-status="hold" data-pilot="ai">
|
||||
<div data-object="unit-aircraft" data-state="hold" data-pilot="ai">
|
||||
<div class="unit-selected-spotlight"></div>
|
||||
<div class="unit-status"></div>
|
||||
<div class="unit-state"></div>
|
||||
<div class="unit-vvi" style="height: 50px; transform:rotate(135deg);"></div>
|
||||
<div class="unit-hotgroup">
|
||||
<div class="unit-hotgroup-id">4</div>
|
||||
@@ -621,9 +621,9 @@
|
||||
|
||||
<div class="example">
|
||||
|
||||
<div data-object="unit-aircraft" data-status="hold" data-coalition="blue" data-is-in-hotgroup data-is-selected>
|
||||
<div data-object="unit-aircraft" data-state="hold" data-coalition="blue" data-is-in-hotgroup data-is-selected>
|
||||
<div class="unit-selected-spotlight"></div>
|
||||
<div class="unit-status"></div>
|
||||
<div class="unit-state"></div>
|
||||
<div class="unit-vvi" style="height: 50px; transform:rotate(315deg);"></div>
|
||||
<div class="unit-hotgroup">
|
||||
<div class="unit-hotgroup-id">4</div>
|
||||
@@ -650,9 +650,9 @@
|
||||
|
||||
<div class="example">
|
||||
|
||||
<div data-object="unit-aircraft" data-status="hold" data-pilot="ai" data-coalition="red" data-is-in-hotgroup>
|
||||
<div data-object="unit-aircraft" data-state="hold" data-pilot="ai" data-coalition="red" data-is-in-hotgroup>
|
||||
<div class="unit-selected-spotlight"></div>
|
||||
<div class="unit-status"></div>
|
||||
<div class="unit-state"></div>
|
||||
<div class="unit-vvi" style="height: 50px; transform:rotate(280deg);"></div>
|
||||
<div class="unit-hotgroup">
|
||||
<div class="unit-hotgroup-id">4</div>
|
||||
@@ -688,9 +688,9 @@
|
||||
|
||||
<div class="example">
|
||||
|
||||
<div data-object="unit-aircraft" data-status="hold" data-pilot="ai" data-is-dead>
|
||||
<div data-object="unit-aircraft" data-state="hold" data-pilot="ai" data-is-dead>
|
||||
<div class="unit-selected-spotlight"></div>
|
||||
<div class="unit-status"></div>
|
||||
<div class="unit-state"></div>
|
||||
<div class="unit-vvi" style="height: 50px; transform:rotate(135deg);"></div>
|
||||
<div class="unit-hotgroup">
|
||||
<div class="unit-hotgroup-id">4</div>
|
||||
@@ -718,9 +718,9 @@
|
||||
|
||||
<div class="example">
|
||||
|
||||
<div data-object="unit-aircraft" data-status="hold" data-coalition="blue" data-is-in-hotgroup data-is-selected data-is-dead>
|
||||
<div data-object="unit-aircraft" data-state="hold" data-coalition="blue" data-is-in-hotgroup data-is-selected data-is-dead>
|
||||
<div class="unit-selected-spotlight"></div>
|
||||
<div class="unit-status"></div>
|
||||
<div class="unit-state"></div>
|
||||
<div class="unit-vvi" style="height: 50px; transform:rotate(315deg);"></div>
|
||||
<div class="unit-hotgroup">
|
||||
<div class="unit-hotgroup-id">4</div>
|
||||
@@ -747,9 +747,9 @@
|
||||
|
||||
<div class="example">
|
||||
|
||||
<div data-object="unit-aircraft" data-status="hold" data-pilot="ai" data-coalition="red" data-is-dead>
|
||||
<div data-object="unit-aircraft" data-state="hold" data-pilot="ai" data-coalition="red" data-is-dead>
|
||||
<div class="unit-selected-spotlight"></div>
|
||||
<div class="unit-status"></div>
|
||||
<div class="unit-state"></div>
|
||||
<div class="unit-vvi" style="height: 50px; transform:rotate(280deg);"></div>
|
||||
<div class="unit-hotgroup">
|
||||
<div class="unit-hotgroup-id">4</div>
|
||||
@@ -982,6 +982,42 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="example">
|
||||
|
||||
<div class="ol-select">
|
||||
<div class="ol-select-value">
|
||||
The selected value goes here
|
||||
</div>
|
||||
<div class="ol-select-options">
|
||||
<div>
|
||||
<button>Option 1</button>
|
||||
</div>
|
||||
<div>
|
||||
<button>Option 2</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="example">
|
||||
|
||||
<div class="ol-select" data-position="top">
|
||||
<div class="ol-select-value">
|
||||
Options go up
|
||||
</div>
|
||||
<div class="ol-select-options">
|
||||
<div>
|
||||
<button>Option 1</button>
|
||||
</div>
|
||||
<div>
|
||||
<button>Option 2</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -991,7 +1027,7 @@
|
||||
<div class="content-body">
|
||||
<div class="example">
|
||||
|
||||
<div id="airbase-contextmenu" class="ol-panel">
|
||||
<div id="airbase-contextmenu" class="ol-panel" style="position:relative;">
|
||||
<h3 id="airbase-name">Al Alhambra</h3>
|
||||
<dl id="airbase-properties" class="ol-data-grid">
|
||||
<dt>Runway 1</dt>
|
||||
@@ -1048,6 +1084,77 @@
|
||||
</div>
|
||||
|
||||
|
||||
<div id="fuel-percentage" data-percentage="45"></div>
|
||||
<div id="fuel-display">
|
||||
<div id="fuel-bar" class="highlight-coalition" data-coalition="blue" style="width:0%;"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="example">
|
||||
|
||||
<div id="unit-info-panel" class="ol-panel" style="position:relative;">
|
||||
|
||||
<div class="ol-panel-board">
|
||||
|
||||
<div id="general" class="panel-section">
|
||||
<h3 class="unit-name">Olympus 1-1</h3>
|
||||
<div class="ol-group">
|
||||
<div class="unit-label">Name</div>
|
||||
<div class="unit-control">AI Controlled</div>
|
||||
</div>
|
||||
<div id="current-task" class="pill highlight-coalition" data-coalition="blue" data-current-task="Awaiting tasking"></div>
|
||||
</div>
|
||||
|
||||
<div id="loadout-container" class="panel-section">
|
||||
|
||||
<div id="loadout">
|
||||
<div id="loadout-silhouette" style="--loadout-background-image:url('/images/units/f-15.png');"></div>
|
||||
<div id="loadout-items">
|
||||
<div data-qty="1150" data-item="30mm AP"></div>
|
||||
<div data-qty="2" data-item="AIM-9M"></div>
|
||||
<div data-qty="6" data-item="Mk-82"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="fuel-percentage" data-percentage="45"></div>
|
||||
<div id="fuel-display">
|
||||
<div id="fuel-bar" class="highlight-coalition" data-coalition="blue" style="width:0%;"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="example">
|
||||
|
||||
<div id="unit-info-panel" class="ol-panel" style="position:relative;">
|
||||
|
||||
<div class="ol-panel-board">
|
||||
|
||||
<div id="loadout-container" class="panel-section">
|
||||
|
||||
<div id="loadout">
|
||||
<div id="loadout-silhouette" style="--loadout-background-image:url('/images/units/f-15.png');"></div>
|
||||
<div id="loadout-items">
|
||||
<div data-qty="1150" data-item="30mm AP"></div>
|
||||
<div data-qty="2" data-item="AIM-9M with a really long name for no reason"></div>
|
||||
<div data-qty="6" data-item="Mk-82"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="fuel-percentage" data-percentage="45"></div>
|
||||
<div id="fuel-display">
|
||||
<div id="fuel-bar" class="highlight-coalition" data-coalition="blue" style="width:0%;"></div>
|
||||
|
||||
@@ -1,23 +1,16 @@
|
||||
<div id="unit-control-panel" class="ol-panel ol-panel-padding-lg">
|
||||
|
||||
<h3>Selected Units</h3>
|
||||
|
||||
<div id="unit-selection">
|
||||
|
||||
<div id="unit-identification">
|
||||
<div data-object="unit-aircraft">
|
||||
<div class="unit-marker"></div>
|
||||
<div class="unit-short-label" data-point="shortLabel"></div>
|
||||
</div>
|
||||
|
||||
<input id="unit-name" value="" data-point="unitName" readonly disabled />
|
||||
|
||||
<!-- <button id="edit-unit-name" data-on-click="editUnitName"></button> -->
|
||||
</div>
|
||||
|
||||
<div id="selected-units-container" class="ol-scroll">
|
||||
<div id="selected-units-container" class="ol-scrollable">
|
||||
<!-- This is where all the unit selection buttons will be shown-->
|
||||
<!-- <button class="pill highlight-coalition" data-coalition="blue" data-short-label="18">Olympus 1-1</button> -->
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div id="flight-data">
|
||||
<h4>Flight controls</h4>
|
||||
<div class="slider-container flight-control-slider" id="airspeed-slider">
|
||||
@@ -52,16 +45,19 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4>Reaction to threat</h4>
|
||||
<div id="reaction-to-threat-buttons-container" class="ol-group ol-button-box">
|
||||
<!-- This is where the reaction to threat buttons will be shown -->
|
||||
<div id="threat">
|
||||
<h4>Reaction to threat</h4>
|
||||
<div id="reaction-to-threat-buttons-container" class="ol-group ol-button-box">
|
||||
<!-- This is where the reaction to threat buttons will be shown -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<!--<button class="ol-button-settings" data-on-click="toggleElements" data-on-click-params='{"selector": "#aircraft-settings-dialog"}'>Adjust settings</button>
|
||||
Hidden unit implemented
|
||||
<hr />-->
|
||||
<div id="advanced-settings-div">
|
||||
<button id="advanced-settings-button" class="ol-button-settings" data-on-click="showAdvancedSettings">Adjust settings</button>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<button class="ol-button-warning" data-on-click="deleteSelectedUnits">Delete unit</button>
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#define nwjsFolder "C:\Users\dpass\Documents\nwjs\"
|
||||
#define version "v0.1.1-alpha"
|
||||
#define version "v0.2.0-alpha"
|
||||
|
||||
[Setup]
|
||||
AppName=DCS Olympus
|
||||
AppVerName={#version}
|
||||
AppVerName=DCS Olympus {#version}
|
||||
DefaultDirName={usersavedgames}\DCS.openbeta
|
||||
DefaultGroupName=DCSOlympus
|
||||
OutputBaseFilename=DCSOlympus_{#version}
|
||||
@@ -23,7 +23,7 @@ Source: "..\olympus.json"; DestDir: "{app}\Mods\Services\Olympus"; Flags: onlyif
|
||||
Source: "..\scripts\OlympusCommand.lua"; DestDir: "{app}\Mods\Services\Olympus\Scripts"; Flags: ignoreversion
|
||||
Source: "..\scripts\unitPayloads.lua"; DestDir: "{app}\Mods\Services\Olympus\Scripts"; Flags: ignoreversion
|
||||
;Source: "..\scripts\OlympusMission.lua"; DestDir: "{app}\Mods\Services\Olympus\Scripts"; Flags: ignoreversion
|
||||
Source: "..\scripts\mist_4_4_90.lua"; DestDir: "{app}\Mods\Services\Olympus\Scripts"; Flags: ignoreversion
|
||||
Source: "..\scripts\mist.lua"; DestDir: "{app}\Mods\Services\Olympus\Scripts"; Flags: ignoreversion
|
||||
Source: "..\mod\*"; DestDir: "{app}\Mods\Services\Olympus"; Flags: ignoreversion recursesubdirs;
|
||||
Source: "..\bin\*.dll"; DestDir: "{app}\Mods\Services\Olympus\bin"; Flags: ignoreversion;
|
||||
Source: "..\client\bin\*"; DestDir: "{app}\Mods\Services\Olympus\client\bin"; Flags: ignoreversion;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
local version = "v0.1.1-alpha"
|
||||
local version = "v0.2.0-alpha"
|
||||
|
||||
local debug = false
|
||||
|
||||
@@ -38,7 +38,7 @@ end
|
||||
function Olympus.getUnitByID(ID)
|
||||
for name, table in pairs(mist.DBs.unitsByName) do
|
||||
local unit = Unit.getByName(name)
|
||||
if unit and unit:getObjectID() == ID then
|
||||
if unit and unit["getObjectID"] and unit:getObjectID() == ID then
|
||||
return unit
|
||||
end
|
||||
end
|
||||
@@ -79,6 +79,18 @@ function Olympus.buildEnrouteTask(options)
|
||||
}
|
||||
}
|
||||
end
|
||||
-- Start being an active tanker
|
||||
elseif options['id'] == 'Tanker' then
|
||||
task = {
|
||||
id = 'Tanker',
|
||||
params = {},
|
||||
}
|
||||
-- Start being an active AWACS
|
||||
elseif options['id'] == 'AWACS' then
|
||||
task = {
|
||||
id = 'AWACS',
|
||||
params = {},
|
||||
}
|
||||
end
|
||||
return task
|
||||
end
|
||||
@@ -86,18 +98,44 @@ end
|
||||
-- Builds a valid task depending on the provided options
|
||||
function Olympus.buildTask(options)
|
||||
local task = nil
|
||||
-- Engage specific target by ID. Checks if target exists.
|
||||
if options['id'] == 'FollowUnit' and options['leaderID'] and options['offset'] then
|
||||
local leader = Olympus.getUnitByID(options['leaderID'])
|
||||
if leader and leader:isExist() then
|
||||
|
||||
if (Olympus.isArray(options)) then
|
||||
local tasks = {}
|
||||
for idx, subOptions in pairs(options) do
|
||||
tasks[idx] = Olympus.buildTask(subOptions) or Olympus.buildEnrouteTask(subOptions)
|
||||
end
|
||||
task = {
|
||||
id = 'ComboTask',
|
||||
params = {
|
||||
tasks = tasks
|
||||
}
|
||||
}
|
||||
Olympus.debug(Olympus.serializeTable(task), 30)
|
||||
else
|
||||
if options['id'] == 'FollowUnit' and options['leaderID'] and options['offset'] then
|
||||
local leader = Olympus.getUnitByID(options['leaderID'])
|
||||
if leader and leader:isExist() then
|
||||
task = {
|
||||
id = 'Follow',
|
||||
params = {
|
||||
groupId = leader:getGroup():getID(),
|
||||
pos = options['offset'],
|
||||
lastWptIndexFlag = false,
|
||||
lastWptIndex = 1
|
||||
}
|
||||
}
|
||||
end
|
||||
elseif options['id'] == 'Refuel' then
|
||||
task = {
|
||||
id = 'Follow',
|
||||
params = {
|
||||
groupId = leader:getGroup():getID(),
|
||||
pos = options['offset'],
|
||||
lastWptIndexFlag = false,
|
||||
lastWptIndex = 1
|
||||
}
|
||||
id = 'Refueling',
|
||||
params = {}
|
||||
}
|
||||
elseif options['id'] == 'Orbit' then
|
||||
task = {
|
||||
id = 'Orbit',
|
||||
params = {
|
||||
pattern = options['pattern'] or "Circle"
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
@@ -253,6 +291,7 @@ function Olympus.spawnAircraft(coalition, unitType, lat, lng, spawnOptions)
|
||||
["payload"] =
|
||||
{
|
||||
["pylons"] = payload,
|
||||
["fuel"] = 999999,
|
||||
["flare"] = 60,
|
||||
["ammo_type"] = 1,
|
||||
["chaff"] = 60,
|
||||
@@ -341,8 +380,13 @@ function Olympus.delete(ID, lat, lng)
|
||||
Olympus.debug("Olympus.delete " .. ID, 2)
|
||||
local unit = Olympus.getUnitByID(ID)
|
||||
if unit then
|
||||
unit:destroy();
|
||||
Olympus.debug("Olympus.delete completed successfully", 2)
|
||||
if unit:getPlayerName() then
|
||||
trigger.action.explosion(unit:getPoint() , 250 ) --consider replacing with forcibly deslotting the player, however this will work for now
|
||||
Olympus.debug("Olympus.delete completed successfully", 2)
|
||||
else
|
||||
unit:destroy(); --works for AI units not players
|
||||
Olympus.debug("Olympus.delete completed successfully", 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -351,6 +395,7 @@ function Olympus.setTask(ID, taskOptions)
|
||||
local unit = Olympus.getUnitByID(ID)
|
||||
if unit then
|
||||
local task = Olympus.buildTask(taskOptions);
|
||||
Olympus.debug("Olympus.setTask " .. Olympus.serializeTable(task), 20)
|
||||
if task then
|
||||
unit:getGroup():getController():setTask(task)
|
||||
Olympus.debug("Olympus.setTask completed successfully", 2)
|
||||
@@ -377,7 +422,7 @@ function Olympus.setCommand(ID, command)
|
||||
end
|
||||
|
||||
function Olympus.setOption(ID, optionID, optionValue)
|
||||
Olympus.debug("Olympus.setCommand " .. ID .. " " .. optionID .. " " .. optionValue, 2)
|
||||
Olympus.debug("Olympus.setOption " .. ID .. " " .. optionID .. " " .. optionValue, 2)
|
||||
local unit = Olympus.getUnitByID(ID)
|
||||
if unit then
|
||||
unit:getGroup():getController():setOption(optionID, optionValue)
|
||||
@@ -417,6 +462,16 @@ function Olympus.serializeTable(val, name, skipnewlines, depth)
|
||||
return tmp
|
||||
end
|
||||
|
||||
function Olympus.isArray(t)
|
||||
local i = 0
|
||||
for _ in pairs(t) do
|
||||
i = i + 1
|
||||
if t[i] == nil then return false end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function Olympus.setMissionData(arg, time)
|
||||
local missionData = {}
|
||||
|
||||
@@ -436,40 +491,42 @@ function Olympus.setMissionData(arg, time)
|
||||
local startIndex = Olympus.groupIndex
|
||||
local endIndex = startIndex + Olympus.groupStep
|
||||
local index = 0
|
||||
for groupName, gp in pairs(mist.DBs.groupsByName) do
|
||||
index = index + 1
|
||||
if index > startIndex then
|
||||
if groupName ~= nil then
|
||||
local group = Group.getByName(groupName)
|
||||
if group ~= nil then
|
||||
local controller = group:getController()
|
||||
for index, unit in pairs(group:getUnits()) do
|
||||
local table = {}
|
||||
table["targets"] = {}
|
||||
table["targets"]["visual"] = controller:getDetectedTargets(1)
|
||||
table["targets"]["radar"] = controller:getDetectedTargets(4)
|
||||
table["targets"]["rwr"] = controller:getDetectedTargets(16)
|
||||
table["targets"]["other"] = controller:getDetectedTargets(2, 8, 32)
|
||||
if mist ~= nil and mist.DBs ~= nil and mist.DBs.groupsByName ~= nil then
|
||||
for groupName, gp in pairs(mist.DBs.groupsByName) do
|
||||
index = index + 1
|
||||
if index > startIndex then
|
||||
if groupName ~= nil then
|
||||
local group = Group.getByName(groupName)
|
||||
if group ~= nil then
|
||||
local controller = group:getController()
|
||||
for index, unit in pairs(group:getUnits()) do
|
||||
local table = {}
|
||||
table["targets"] = {}
|
||||
table["targets"]["visual"] = controller:getDetectedTargets(1)
|
||||
table["targets"]["radar"] = controller:getDetectedTargets(4)
|
||||
table["targets"]["rwr"] = controller:getDetectedTargets(16)
|
||||
table["targets"]["other"] = controller:getDetectedTargets(2, 8, 32)
|
||||
|
||||
table["hasTask"] = controller:hasTask()
|
||||
|
||||
table["ammo"] = unit:getAmmo()
|
||||
table["fuel"] = unit:getFuel()
|
||||
table["life"] = unit:getLife() / unit:getLife0()
|
||||
unitsData[unit:getObjectID()] = table
|
||||
table["hasTask"] = controller:hasTask()
|
||||
|
||||
table["ammo"] = unit:getAmmo()
|
||||
table["fuel"] = unit:getFuel()
|
||||
table["life"] = unit:getLife() / unit:getLife0()
|
||||
unitsData[unit:getObjectID()] = table
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if index >= endIndex then
|
||||
break
|
||||
end
|
||||
end
|
||||
if index >= endIndex then
|
||||
break
|
||||
if index ~= endIndex then
|
||||
Olympus.groupIndex = 0
|
||||
else
|
||||
Olympus.groupIndex = endIndex
|
||||
end
|
||||
end
|
||||
if index ~= endIndex then
|
||||
Olympus.groupIndex = 0
|
||||
else
|
||||
Olympus.groupIndex = endIndex
|
||||
end
|
||||
|
||||
-- Airbases data
|
||||
local base = world.getAirbases()
|
||||
@@ -496,6 +553,10 @@ function Olympus.setMissionData(arg, time)
|
||||
|
||||
local mission = {}
|
||||
mission.theatre = env.mission.theatre
|
||||
mission.elapsedTime = DCS.getRealTime()
|
||||
mission.time = mist.time.getDHMS(timer.getAbsTime())
|
||||
mission.startTime = env.mission.start_time
|
||||
mission.date = env.mission.date
|
||||
|
||||
-- Assemble missionData table
|
||||
missionData["bullseyes"] = bullseyes
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
local version = 'v0.1.1-alpha'
|
||||
local version = 'v0.2.0-alpha'
|
||||
|
||||
Olympus = {}
|
||||
Olympus.OlympusDLL = nil
|
||||
|
||||
@@ -26,5 +26,4 @@ protected:
|
||||
void createHoldingPattern();
|
||||
bool updateActivePath(bool looping);
|
||||
void goToDestination(wstring enrouteTask = L"nil");
|
||||
void taskWingmen();
|
||||
};
|
||||
@@ -103,13 +103,35 @@ public:
|
||||
void pushActivePathBack(Coords newActivePathBack);
|
||||
void popActivePathFront();
|
||||
void setTargetID(int newTargetID) { targetID = newTargetID; addMeasure(L"targetID", json::value(newTargetID));}
|
||||
void setIsTanker(bool newIsTanker) { isTanker = newIsTanker; addMeasure(L"isTanker", json::value(newIsTanker));}
|
||||
void setIsAWACS(bool newIsAWACS) { isAWACS = newIsAWACS; addMeasure(L"isAWACS", json::value(newIsAWACS));}
|
||||
void setTACANOn(bool newTACANOn);
|
||||
void setTACANChannel(int newTACANChannel);
|
||||
void setTACANXY(wstring newTACANXY);
|
||||
void setTACANCallsign(wstring newTACANCallsign);
|
||||
void setTACAN();
|
||||
void setRadioOn(bool newRadioOn);
|
||||
void setRadioFrequency(int newRadioFrequency);
|
||||
void setRadioCallsign(int newRadioCallsign);
|
||||
void setRadioCallsignNumber(int newRadioCallsignNumber);
|
||||
void setRadio();
|
||||
wstring getCurrentTask() { return currentTask; }
|
||||
virtual double getTargetSpeed() { return targetSpeed; };
|
||||
virtual double getTargetAltitude() { return targetAltitude; };
|
||||
Coords getActiveDestination() { return activeDestination; }
|
||||
list<Coords> getActivePath() { return activePath; }
|
||||
int getTargetID() { return targetID; }
|
||||
|
||||
bool getIsTanker() { return isTanker; }
|
||||
bool getIsAWACS() { return isAWACS; }
|
||||
bool getTACANOn() { return TACANOn; }
|
||||
int getTACANChannel() { return TACANChannel; }
|
||||
wstring getTACANXY() { return TACANXY; }
|
||||
wstring getTACANCallsign() { return TACANCallsign; }
|
||||
bool getRadioOn() { return radioOn; }
|
||||
int getRadioFrequency() { return radioFrequency; }
|
||||
int getRadioCallsign() { return radioCallsign; }
|
||||
int getRadioCallsignNumber() { return radioCallsignNumber; }
|
||||
|
||||
/********** Options data **********/
|
||||
void setROE(wstring newROE);
|
||||
void setReactionToThreat(wstring newReactionToThreat);
|
||||
@@ -147,6 +169,7 @@ protected:
|
||||
|
||||
/********** Mission data **********/
|
||||
double fuel = 0;
|
||||
double initialFuel = 0; // Used internally to detect refueling completed
|
||||
json::value ammo = json::value::null();
|
||||
json::value targets = json::value::null();
|
||||
bool hasTask = false;
|
||||
@@ -168,6 +191,16 @@ protected:
|
||||
list<Coords> activePath;
|
||||
Coords activeDestination = Coords(0);
|
||||
int targetID = NULL;
|
||||
bool isTanker = false;
|
||||
bool isAWACS = false;
|
||||
bool TACANOn = false;
|
||||
int TACANChannel = 40;
|
||||
wstring TACANXY = L"X";
|
||||
wstring TACANCallsign = L"TKR";
|
||||
bool radioOn = false;
|
||||
int radioFrequency = 260000000; // MHz
|
||||
int radioCallsign = 1;
|
||||
int radioCallsignNumber = 1;
|
||||
|
||||
/********** Options data **********/
|
||||
wstring ROE = L"";
|
||||
|
||||
@@ -22,6 +22,7 @@ void AirUnit::setState(int newState)
|
||||
{
|
||||
if (state != newState)
|
||||
{
|
||||
/* Perform any action required when LEAVING a certain state */
|
||||
switch (state) {
|
||||
case State::IDLE: {
|
||||
break;
|
||||
@@ -36,25 +37,27 @@ void AirUnit::setState(int newState)
|
||||
case State::FOLLOW: {
|
||||
break;
|
||||
}
|
||||
case State::WINGMAN: {
|
||||
if (isWingman)
|
||||
return;
|
||||
case State::LAND: {
|
||||
break;
|
||||
}
|
||||
case State::LAND: {
|
||||
case State::REFUEL: {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Perform any action required when ENTERING a certain state */
|
||||
switch (newState) {
|
||||
case State::IDLE: {
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
addMeasure(L"currentState", json::value(L"Idle"));
|
||||
break;
|
||||
}
|
||||
case State::REACH_DESTINATION: {
|
||||
resetActiveDestination();
|
||||
addMeasure(L"currentState", json::value(L"Reach destination"));
|
||||
break;
|
||||
}
|
||||
case State::ATTACK: {
|
||||
@@ -64,19 +67,26 @@ void AirUnit::setState(int newState)
|
||||
clearActivePath();
|
||||
pushActivePathFront(targetPosition);
|
||||
resetActiveDestination();
|
||||
addMeasure(L"currentState", json::value(L"Attack"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case State::FOLLOW: {
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::WINGMAN: {
|
||||
resetActiveDestination();
|
||||
addMeasure(L"currentState", json::value(L"Follow"));
|
||||
break;
|
||||
}
|
||||
case State::LAND: {
|
||||
resetActiveDestination();
|
||||
addMeasure(L"currentState", json::value(L"Land"));
|
||||
break;
|
||||
}
|
||||
case State::REFUEL: {
|
||||
initialFuel = fuel;
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
addMeasure(L"currentState", json::value(L"Refuel"));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -170,63 +180,50 @@ void AirUnit::goToDestination(wstring enrouteTask)
|
||||
log(unitName + L" error, no active destination!");
|
||||
}
|
||||
|
||||
void AirUnit::taskWingmen()
|
||||
{
|
||||
switch (state) {
|
||||
case State::IDLE:
|
||||
case State::REACH_DESTINATION:
|
||||
case State::ATTACK:{
|
||||
int idx = 1;
|
||||
for (auto const& wingman : wingmen)
|
||||
{
|
||||
if (!wingman->getIsWingman())
|
||||
{
|
||||
wingman->setIsWingman(true);
|
||||
wingman->setLeader(this);
|
||||
}
|
||||
|
||||
if (wingman->getFormation().compare(formation) != 0)
|
||||
{
|
||||
wingman->resetTask();
|
||||
wingman->setFormation(formation);
|
||||
if (formation.compare(L"Line abreast") == 0)
|
||||
wingman->setFormationOffset(Offset(0 * idx, 0 * idx, 1852 * idx));
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AirUnit::AIloop()
|
||||
{
|
||||
/* State machine */
|
||||
switch (state) {
|
||||
case State::IDLE: {
|
||||
wstring enrouteTask = L"nil";
|
||||
currentTask = L"Idle";
|
||||
|
||||
if (activeDestination == NULL || !hasTask)
|
||||
if (!hasTask)
|
||||
{
|
||||
createHoldingPattern();
|
||||
setActiveDestination();
|
||||
goToDestination(enrouteTask);
|
||||
std::wostringstream taskSS;
|
||||
if (isTanker) {
|
||||
taskSS << "{ [1] = { id = 'Tanker' }, [2] = { id = 'Orbit', pattern = 'Race-Track' } }";
|
||||
}
|
||||
else if (isAWACS) {
|
||||
taskSS << "{ [1] = { id = 'AWACS' }, [2] = { id = 'Orbit', pattern = 'Circle' } }";
|
||||
}
|
||||
else {
|
||||
taskSS << "{ id = 'Orbit', pattern = 'Circle' }";
|
||||
}
|
||||
Command* command = dynamic_cast<Command*>(new SetTask(ID, taskSS.str()));
|
||||
scheduler->appendCommand(command);
|
||||
hasTask = true;
|
||||
}
|
||||
else {
|
||||
if (isDestinationReached() && updateActivePath(true) && setActiveDestination())
|
||||
goToDestination(enrouteTask);
|
||||
}
|
||||
|
||||
if (isLeader)
|
||||
taskWingmen();
|
||||
break;
|
||||
}
|
||||
case State::REACH_DESTINATION: {
|
||||
wstring enrouteTask = L"nil";
|
||||
currentTask = L"Reaching destination";
|
||||
wstring enrouteTask = L"";
|
||||
bool looping = false;
|
||||
|
||||
if (isTanker)
|
||||
{
|
||||
enrouteTask = L"{ id = 'Tanker' }";
|
||||
currentTask = L"Tanker";
|
||||
}
|
||||
else if (isAWACS)
|
||||
{
|
||||
enrouteTask = L"{ id = 'AWACS' }";
|
||||
currentTask = L"AWACS";
|
||||
}
|
||||
else
|
||||
{
|
||||
enrouteTask = L"nil";
|
||||
currentTask = L"Reaching destination";
|
||||
}
|
||||
|
||||
if (activeDestination == NULL || !hasTask)
|
||||
{
|
||||
@@ -235,23 +232,18 @@ void AirUnit::AIloop()
|
||||
}
|
||||
else {
|
||||
if (isDestinationReached()) {
|
||||
if (updateActivePath(false) && setActiveDestination())
|
||||
if (updateActivePath(looping) && setActiveDestination())
|
||||
goToDestination(enrouteTask);
|
||||
else {
|
||||
setState(State::IDLE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isLeader)
|
||||
taskWingmen();
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case State::LAND: {
|
||||
wstring enrouteTask = L"{" "id = 'land' }";
|
||||
wstring enrouteTask = L"{ id = 'Land' }";
|
||||
currentTask = L"Landing";
|
||||
|
||||
if (activeDestination == NULL)
|
||||
@@ -259,10 +251,6 @@ void AirUnit::AIloop()
|
||||
setActiveDestination();
|
||||
goToDestination(enrouteTask);
|
||||
}
|
||||
|
||||
if (isLeader)
|
||||
taskWingmen();
|
||||
|
||||
break;
|
||||
}
|
||||
case State::ATTACK: {
|
||||
@@ -282,49 +270,34 @@ void AirUnit::AIloop()
|
||||
wstring enrouteTask = enrouteTaskSS.str();
|
||||
currentTask = L"Attacking " + getTargetName();
|
||||
|
||||
if (activeDestination == NULL || !hasTask)
|
||||
if (!hasTask)
|
||||
{
|
||||
setActiveDestination();
|
||||
goToDestination(enrouteTask);
|
||||
}
|
||||
else {
|
||||
if (isDestinationReached()) {
|
||||
if (updateActivePath(false) && setActiveDestination())
|
||||
goToDestination(enrouteTask);
|
||||
else {
|
||||
setState(State::IDLE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isLeader)
|
||||
taskWingmen();
|
||||
|
||||
break;
|
||||
}
|
||||
case State::FOLLOW: {
|
||||
/* TODO */
|
||||
setState(State::IDLE);
|
||||
break;
|
||||
}
|
||||
case State::WINGMAN: {
|
||||
/* In the WINGMAN state, the unit relinquishes control to the leader */
|
||||
clearActivePath();
|
||||
activeDestination = Coords(NULL);
|
||||
if (leader == nullptr || !leader->getAlive())
|
||||
{
|
||||
this->setFormation(L"");
|
||||
this->setIsWingman(false);
|
||||
|
||||
/* If the target is not alive (either not set or was destroyed) go back to IDLE */
|
||||
if (!isTargetAlive()) {
|
||||
setState(State::IDLE);
|
||||
break;
|
||||
}
|
||||
|
||||
currentTask = L"Following " + getTargetName();
|
||||
|
||||
Unit* target = unitsManager->getUnit(targetID);
|
||||
if (!hasTask) {
|
||||
if (leader != nullptr && leader->getAlive() && formationOffset != NULL)
|
||||
if (target != nullptr && target->getAlive() && formationOffset != NULL)
|
||||
{
|
||||
std::wostringstream taskSS;
|
||||
taskSS << "{"
|
||||
<< "id = 'FollowUnit'" << ", "
|
||||
<< "leaderID = " << leader->getID() << ","
|
||||
<< "leaderID = " << target->getID() << ","
|
||||
<< "offset = {"
|
||||
<< "x = " << formationOffset.x << ","
|
||||
<< "y = " << formationOffset.y << ","
|
||||
@@ -338,7 +311,26 @@ void AirUnit::AIloop()
|
||||
}
|
||||
break;
|
||||
}
|
||||
case State::REFUEL: {
|
||||
currentTask = L"Refueling";
|
||||
|
||||
if (!hasTask) {
|
||||
if (fuel <= initialFuel) {
|
||||
std::wostringstream taskSS;
|
||||
taskSS << "{"
|
||||
<< "id = 'Refuel'"
|
||||
<< "}";
|
||||
Command* command = dynamic_cast<Command*>(new SetTask(ID, taskSS.str()));
|
||||
scheduler->appendCommand(command);
|
||||
hasTask = true;
|
||||
}
|
||||
else {
|
||||
setState(State::IDLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
addMeasure(L"currentTask", json::value(currentTask));
|
||||
}
|
||||
|
||||
@@ -142,14 +142,34 @@ void Scheduler::handleRequest(wstring key, json::value value)
|
||||
unit->setTargetID(targetID);
|
||||
unit->setState(State::ATTACK);
|
||||
}
|
||||
else if (key.compare(L"stopAttack") == 0)
|
||||
else if (key.compare(L"followUnit") == 0)
|
||||
{
|
||||
int ID = value[L"ID"].as_integer();
|
||||
int targetID = value[L"targetID"].as_integer();
|
||||
int offsetX = value[L"offsetX"].as_integer();
|
||||
int offsetY = value[L"offsetY"].as_integer();
|
||||
int offsetZ = value[L"offsetZ"].as_integer();
|
||||
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
Unit* target = unitsManager->getUnit(targetID);
|
||||
|
||||
wstring unitName;
|
||||
wstring targetName;
|
||||
|
||||
if (unit != nullptr)
|
||||
unit->setState(State::REACH_DESTINATION);
|
||||
unitName = unit->getUnitName();
|
||||
else
|
||||
return;
|
||||
|
||||
if (target != nullptr)
|
||||
targetName = target->getUnitName();
|
||||
else
|
||||
return;
|
||||
|
||||
log(L"Unit " + unitName + L" following unit " + targetName);
|
||||
unit->setFormationOffset(Offset(offsetX, offsetY, offsetZ));
|
||||
unit->setTargetID(targetID);
|
||||
unit->setState(State::FOLLOW);
|
||||
}
|
||||
else if (key.compare(L"changeSpeed") == 0)
|
||||
{
|
||||
@@ -250,6 +270,36 @@ void Scheduler::handleRequest(wstring key, json::value value)
|
||||
int ID = value[L"ID"].as_integer();
|
||||
unitsManager->deleteUnit(ID);
|
||||
}
|
||||
else if (key.compare(L"refuel") == 0)
|
||||
{
|
||||
int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
unit->setState(State::REFUEL);
|
||||
}
|
||||
else if (key.compare(L"setAdvancedOptions") == 0)
|
||||
{
|
||||
int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
if (unit != nullptr)
|
||||
{
|
||||
unit->setIsTanker(value[L"isTanker"].as_bool());
|
||||
unit->setIsAWACS(value[L"isAWACS"].as_bool());
|
||||
|
||||
unit->setTACANOn(true); // TODO Remove
|
||||
unit->setTACANChannel(value[L"TACANChannel"].as_number().to_int32());
|
||||
unit->setTACANXY(value[L"TACANXY"].as_string());
|
||||
unit->setTACANCallsign(value[L"TACANCallsign"].as_string());
|
||||
unit->setTACAN();
|
||||
|
||||
unit->setRadioOn(true); // TODO Remove
|
||||
unit->setRadioFrequency(value[L"radioFrequency"].as_number().to_int32());
|
||||
unit->setRadioCallsign(value[L"radioCallsign"].as_number().to_int32());
|
||||
unit->setRadioCallsignNumber(value[L"radioCallsignNumber"].as_number().to_int32());
|
||||
unit->setRadio();
|
||||
|
||||
unit->resetActiveDestination();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log(L"Unknown command: " + key);
|
||||
|
||||
@@ -47,7 +47,7 @@ void registerLuaFunctions(lua_State* L)
|
||||
return;
|
||||
}
|
||||
|
||||
executeLuaScript(L, modLocation + "\\Scripts\\mist_4_4_90.lua");
|
||||
executeLuaScript(L, modLocation + "\\Scripts\\mist.lua");
|
||||
executeLuaScript(L, modLocation + "\\Scripts\\OlympusCommand.lua");
|
||||
executeLuaScript(L, modLocation + "\\Scripts\\unitPayloads.lua");
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ Unit::Unit(json::value json, int ID) :
|
||||
ID(ID)
|
||||
{
|
||||
log("Creating unit with ID: " + to_string(ID));
|
||||
addMeasure(L"currentState", json::value(L"Idle"));
|
||||
}
|
||||
|
||||
Unit::~Unit()
|
||||
@@ -134,7 +135,7 @@ json::value Unit::getData(long long time)
|
||||
|
||||
/********** Task data **********/
|
||||
json[L"taskData"] = json::value::object();
|
||||
for (auto key : { L"currentTask", L"targetSpeed", L"targetAltitude", L"activePath" })
|
||||
for (auto key : { L"currentState", L"currentTask", L"targetSpeed", L"targetAltitude", L"activePath", L"isTanker", L"isAWACS", L"TACANChannel", L"TACANXY", L"TACANCallsign", L"radioFrequency", L"radioCallsign", L"radioCallsignNumber"})
|
||||
{
|
||||
if (measures.find(key) != measures.end() && measures[key]->getTime() > time)
|
||||
json[L"taskData"][key] = measures[key]->getValue();
|
||||
@@ -346,4 +347,90 @@ void Unit::landAt(Coords loc) {
|
||||
clearActivePath();
|
||||
pushActivePathBack(loc);
|
||||
setState(State::LAND);
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::setTACANOn(bool newTACANOn) {
|
||||
TACANOn = newTACANOn;
|
||||
addMeasure(L"TACANOn", json::value(newTACANOn));
|
||||
}
|
||||
|
||||
void Unit::setTACANChannel(int newTACANChannel) {
|
||||
TACANChannel = newTACANChannel;
|
||||
addMeasure(L"TACANChannel", json::value(newTACANChannel));
|
||||
}
|
||||
|
||||
void Unit::setTACANXY(wstring newTACANXY) {
|
||||
TACANXY = newTACANXY;
|
||||
addMeasure(L"TACANXY", json::value(newTACANXY));
|
||||
}
|
||||
void Unit::setTACANCallsign(wstring newTACANCallsign) {
|
||||
TACANCallsign = newTACANCallsign;
|
||||
addMeasure(L"TACANCallsign", json::value(newTACANCallsign));
|
||||
}
|
||||
|
||||
void Unit::setRadioOn(bool newRadioOn) {
|
||||
radioOn = newRadioOn;
|
||||
addMeasure(L"radioOn", json::value(newRadioOn));
|
||||
}
|
||||
|
||||
void Unit::setRadioFrequency(int newRadioFrequency) {
|
||||
radioFrequency = newRadioFrequency;
|
||||
addMeasure(L"radioFrequency", json::value(newRadioFrequency));
|
||||
}
|
||||
|
||||
void Unit::setRadioCallsign(int newRadioCallsign) {
|
||||
radioCallsign = newRadioCallsign;
|
||||
addMeasure(L"radioCallsign", json::value(newRadioCallsign));
|
||||
}
|
||||
|
||||
void Unit::setRadioCallsignNumber(int newRadioCallsignNumber) {
|
||||
radioCallsignNumber = newRadioCallsignNumber;
|
||||
addMeasure(L"radioCallsignNumber", json::value(newRadioCallsignNumber));
|
||||
}
|
||||
|
||||
void Unit::setTACAN()
|
||||
{
|
||||
std::wostringstream commandSS;
|
||||
commandSS << "{"
|
||||
<< "id = 'ActivateBeacon',"
|
||||
<< "params = {"
|
||||
<< "type = " << ((TACANXY.compare(L"X") == 0)? 4: 5) << ","
|
||||
<< "system = 4,"
|
||||
<< "name = Olympus_TACAN,"
|
||||
<< "callsign = " << TACANCallsign << ", "
|
||||
<< "frequency = " << TACANChannelToFrequency(TACANChannel, TACANXY) << ","
|
||||
<< "}"
|
||||
<< "}";
|
||||
Command* command = dynamic_cast<Command*>(new SetCommand(ID, commandSS.str()));
|
||||
scheduler->appendCommand(command);
|
||||
}
|
||||
|
||||
void Unit::setRadio()
|
||||
{
|
||||
{
|
||||
std::wostringstream commandSS;
|
||||
commandSS << "{"
|
||||
<< "id = 'SetFrequency',"
|
||||
<< "params = {"
|
||||
<< "modulation = 0," // TODO Allow selection
|
||||
<< "frequency = " << radioFrequency << ","
|
||||
<< "}"
|
||||
<< "}";
|
||||
Command* command = dynamic_cast<Command*>(new SetCommand(ID, commandSS.str()));
|
||||
scheduler->appendCommand(command);
|
||||
}
|
||||
|
||||
{
|
||||
std::wostringstream commandSS;
|
||||
commandSS << "{"
|
||||
<< "id = 'SetCallsign',"
|
||||
<< "params = {"
|
||||
<< "callname = " << radioCallsign << ","
|
||||
<< "number = " << radioCallsignNumber << ","
|
||||
<< "}"
|
||||
<< "}";
|
||||
Command* command = dynamic_cast<Command*>(new SetCommand(ID, commandSS.str()));
|
||||
scheduler->appendCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,4 +8,5 @@ void DllExport LogError(lua_State* L, string message);
|
||||
void DllExport Log(lua_State* L, string message, int level);
|
||||
int DllExport dostring_in(lua_State* L, string target, string command);
|
||||
map<int, json::value> DllExport getAllUnits(lua_State* L);
|
||||
int DllExport TACANChannelToFrequency(int channel, wstring XY);
|
||||
|
||||
|
||||
@@ -94,7 +94,6 @@ exit:
|
||||
return units;
|
||||
}
|
||||
|
||||
|
||||
int dostring_in(lua_State* L, string target, string command)
|
||||
{
|
||||
lua_getglobal(L, "net");
|
||||
@@ -102,4 +101,10 @@ int dostring_in(lua_State* L, string target, string command)
|
||||
lua_pushstring(L, target.c_str());
|
||||
lua_pushstring(L, command.c_str());
|
||||
return lua_pcall(L, 2, 0, 0);
|
||||
}
|
||||
|
||||
int TACANChannelToFrequency(int channel, wstring XY)
|
||||
{
|
||||
int basef = (XY == L"X" && channel > 63) || (XY == L"Y" && channel < 64) ? 1087: 961;
|
||||
return (basef + channel) * 1000000;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#define VERSION "v0.1.1"
|
||||
#define VERSION "v0.2.0"
|
||||
#define LOG_NAME "Olympus_log.txt"
|
||||
#define REST_ADDRESS L"http://localhost:30000"
|
||||
#define REST_URI L"olympus"
|
||||
|
||||