Compare commits
7 commits
186a8b4133
...
b5071aa338
| Author | SHA1 | Date | |
|---|---|---|---|
| b5071aa338 | |||
| 255c47183d | |||
| 48aad70993 | |||
| af337ea0bf | |||
| 7d45e2f717 | |||
| f7e5bb37bf | |||
| ef1734ccd4 |
66
assets/button-stepped-border-image.svg
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="100"
|
||||
height="100"
|
||||
viewBox="0 0 100 100"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xml:space="preserve"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
sodipodi:docname="mockup.svg"
|
||||
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"><sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#999999"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="px"
|
||||
inkscape:zoom="2.7556247"
|
||||
inkscape:cx="1253.2549"
|
||||
inkscape:cy="1447.5847"
|
||||
inkscape:window-width="1703"
|
||||
inkscape:window-height="1071"
|
||||
inkscape:window-x="56"
|
||||
inkscape:window-y="50"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="g4"><inkscape:page
|
||||
x="0"
|
||||
y="0"
|
||||
width="100"
|
||||
height="100"
|
||||
id="page2"
|
||||
margin="0"
|
||||
bleed="0" /></sodipodi:namedview><defs
|
||||
id="defs1" /><g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Default Mobile"
|
||||
transform="translate(-1295.6909,-1417)"><g
|
||||
id="g7"
|
||||
inkscape:label="button-stepped"><rect
|
||||
style="fill:#ffffff;fill-opacity:0;stroke:none;stroke-width:1.58144;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
id="rect17-4-3-3"
|
||||
width="100"
|
||||
height="100"
|
||||
x="1295.6909"
|
||||
y="1417" /><rect
|
||||
style="display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:15.4123;stroke-opacity:1"
|
||||
id="rect3-9-4-86-1"
|
||||
width="75.705887"
|
||||
height="99.999954"
|
||||
x="1307.8379"
|
||||
y="1417" /><rect
|
||||
style="display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:15.6491;stroke-opacity:1"
|
||||
id="rect3-5-5-2-2"
|
||||
width="99.999886"
|
||||
height="78.049637"
|
||||
x="1295.6909"
|
||||
y="1427.9751" /></g></g></svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
69
assets/neon-border-image.svg
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="100"
|
||||
height="100"
|
||||
viewBox="0 0 100 100"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xml:space="preserve"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
sodipodi:docname="mockup.svg"
|
||||
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"><sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#999999"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="px"
|
||||
inkscape:zoom="5.1118834"
|
||||
inkscape:cx="1209.4368"
|
||||
inkscape:cy="1470.8864"
|
||||
inkscape:window-width="1703"
|
||||
inkscape:window-height="1071"
|
||||
inkscape:window-x="56"
|
||||
inkscape:window-y="50"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="g4"><inkscape:page
|
||||
x="0"
|
||||
y="0"
|
||||
width="100"
|
||||
height="100"
|
||||
id="page2"
|
||||
margin="0"
|
||||
bleed="0" /></sodipodi:namedview><defs
|
||||
id="defs1" /><g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Default Mobile"
|
||||
transform="translate(-1178,-1417)"><g
|
||||
id="g4"
|
||||
inkscape:label="neon-border-image"
|
||||
inkscape:export-filename="assets/neon-border-image.svg"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"><rect
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.58144;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
id="rect17-4-3"
|
||||
width="100"
|
||||
height="100"
|
||||
x="1178"
|
||||
y="1417" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke:#ffbf3e;stroke-width:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
d="m 1178,1419 h 100"
|
||||
id="path17-2-5"
|
||||
sodipodi:nodetypes="cc" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke:#ff4e00;stroke-width:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
d="m 1178,1423 h 100"
|
||||
id="path17-9-2-6"
|
||||
sodipodi:nodetypes="cc" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke:#8800ff;stroke-width:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
d="m 1178,1427 h 100"
|
||||
id="path17-9-6-6-2"
|
||||
sodipodi:nodetypes="cc" /></g></g></svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
|
|
@ -4,7 +4,6 @@
|
|||
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
|
||||
"features": [
|
||||
{ "type": "Feature", "properties": { "name": "Tableau de programmation" }, "geometry": { "type": "Point", "coordinates": [ -2.091304219258237, 47.541608316100941 ] } },
|
||||
{ "type": "Feature", "properties": { "name": "Tableau des shifts" }, "geometry": { "type": "Point", "coordinates": [ -2.091287266713699, 47.541705450550154 ] } },
|
||||
{ "type": "Feature", "properties": { "name": "Tableau des shifts" }, "geometry": null }
|
||||
{ "type": "Feature", "properties": { "name": "Tableau des shifts" }, "geometry": { "type": "Point", "coordinates": [ -2.091287983083753, 47.541680943841193 ] } }
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
"name": "batiments",
|
||||
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
|
||||
"features": [
|
||||
{ "type": "Feature", "properties": { "id": 1, "nom": "Batiment A" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -2.091581996371882, 47.541032945940522 ], [ -2.09151399426637, 47.541497984433285 ], [ -2.091312011285422, 47.541481979469303 ], [ -2.091326034403365, 47.541400730704773 ], [ -2.091241014242576, 47.541394942672135 ], [ -2.091251030755392, 47.541319968658911 ], [ -2.091334848934643, 47.541327974547109 ], [ -2.091346067428997, 47.541254515067628 ], [ -2.091304879528295, 47.541251918559851 ], [ -2.091309046397626, 47.541206046901102 ], [ -2.091353038921917, 47.541207940189693 ], [ -2.091375035184063, 47.541061913344244 ], [ -2.091330882395567, 47.541059965956265 ], [ -2.091335990817103, 47.541026008366721 ], [ -2.091380744596368, 47.54102704967903 ], [ -2.091381966610932, 47.541019003174263 ], [ -2.091581996371882, 47.541032945940522 ] ] ] ] } },
|
||||
{ "type": "Feature", "properties": { "id": 2, "nom": "Batiment B", "electricite-triphase": true }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -2.091630987136071, 47.541689935433055 ], [ -2.091803321239079, 47.54170457447416 ], [ -2.091796950736927, 47.541739951576218 ], [ -2.092355992350255, 47.541780954364874 ], [ -2.092339965929748, 47.54185403445365 ], [ -2.091958937782201, 47.541822011214833 ], [ -2.09193297498098, 47.54193998862457 ], [ -2.091763976376737, 47.541926005529561 ], [ -2.091756003232534, 47.541964993201951 ], [ -2.091590991200393, 47.541954999486393 ], [ -2.091630987136071, 47.541689935433055 ] ] ] ] } },
|
||||
{ "type": "Feature", "properties": { "id": 10, "nom": "Toilettes sèches" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -2.091342607190285, 47.541484412003662 ], [ -2.091438001950184, 47.541492274863295 ], [ -2.09143324403292, 47.541516949622384 ], [ -2.09133755253389, 47.541508679404679 ], [ -2.091342607190285, 47.541484412003662 ] ] ] ] } }
|
||||
{ "type": "Feature", "properties": { "id": 1, "nom": "Batiment A", "batiment": true }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -2.091581996371882, 47.541032945940522 ], [ -2.09151399426637, 47.541497984433285 ], [ -2.091312011285422, 47.541481979469303 ], [ -2.091326034403365, 47.541400730704773 ], [ -2.091241014242576, 47.541394942672135 ], [ -2.091251030755392, 47.541319968658911 ], [ -2.091334848934643, 47.541327974547109 ], [ -2.091346067428997, 47.541254515067628 ], [ -2.091304879528295, 47.541251918559851 ], [ -2.091309046397626, 47.541206046901102 ], [ -2.091353038921917, 47.541207940189693 ], [ -2.091375035184063, 47.541061913344244 ], [ -2.091330882395567, 47.541059965956265 ], [ -2.091335990817103, 47.541026008366721 ], [ -2.091380744596368, 47.54102704967903 ], [ -2.091381966610932, 47.541019003174263 ], [ -2.091581996371882, 47.541032945940522 ] ] ] ] } },
|
||||
{ "type": "Feature", "properties": { "id": 2, "nom": "Batiment B", "batiment": true, "electricite-triphase": true }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -2.091630987136071, 47.541689935433055 ], [ -2.091803321239079, 47.54170457447416 ], [ -2.091796950736927, 47.541739951576218 ], [ -2.092355992350255, 47.541780954364874 ], [ -2.092339965929748, 47.54185403445365 ], [ -2.091958937782201, 47.541822011214833 ], [ -2.09193297498098, 47.54193998862457 ], [ -2.091763976376737, 47.541926005529561 ], [ -2.091756003232534, 47.541964993201951 ], [ -2.091590991200393, 47.541954999486393 ], [ -2.091630987136071, 47.541689935433055 ] ] ] ] } },
|
||||
{ "type": "Feature", "properties": { "id": 10, "nom": "Toilettes sèches", "batiment": true }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -2.091342607190285, 47.541484412003662 ], [ -2.091438001950184, 47.541492274863295 ], [ -2.09143324403292, 47.541516949622384 ], [ -2.09133755253389, 47.541508679404679 ], [ -2.091342607190285, 47.541484412003662 ] ] ] ] } }
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@
|
|||
"name": "medic",
|
||||
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
|
||||
"features": [
|
||||
{ "type": "Feature", "properties": { "name": "Infirmerie" }, "geometry": null },
|
||||
{ "type": "Feature", "properties": { "name": "infirmerie" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -2.091966260276902, 47.541709299003671 ], [ -2.092019639165452, 47.541714403762832 ], [ -2.092031204591305, 47.541653747180767 ], [ -2.091978270526826, 47.54165014381725 ], [ -2.091966260276902, 47.541709299003671 ] ] ] } },
|
||||
{ "type": "Feature", "properties": { "name": "infirmerie" }, "geometry": null },
|
||||
{ "type": "Feature", "properties": { "name": "infirmerie" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -2.091983279274473, 47.541750296814556 ], [ -2.092011290414653, 47.541752703414282 ], [ -2.092017401936146, 47.541713510204964 ], [ -2.091990409382882, 47.54171144740365 ], [ -2.091983279274473, 47.541750296814556 ] ] ] } },
|
||||
{ "type": "Feature", "properties": { "name": "zone infirmerie" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -2.091842510161106, 47.54181195296588 ], [ -2.091847583778531, 47.541782685155603 ], [ -2.091792696462745, 47.541778014758826 ], [ -2.091786239131476, 47.54180697121209 ], [ -2.091842510161106, 47.54181195296588 ] ] ] } }
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,6 @@
|
|||
"name": "piscine",
|
||||
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
|
||||
"features": [
|
||||
{ "type": "Feature", "properties": { "id": null, "name": "Piscine" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -2.091707042517393, 47.542115661078718 ], [ -2.091903846960937, 47.542128643402442 ], [ -2.091884615256356, 47.542248080629903 ], [ -2.091687810812811, 47.542235963822122 ], [ -2.091707042517393, 47.542115661078718 ] ] ] ] } }
|
||||
{ "type": "Feature", "properties": { "id": null, "name": "Piscine", "piscine": true }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -2.091707042517393, 47.542115661078718 ], [ -2.091903846960937, 47.542128643402442 ], [ -2.091884615256356, 47.542248080629903 ], [ -2.091687810812811, 47.542235963822122 ], [ -2.091707042517393, 47.542115661078718 ] ] ] ] } }
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
"name": "wifi",
|
||||
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
|
||||
"features": [
|
||||
{ "type": "Feature", "properties": { "fixe": true }, "geometry": { "type": "Point", "coordinates": [ -2.091875157168781, 47.541822388950891 ] } },
|
||||
{ "type": "Feature", "properties": { "fixe": true }, "geometry": { "type": "Point", "coordinates": [ -2.091771851987061, 47.541790332713326 ] } },
|
||||
{ "type": "Feature", "properties": { "fixe": true }, "geometry": { "type": "Point", "coordinates": [ -2.092165078162641, 47.541781334467679 ] } }
|
||||
{ "type": "Feature", "properties": { "wifi": true, "fixe": true }, "geometry": { "type": "Point", "coordinates": [ -2.091875157168781, 47.541822388950891 ] } },
|
||||
{ "type": "Feature", "properties": { "wifi": true, "fixe": true }, "geometry": { "type": "Point", "coordinates": [ -2.091771851987061, 47.541790332713326 ] } },
|
||||
{ "type": "Feature", "properties": { "wifi": true, "fixe": true }, "geometry": { "type": "Point", "coordinates": [ -2.092165078162641, 47.541781334467679 ] } }
|
||||
]
|
||||
}
|
||||
|
|
|
|||
179
css/style.css
|
|
@ -5,12 +5,29 @@ body, html {
|
|||
|
||||
body {
|
||||
pointer-events: none;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
body > * {
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
body > hr {
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
min-height: 50vh;
|
||||
flex-shrink: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* HEADER and NAV */
|
||||
|
||||
#main-header {
|
||||
|
|
@ -71,22 +88,8 @@ body > * {
|
|||
}
|
||||
}
|
||||
|
||||
.map-hilight-area.active {
|
||||
stroke: #ff4e00;
|
||||
stroke-width: 5px;
|
||||
fill: rgba(255, 77, 0, 0.25);
|
||||
}
|
||||
|
||||
.highlight-point-icon::after {
|
||||
content: "";
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
border-radius: 100%;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.active .highlight-point-icon::after {
|
||||
background: #ff4e00;
|
||||
.highlight-point-icon > * {
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
}
|
||||
|
||||
.map-amenity-icon .map-amenity-icon-container {
|
||||
|
|
@ -126,4 +129,146 @@ body > * {
|
|||
filter: drop-shadow(0 0 10px black);
|
||||
opacity: clamp(0, calc( 1 - ( var(--zoom-level) - 18 ) ), 1) ;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* SAERCH FORM */
|
||||
|
||||
#search-section {
|
||||
border: solid 10px black;
|
||||
border-image: url("../assets/button-stepped-border-image.svg") 16 15 fill;
|
||||
z-index: 100;
|
||||
margin-bottom: 5px;
|
||||
margin-left: 5px;
|
||||
width: fit-content;
|
||||
max-width: 100%;
|
||||
background: black;
|
||||
background-clip: content-box;
|
||||
color: white;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: min-content 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
}
|
||||
|
||||
#search-section input {
|
||||
background: black;
|
||||
font-size: 1em;
|
||||
color: inherit;
|
||||
font-family: monospace;
|
||||
border: none;
|
||||
padding: 1ex;
|
||||
|
||||
grid-column: 2;
|
||||
grid-row: 1;
|
||||
}
|
||||
|
||||
#search-section button {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 1ex;
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#search-section label {
|
||||
grid-column: 2;
|
||||
grid-row: 1;
|
||||
padding: 1ex;
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
#search-section button img {
|
||||
height: 1.5em;
|
||||
}
|
||||
|
||||
/* PANEL */
|
||||
|
||||
#result-panel {
|
||||
background: black;
|
||||
border-image: url("../assets/neon-border-image.svg") 12;
|
||||
border-top: 5.5px white solid;
|
||||
|
||||
color: white;
|
||||
}
|
||||
|
||||
#result-panel.empty,
|
||||
#result-panel:empty{
|
||||
display:none;
|
||||
}
|
||||
|
||||
#result-panel > * {
|
||||
padding: 1em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#result-panel::part(navigation-panel) {
|
||||
background: black;
|
||||
color: white;
|
||||
box-shadow: 0 0 10px black;
|
||||
border-top: solid 1px rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
#result-panel::part(dot),
|
||||
#result-panel::part(dot-active) {
|
||||
border-radius: 0;
|
||||
width: 1ex;
|
||||
height: 1ex;
|
||||
margin-top: 0.5ex;
|
||||
}
|
||||
|
||||
#result-panel::part(dot-active) {
|
||||
transform-origin: 0% 100%;
|
||||
transform: scaleX(1) scaleY(1.5);
|
||||
}
|
||||
|
||||
camp-feature-short-header {
|
||||
display: grid;
|
||||
grid-template-rows: 1fr min-content;
|
||||
grid-template-columns: 3em 1fr;
|
||||
gap: 0.5ex 0.5em;
|
||||
vertical-align: center;
|
||||
}
|
||||
|
||||
camp-feature-short-header .feature-legend {
|
||||
grid-row: 1 / 3;
|
||||
height: 3em;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
camp-feature-short-header h2 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 1em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
camp-feature-short-header .feature-location {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 0.6em;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
#search-result {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
#search-result > li:not(:first-child) {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
#search-result > li:not(:last-child) {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
#search-result > li > a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
/* FEATURE */
|
||||
|
||||
camp-feature {
|
||||
min-height: 25vh;
|
||||
}
|
||||
|
|
|
|||
19
icons/arrow-left.svg
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="20.302734"
|
||||
height="21.37561"
|
||||
viewBox="0 0 20.302734 21.37561"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xml:space="preserve"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs1" /><g
|
||||
id="layer2"
|
||||
transform="translate(-1524.3279,-1694.6793)"><path
|
||||
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1.84565;stroke-linecap:butt;stroke-linejoin:bevel;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
d="m 356.12486,1705.4702 h -19.62275 l 9.32634,-10.1671 -9.32634,10.1671 9.32634,9.9538"
|
||||
id="path23-6-2"
|
||||
transform="translate(1188.5058)" /></g></svg>
|
||||
|
After Width: | Height: | Size: 792 B |
19
icons/arrow-right.svg
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="20.302734"
|
||||
height="21.37561"
|
||||
viewBox="0 0 20.302734 21.37561"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xml:space="preserve"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs1" /><g
|
||||
id="layer2"
|
||||
transform="translate(-1562.407,-1694.6793)"><path
|
||||
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1.84565;stroke-linecap:butt;stroke-linejoin:bevel;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
d="m 373.90116,1705.4702 h 19.62274 l -9.32633,-10.1671 9.32633,10.1671 -9.32633,9.9538"
|
||||
id="path23-8-8"
|
||||
transform="translate(1188.5058)" /></g></svg>
|
||||
|
After Width: | Height: | Size: 791 B |
48
icons/default-marker.svg
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
sodipodi:docname="default-marker.svg"
|
||||
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">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#999999"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="px"
|
||||
inkscape:zoom="29.973597"
|
||||
inkscape:cx="9.4082804"
|
||||
inkscape:cy="8.7076638"
|
||||
inkscape:window-width="1714"
|
||||
inkscape:window-height="1081"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs1" />
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<circle
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:2.94218;stroke-linejoin:bevel;paint-order:stroke markers fill"
|
||||
id="path1"
|
||||
cx="8"
|
||||
cy="8"
|
||||
r="6.6128607" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
66
icons/parking.svg
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="32"
|
||||
height="32"
|
||||
viewBox="0 0 32 32"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xml:space="preserve"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
sodipodi:docname="parking.svg"
|
||||
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"><sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:document-units="px"
|
||||
inkscape:zoom="8"
|
||||
inkscape:cx="-3.1875"
|
||||
inkscape:cy="25.5"
|
||||
inkscape:window-width="1703"
|
||||
inkscape:window-height="1071"
|
||||
inkscape:window-x="56"
|
||||
inkscape:window-y="50"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer1" /><defs
|
||||
id="defs1" /><g
|
||||
inkscape:label="Calque 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"><rect
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:4.93195;stroke-opacity:1"
|
||||
id="rect3"
|
||||
width="24.225895"
|
||||
height="32"
|
||||
x="3.8870521"
|
||||
y="0" /><rect
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:5.00771;stroke-opacity:1"
|
||||
id="rect3-5"
|
||||
width="31.999977"
|
||||
height="24.975895"
|
||||
x="3.8684334e-16"
|
||||
y="3.5120521" /><rect
|
||||
style="fill:#085ec7;fill-opacity:1;stroke-width:2;stroke:none;stroke-opacity:1;stroke-dasharray:none;paint-order:stroke fill markers"
|
||||
id="rect2"
|
||||
width="22.600895"
|
||||
height="22.600895"
|
||||
x="4.6995521"
|
||||
y="4.6995521" /><text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.1541px;line-height:100%;font-family:Sans;-inkscape-font-specification:'Sans Bold';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke-width:4.06158;stroke-linejoin:bevel;paint-order:stroke markers fill"
|
||||
x="8.5451469"
|
||||
y="23.909"
|
||||
id="text1"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan1"
|
||||
x="8.5451469"
|
||||
y="23.909"
|
||||
style="stroke-width:4.06158">P</tspan></text></g></svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
71
icons/piscine.svg
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="32"
|
||||
height="32"
|
||||
viewBox="0 0 32 32"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xml:space="preserve"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
sodipodi:docname="piscine.svg"
|
||||
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"><sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:document-units="px"
|
||||
inkscape:zoom="8"
|
||||
inkscape:cx="-3.1875"
|
||||
inkscape:cy="25.5"
|
||||
inkscape:window-width="1703"
|
||||
inkscape:window-height="1071"
|
||||
inkscape:window-x="56"
|
||||
inkscape:window-y="50"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer1" /><defs
|
||||
id="defs1" /><g
|
||||
inkscape:label="Calque 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"><g
|
||||
id="g1"
|
||||
transform="translate(-12.112948,-32.000002)"><rect
|
||||
style="display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:4.93195;stroke-opacity:1"
|
||||
id="rect3-65-9"
|
||||
width="24.225895"
|
||||
height="32"
|
||||
x="16"
|
||||
y="32" /><rect
|
||||
style="display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:5.00771;stroke-opacity:1"
|
||||
id="rect3-5-6-1"
|
||||
width="31.999977"
|
||||
height="24.975895"
|
||||
x="12.112946"
|
||||
y="35.512054" /><rect
|
||||
style="display:inline;fill:#0084ff;fill-opacity:1;stroke:none;stroke-width:2;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
id="rect2-9-4"
|
||||
width="22.600895"
|
||||
height="22.600895"
|
||||
x="16.8125"
|
||||
y="36.699554" /><path
|
||||
style="display:inline;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
d="m 19.907254,45.319304 c 0,0 2.221909,-2.3042 6.501128,-2.3042 4.93756,0 5.72351,2.323397 10.341611,2.323397"
|
||||
id="path18"
|
||||
sodipodi:nodetypes="csc" /><path
|
||||
style="display:inline;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
d="m 19.907254,49.049002 c 0,0 2.221909,-2.3042 6.501128,-2.3042 4.93756,0 5.72351,2.323397 10.341611,2.323397"
|
||||
id="path18-7"
|
||||
sodipodi:nodetypes="csc" /><path
|
||||
style="display:inline;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
d="m 20.195751,52.965682 c 0,0 2.221909,-2.3042 6.501128,-2.3042 4.93756,0 5.72351,2.323397 10.341611,2.323397"
|
||||
id="path18-7-4"
|
||||
sodipodi:nodetypes="csc"
|
||||
inkscape:label="path18-7-4" /></g></g></svg>
|
||||
|
After Width: | Height: | Size: 3 KiB |
541
icons/search.svg
Normal file
|
After Width: | Height: | Size: 7.2 MiB |
71
icons/wifi.svg
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="32"
|
||||
height="32"
|
||||
viewBox="0 0 32 32"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xml:space="preserve"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
sodipodi:docname="wifi.svg"
|
||||
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"><sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:document-units="px"
|
||||
inkscape:zoom="12.564654"
|
||||
inkscape:cx="24.79177"
|
||||
inkscape:cy="19.73791"
|
||||
inkscape:window-width="1703"
|
||||
inkscape:window-height="1071"
|
||||
inkscape:window-x="56"
|
||||
inkscape:window-y="50"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="g1" /><defs
|
||||
id="defs1" /><g
|
||||
inkscape:label="Calque 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"><g
|
||||
id="g1"
|
||||
transform="translate(-12.112948,-32.000002)"><rect
|
||||
style="display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:4.93195;stroke-opacity:1"
|
||||
id="rect3-65-9"
|
||||
width="24.225895"
|
||||
height="32"
|
||||
x="16"
|
||||
y="32" /><rect
|
||||
style="display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:5.00771;stroke-opacity:1"
|
||||
id="rect3-5-6-1"
|
||||
width="31.999977"
|
||||
height="24.975895"
|
||||
x="12.112946"
|
||||
y="35.512054" /><rect
|
||||
style="display:inline;fill:#a327ff;fill-opacity:1;stroke:none;stroke-width:2;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
id="rect2-9-4"
|
||||
width="22.600895"
|
||||
height="22.600895"
|
||||
x="16.8125"
|
||||
y="36.699554" /><g
|
||||
id="g2"
|
||||
transform="translate(1.849541,-2.254381)"><path
|
||||
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2.2;stroke-linejoin:bevel;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
d="m 18.917369,53.161005 c 4.561206,0 4.598593,1.870241 4.598593,4.598592"
|
||||
id="path1" /><path
|
||||
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2.2;stroke-linejoin:bevel;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
d="m 18.917369,48.465293 c 5.993796,0 8.975952,2.188594 8.975952,9.294304"
|
||||
id="path1-0"
|
||||
sodipodi:nodetypes="cc" /><path
|
||||
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2.2;stroke-linejoin:bevel;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
d="m 18.917369,43.849169 c 8.540623,0 13.592076,3.462007 13.592076,13.910428"
|
||||
id="path1-0-6"
|
||||
sodipodi:nodetypes="cc" /></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
34
index.html
|
|
@ -7,6 +7,7 @@
|
|||
<link rel="stylesheet" href="./js/lib/leaflet/leaflet.css">
|
||||
<link rel="stylesheet" href="./css/style.css">
|
||||
<script type="module" src="./js/index.js"></script>
|
||||
<script type="module" src="./js/components/bidi-panel.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<header id="main-header">
|
||||
|
|
@ -14,26 +15,17 @@
|
|||
</header>
|
||||
|
||||
<section id="map"></section>
|
||||
<style>
|
||||
#search-section {
|
||||
background: white;
|
||||
padding: 15px;
|
||||
max-width: 300px;
|
||||
margin-left: 15px;
|
||||
margin-top: 15px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
</style>
|
||||
<section id="search-section">
|
||||
<form id="search-area">
|
||||
<label for="search-area-query">Rechercher une zone</label><br/>
|
||||
<input type="search" name="query" id="search-area-query" />
|
||||
<button>Rechercher</button>
|
||||
</form>
|
||||
<ul id="search-result"></ul>
|
||||
</section>
|
||||
|
||||
<hr>
|
||||
|
||||
<form id="search-section">
|
||||
<label for="search-area-query">Rechercher une zone</label><br/>
|
||||
<input type="search" name="query" id="search-area-query" />
|
||||
<button title="Rechercher" autocomplete="no">
|
||||
<img src="icons/search.svg" alt="Icone de loupe"/>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<camp-bidi-panel id="result-panel" ></camp-bidi-panel>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
274
js/components/bidi-panel.js
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
const TEMPLATE = document.createElement("template");
|
||||
TEMPLATE.innerHTML = `
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
#navigation {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
|
||||
background: inherit;
|
||||
color: inherit;
|
||||
font-weight: bold;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: stretch;
|
||||
|
||||
padding: 0.5ex;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:host(.single-panel) #navigation {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#navigation .progress-container {
|
||||
flex: 1;
|
||||
flex-shrink: 100;
|
||||
}
|
||||
|
||||
#navigation button {
|
||||
flex-shrink: 0;
|
||||
width: 3em;
|
||||
height: 3em;
|
||||
background: none;
|
||||
border: none;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#navigation button img {
|
||||
height: 1.5em;
|
||||
}
|
||||
|
||||
.progress-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.progress-container progress {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
opacity: 0;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
#progress-dots {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow-x: auto;
|
||||
gap: 0.5ex;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#progress-dots .dot {
|
||||
width: 0.75ex;
|
||||
height: 0.75ex;
|
||||
border-radius: 100%;
|
||||
background: currentColor;
|
||||
}
|
||||
|
||||
#progress-dots .dot.active {
|
||||
transform: scale(1.5);
|
||||
}
|
||||
|
||||
#content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
overflow-x: auto;
|
||||
scroll-snap-type: x mandatory;
|
||||
scroll-behavior: inherit;
|
||||
}
|
||||
|
||||
#content ::slotted(*) {
|
||||
width: 100%;
|
||||
flex-shrink: 0;
|
||||
scroll-snap-align: start;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
|
||||
<section id="content"><slot></slot></section>
|
||||
|
||||
<nav id="navigation" part="navigation-panel">
|
||||
<button id="nav-left-panel" title="Aller au panneau de gauche" part="nav-button-left">
|
||||
<img alt="Fleche vers la gauche" src="${new URL("../../icons/arrow-left.svg", import.meta.url)}"/>
|
||||
</button>
|
||||
<div class="progress-container">
|
||||
<progress id="panel-progress-bar" value="0"></progress>
|
||||
<div id="progress-dots" aria-hidden="true"></div>
|
||||
</div>
|
||||
<button id="nav-right-panel" title="Aller au panneau de droite" part="nav-button-right" >
|
||||
<img alt="Fleche vers la droite" src="${new URL("../../icons/arrow-right.svg", import.meta.url)}"/>
|
||||
</button>
|
||||
</nav>
|
||||
`
|
||||
|
||||
export class BidiPanelElement extends HTMLElement {
|
||||
|
||||
shadow
|
||||
|
||||
mutationObserver
|
||||
|
||||
#lastActive
|
||||
#currentIndex
|
||||
|
||||
get contentContainer(){
|
||||
return this.shadow.getElementById("content")
|
||||
}
|
||||
|
||||
get progressBar(){
|
||||
return this.shadow.getElementById("panel-progress-bar")
|
||||
}
|
||||
|
||||
get progressDotsContainer(){
|
||||
return this.shadow.getElementById("progress-dots")
|
||||
}
|
||||
|
||||
get activeChildrenIndex(){
|
||||
let thisGeometry = this.getBoundingClientRect()
|
||||
let progress = this.contentContainer.scrollLeft / (this.contentContainer.scrollWidth - thisGeometry.width)
|
||||
let focusedElementIndex = Math.floor(progress * this.children.length)
|
||||
if(Number.isFinite(focusedElementIndex)){
|
||||
if(focusedElementIndex == this.children.length){
|
||||
return this.children.length - 1
|
||||
} else {
|
||||
return focusedElementIndex
|
||||
}
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
set activeChildrenIndex(newIndex){
|
||||
this.setActiveChildrenIndex(newIndex, {behavior: "auto"})
|
||||
}
|
||||
|
||||
setActiveChildrenIndex(newIndex, options){
|
||||
let newPanel = this.children[newIndex]
|
||||
let newPanelRect = newPanel.getBoundingClientRect()
|
||||
let selfRect = this.getBoundingClientRect()
|
||||
this.contentContainer.scrollTo({
|
||||
left: this.contentContainer.scrollLeft + ( newPanelRect.left - selfRect.left ),
|
||||
behavior: options?.behavior || "auto"
|
||||
})
|
||||
this.#currentIndex = newIndex
|
||||
}
|
||||
|
||||
get activeChildren(){
|
||||
return this.children[this.activeChildrenIndex]
|
||||
}
|
||||
|
||||
connectedCallback(){
|
||||
if(!this.shadow){
|
||||
this.shadow = this.attachShadow({ mode: "open" })
|
||||
this.shadow.append(TEMPLATE.content.cloneNode(true))
|
||||
}
|
||||
this.contentContainer.addEventListener("scroll", this.handleContentScroll.bind(this))
|
||||
this.shadow.getElementById("nav-left-panel").addEventListener("click", () => this.previous());
|
||||
this.shadow.getElementById("nav-right-panel").addEventListener("click", () => this.next());
|
||||
|
||||
this.mutationObserver = (new MutationObserver(this.handleMutations.bind(this)))
|
||||
this.mutationObserver.observe(this, {childList:true})
|
||||
|
||||
this.updateProgress()
|
||||
}
|
||||
|
||||
handleMutations(mutation){
|
||||
let newIndex = this.#currentIndex
|
||||
this.updateProgress()
|
||||
if(Number.isFinite(newIndex)){
|
||||
this.setActiveChildrenIndex(newIndex, {behavior: "instant"})
|
||||
}
|
||||
this.requestDispatchChangeEvent()
|
||||
}
|
||||
|
||||
handleContentScroll(e){
|
||||
this.updateProgress()
|
||||
this.#currentIndex = this.activeChildrenIndex
|
||||
this.requestDispatchChangeEvent()
|
||||
}
|
||||
|
||||
requestDispatchChangeEvent(){
|
||||
let currentPanel = this.activeChildren
|
||||
if(currentPanel != this.#lastActive){
|
||||
this.dispatchEvent(new ActivePanelChangeEvent("activePanelChange", this.#currentIndex))
|
||||
this.#lastActive = currentPanel
|
||||
}
|
||||
}
|
||||
|
||||
updateProgress(){
|
||||
let focusedElementIndex = this.activeChildrenIndex;
|
||||
|
||||
let progressBar = this.progressBar;
|
||||
progressBar.value = focusedElementIndex;
|
||||
progressBar.min = 0;
|
||||
progressBar.max = this.children.length-1;
|
||||
|
||||
this.classList.toggle("single-panel", this.children.length == 1)
|
||||
this.classList.toggle("empty", this.children.length == 0)
|
||||
|
||||
let dotsContainer = this.progressDotsContainer;
|
||||
if(dotsContainer.children.length != parseInt(progressBar.max)+1){
|
||||
let dots = (new Array(this.children.length))
|
||||
.fill(0)
|
||||
.map(() => {
|
||||
let el = document.createElement("div")
|
||||
el.classList.add("dot")
|
||||
el.part = "dot"
|
||||
return el
|
||||
});
|
||||
dotsContainer.replaceChildren(...dots)
|
||||
}
|
||||
for(let inactiveDot of dotsContainer.querySelectorAll(".active")){
|
||||
inactiveDot.part = "dot"
|
||||
inactiveDot.classList.remove("active")
|
||||
}
|
||||
|
||||
let activeDot = dotsContainer.children[parseInt(progressBar.value)]
|
||||
if(activeDot){
|
||||
activeDot.part = "dot-active"
|
||||
activeDot.classList.add("active")
|
||||
}
|
||||
}
|
||||
|
||||
next(){
|
||||
let nextItem = this.activeChildrenIndex + 1;
|
||||
if(nextItem < this.children.length){
|
||||
this.activeChildrenIndex = nextItem
|
||||
}
|
||||
}
|
||||
|
||||
previous(){
|
||||
let nextItem = this.activeChildrenIndex - 1;
|
||||
if(nextItem >= 0){
|
||||
this.activeChildrenIndex = nextItem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class ActivePanelChangeEvent extends Event {
|
||||
constructor(name, activePanelIndex){
|
||||
super(name)
|
||||
this.activePanelIndex = activePanelIndex
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("camp-bidi-panel", BidiPanelElement);
|
||||
72
js/components/feature-legend.js
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
const TEMPLATE = document.createElement("template")
|
||||
TEMPLATE.innerHTML = `
|
||||
<style>
|
||||
:host {
|
||||
display: inline-block;
|
||||
width: 3em;
|
||||
height: 3em;
|
||||
background: #404040;
|
||||
}
|
||||
|
||||
#legend-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
box-sizing: border-box;
|
||||
border: solid 1px transparent;
|
||||
}
|
||||
|
||||
#legend-container[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#marker-icon {
|
||||
max-height: 2em;
|
||||
}
|
||||
|
||||
#marker-icon:not([src]) {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<div id="legend-container">
|
||||
<img id="marker-icon" />
|
||||
</div>
|
||||
`
|
||||
|
||||
export class FeatureLegendElement extends HTMLElement {
|
||||
|
||||
feature
|
||||
|
||||
connectedCallback(){
|
||||
if(!this.shadow){
|
||||
this.shadow = this.attachShadow({mode: "open"})
|
||||
this.shadow.append(TEMPLATE.content.cloneNode(true))
|
||||
}
|
||||
this.updateContent()
|
||||
}
|
||||
|
||||
updateContent(){
|
||||
let container = this.shadow.getElementById("legend-container")
|
||||
let marker = this.shadow.getElementById("marker-icon")
|
||||
container.hidden = !this.feature
|
||||
if(this.feature){
|
||||
let symbol = this.feature.mapSymbol
|
||||
container.style.backgroundColor = symbol.backgroundColor || "transparent"
|
||||
container.style.backgroundImage = symbol.backgroundUrl ? `url(${symbol.backgroundUrl})` : "none"
|
||||
container.style.borderColor = symbol.borderColor || "transparent"
|
||||
if(symbol.markerUrl){
|
||||
marker.src = symbol.markerUrl
|
||||
} else {
|
||||
marker.removeAttribute("src")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
customElements.define("camp-feature-legend", FeatureLegendElement)
|
||||
54
js/components/feature-short-header.js
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import "./feature-legend.js"
|
||||
|
||||
const TEMPLATE = document.createElement("template")
|
||||
TEMPLATE.innerHTML = `
|
||||
<camp-feature-legend class="feature-legend"></camp-feature-legend>
|
||||
<h2 class="feature-name"></h2>
|
||||
<small class="feature-location"></small>
|
||||
`
|
||||
|
||||
export class FeatureShortHeaderElement extends HTMLElement {
|
||||
|
||||
#feature
|
||||
|
||||
get feature(){
|
||||
return this.#feature
|
||||
}
|
||||
|
||||
set feature(value){
|
||||
this.#feature = value
|
||||
let legend = this.querySelector(".feature-legend")
|
||||
if(legend)
|
||||
legend.feature = value
|
||||
}
|
||||
|
||||
connectedCallback(){
|
||||
this.updateContent()
|
||||
}
|
||||
|
||||
updateContent(){
|
||||
if(!this.feature){
|
||||
this.replaceChildren()
|
||||
} else {
|
||||
|
||||
this.replaceChildren(TEMPLATE.content.cloneNode(true))
|
||||
|
||||
this.querySelector(".feature-legend").feature = this.feature
|
||||
this.querySelector(".feature-legend").updateContent()
|
||||
|
||||
this.querySelector(".feature-name").textContent =
|
||||
this.feature?.properties?.name ||
|
||||
this.feature.mapSymbol.genericName ||
|
||||
this.feature.id
|
||||
|
||||
let featurePoint = this.feature.asPoint()
|
||||
|
||||
this.querySelector(".feature-location").textContent =
|
||||
this.feature?.properties?.["location-description"] ||
|
||||
`${featurePoint.geometry.coordinates[1]}, ${featurePoint.geometry.coordinates[0]}`
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
customElements.define("camp-feature-short-header", FeatureShortHeaderElement)
|
||||
26
js/components/feature.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import "./feature-short-header.js"
|
||||
|
||||
const TEMPLATE = document.createElement("template")
|
||||
TEMPLATE.innerHTML = `
|
||||
<camp-feature-short-header class="feature-header" ></camp-feature-short-header>
|
||||
`
|
||||
|
||||
export class FeatureElement extends HTMLElement {
|
||||
|
||||
feature
|
||||
|
||||
connectedCallback(){
|
||||
this.updateContent()
|
||||
}
|
||||
|
||||
updateContent(){
|
||||
this.replaceChildren(TEMPLATE.content.cloneNode(true))
|
||||
|
||||
let header = this.querySelector("camp-feature-short-header")
|
||||
header.feature = this.feature
|
||||
header.updateContent()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
customElements.define("camp-feature", FeatureElement)
|
||||
78
js/index.js
|
|
@ -1,5 +1,7 @@
|
|||
import * as MAP from "./map.js"
|
||||
import { PlaceDatabase } from "./places.js";
|
||||
import {FeatureElement} from "./components/feature.js"
|
||||
import "./components/feature-short-header.js"
|
||||
|
||||
/** La carte */
|
||||
|
||||
|
|
@ -19,7 +21,7 @@ window.interhackPlaces = places;
|
|||
await MAP.init_places(places)
|
||||
|
||||
// GESTION de la recherche
|
||||
const search_form = document.getElementById("search-area")
|
||||
const search_form = document.getElementById("search-section")
|
||||
search_form.elements["query"].addEventListener("change", () => search_form.requestSubmit())
|
||||
search_form.elements["query"].addEventListener("input", () => search_form.requestSubmit())
|
||||
|
||||
|
|
@ -47,18 +49,86 @@ search_form.addEventListener("submit", e => {
|
|||
let a = document.createElement("a")
|
||||
el.append(a)
|
||||
a.href = "#"+encodeURIComponent(result_item.ref)
|
||||
a.textContent = result_item.feature.properties.name+" ("+result_item.ref+")"
|
||||
a.addEventListener("click", e => {
|
||||
e.preventDefault()
|
||||
openSearchResultItem(result_item.feature)
|
||||
})
|
||||
let header = document.createElement("camp-feature-short-header")
|
||||
header.feature = result_item.feature
|
||||
a.append(header)
|
||||
resultElements.push(el)
|
||||
}
|
||||
|
||||
if(!document.getElementById("search-result")){
|
||||
let el = document.createElement("ol")
|
||||
el.id = "search-result"
|
||||
document.getElementById("result-panel").replaceChildren(el)
|
||||
}
|
||||
|
||||
if(resultElements.length > 0){
|
||||
document.getElementById("search-result").replaceChildren(...resultElements)
|
||||
} else {
|
||||
document.getElementById("search-result").replaceChildren(document.createTextNode("Pas de resultat"))
|
||||
}
|
||||
|
||||
document.getElementById("search-result").children[0]?.scrollIntoView()
|
||||
} else {
|
||||
document.getElementById("search-result").replaceChildren([])
|
||||
document.getElementById("search-result")?.remove()
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
function openSearchResultItem(feature){
|
||||
let searchResultContainer = document.getElementById("search-result")
|
||||
if(searchResultContainer){
|
||||
let featureIndex = -1
|
||||
let featureFound = false
|
||||
let newChildren = []
|
||||
for(let el of searchResultContainer.children){
|
||||
let featureHeader = el.querySelector("camp-feature-short-header")
|
||||
if(!featureHeader)
|
||||
continue
|
||||
let root = document.createElement("camp-feature")
|
||||
root.feature = featureHeader.feature
|
||||
newChildren.push(root)
|
||||
if(!featureFound){
|
||||
featureIndex += 1
|
||||
if(feature == root.feature){
|
||||
featureFound = true
|
||||
}
|
||||
}
|
||||
}
|
||||
let panel = document.getElementById("result-panel")
|
||||
panel.replaceChildren(...newChildren)
|
||||
requestAnimationFrame(() => {
|
||||
if(featureFound){
|
||||
panel.setActiveChildrenIndex(featureIndex, {behavior: "instant"})
|
||||
} else {
|
||||
panel.activeChildrenIndex = 0
|
||||
}
|
||||
})
|
||||
updateActiveFeature(feature)
|
||||
}
|
||||
}
|
||||
|
||||
function updateActiveFeature(feature_or_featureid){
|
||||
let newUrl = new URL(window.location)
|
||||
if(feature_or_featureid){
|
||||
newUrl.hash = encodeURIComponent(feature_or_featureid.id || feature_or_featureid)
|
||||
} else {
|
||||
delete newUrl.hash;
|
||||
}
|
||||
window.history.replaceState(null, "", newUrl.toString())
|
||||
window.dispatchEvent(new Event("hashchange"))
|
||||
}
|
||||
|
||||
document.getElementById("result-panel").addEventListener("activePanelChange", e => {
|
||||
let activeElement = e.target.children[e.activePanelIndex]
|
||||
if(activeElement instanceof FeatureElement){
|
||||
let feature = activeElement.feature
|
||||
updateActiveFeature(feature)
|
||||
} else {
|
||||
MAP.unhighlight_all()
|
||||
}
|
||||
})
|
||||
|
|
|
|||
117
js/map.js
|
|
@ -1,5 +1,5 @@
|
|||
import * as L from "./lib/leaflet/leaflet-src.esm.js"
|
||||
import { PlaceDatabase } from "./places.js";
|
||||
import { MapSubFeature, PlaceDatabase } from "./places.js";
|
||||
import "./lib/turf/turf.js"
|
||||
|
||||
let map = null;
|
||||
|
|
@ -93,93 +93,43 @@ export async function init(){
|
|||
const HIGHLIGHT_LAYER = Symbol("Highlight map layer")
|
||||
const AMENITY_MARKER_LAYER = Symbol("Amenity marker layer")
|
||||
const PARENT_FEATURE = Symbol("Parent feature")
|
||||
const HIGHLIGHT_MARKER_ICON = L.divIcon({
|
||||
className: "highlight-point-icon"
|
||||
})
|
||||
|
||||
export async function init_places(places_db){
|
||||
places = places_db
|
||||
|
||||
// La couche des zones disponibles
|
||||
const amenities = L.geoJSON(null, {
|
||||
pointToLayer: function(feature, latlng) {
|
||||
let iconEl = document.createElement("div")
|
||||
iconEl.classList.add("map-amenity-icon-container")
|
||||
|
||||
if(feature.properties["eau potable"]){
|
||||
let drinking_water_icon = document.createElement("img")
|
||||
drinking_water_icon.src = new URL("../icons/eau-potable.svg", import.meta.url).toString()
|
||||
drinking_water_icon.alt = "Icone d'une goute"
|
||||
drinking_water_icon.title = "Eau potable"
|
||||
drinking_water_icon.classList.add("drinking-water")
|
||||
iconEl.append(drinking_water_icon)
|
||||
}
|
||||
|
||||
if(feature.properties["toilettes"]){
|
||||
let bathrooms_icon = document.createElement("img")
|
||||
bathrooms_icon.src = new URL("../icons/toilettes.svg", import.meta.url).toString()
|
||||
bathrooms_icon.alt = "Icone de toilettes"
|
||||
bathrooms_icon.title = "Toilettes"
|
||||
bathrooms_icon.classList.add("bathroom")
|
||||
iconEl.append(bathrooms_icon)
|
||||
}
|
||||
|
||||
if(feature.properties["douches"]){
|
||||
let shower_icon = document.createElement("img")
|
||||
shower_icon.src = new URL("../icons/douches.svg", import.meta.url).toString()
|
||||
shower_icon.alt = "Icone de douche"
|
||||
shower_icon.title = "Douches"
|
||||
shower_icon.classList.add("shower")
|
||||
iconEl.append(shower_icon)
|
||||
}
|
||||
|
||||
if(feature.properties["n couchage"]){
|
||||
let dorm_icon = document.createElement("img")
|
||||
dorm_icon.src = new URL("../icons/dortoir.svg", import.meta.url).toString()
|
||||
dorm_icon.alt = "Icone de dortoir"
|
||||
dorm_icon.title = "Dortoir"
|
||||
dorm_icon.classList.add("dorm")
|
||||
iconEl.append(dorm_icon)
|
||||
}
|
||||
|
||||
let icon = L.divIcon({
|
||||
className: "map-amenity-icon",
|
||||
html: iconEl
|
||||
})
|
||||
|
||||
return L.marker(latlng, {
|
||||
icon: icon
|
||||
})
|
||||
},
|
||||
onEachFeature: function(feature, layer){
|
||||
if(feature[PARENT_FEATURE]){
|
||||
feature[PARENT_FEATURE][AMENITY_MARKER_LAYER] = layer
|
||||
} else {
|
||||
feature[AMENITY_MARKER_LAYER] = layer
|
||||
}
|
||||
}
|
||||
}).addTo(map)
|
||||
|
||||
// La couche des zones disponibles
|
||||
const area_highlight = L.geoJSON(null, {
|
||||
pointToLayer: function(feature, latlng) {
|
||||
return L.marker(latlng, {
|
||||
icon: HIGHLIGHT_MARKER_ICON
|
||||
})
|
||||
let symbol = feature.mapSymbol;
|
||||
if(symbol.markerUrl) {
|
||||
|
||||
let iconEl = document.createElement("img");
|
||||
iconEl.src = symbol.markerUrl;
|
||||
|
||||
if(iconEl){
|
||||
return L.marker(latlng, {
|
||||
icon: L.divIcon({
|
||||
className: "highlight-point-icon",
|
||||
html: iconEl,
|
||||
iconSize: [0, 0]
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
style: function(feature){
|
||||
let symbol = feature.mapSymbol;
|
||||
return {
|
||||
className: "map-hilight-area",
|
||||
fill: false,
|
||||
stroke: false
|
||||
fill: !!symbol.backgroundColor,
|
||||
fillColor: symbol.backgroundColor,
|
||||
fillOpacity: 0.5,
|
||||
stroke: !!symbol.borderColor,
|
||||
color: symbol.borderColor,
|
||||
}
|
||||
},
|
||||
onEachFeature: function(feature, layer){
|
||||
if(feature[PARENT_FEATURE]){
|
||||
feature[PARENT_FEATURE][HIGHLIGHT_LAYER] = layer
|
||||
} else {
|
||||
feature[HIGHLIGHT_LAYER] = layer
|
||||
}
|
||||
feature[HIGHLIGHT_LAYER] = layer
|
||||
}
|
||||
}).addTo(map)
|
||||
|
||||
|
|
@ -187,22 +137,9 @@ export async function init_places(places_db){
|
|||
for(let [_feature_id, feature] of Object.entries(places.featuresById)){
|
||||
area_highlight.addData(feature)
|
||||
|
||||
if(feature.properties["toilettes"]
|
||||
|| feature.properties["douches"]
|
||||
|| feature.properties["eau potable"]
|
||||
|| feature.properties["n couchage"]
|
||||
) {
|
||||
let amenity_feature
|
||||
|
||||
if(feature.geometry.type != "Point"){
|
||||
amenity_feature = turf.centerOfMass(feature)
|
||||
amenity_feature[PARENT_FEATURE] = feature
|
||||
amenity_feature.properties = feature.properties
|
||||
} else {
|
||||
amenity_feature = feature
|
||||
}
|
||||
|
||||
amenities.addData(amenity_feature)
|
||||
let point_feature = feature.asPoint()
|
||||
if(point_feature !== feature){
|
||||
area_highlight.addData(point_feature)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
145
js/places.js
|
|
@ -1,10 +1,11 @@
|
|||
import lunr from "./lib/lunr/lunr.js"
|
||||
import lunrStemmer from "./lib/lunr/lunr.stemmer.support.js"
|
||||
import lunrFr from "./lib/lunr/lunr.fr.js"
|
||||
import { MapSymbol } from "./symbols.js"
|
||||
lunrStemmer(lunr)
|
||||
lunrFr(lunr)
|
||||
|
||||
const FEATURE_I = Symbol("Feature index")
|
||||
const FEATURE_INDEX = Symbol("Feature index")
|
||||
export const FEATURE_ID = Symbol("Feature id")
|
||||
|
||||
/**
|
||||
|
|
@ -92,22 +93,29 @@ export class PlaceDatabase extends EventTarget {
|
|||
let all_ids = []
|
||||
|
||||
if(geojson.type == "Feature"){
|
||||
let featureId = geojson?.properties?.id || geojson?.properties?.[FEATURE_I]
|
||||
let full_id = idPrefix+"#"+featureId
|
||||
|
||||
if(this.featuresById[full_id]){
|
||||
console.warn(`Warning: a feature with ID "${full_id}" already exists in database`)
|
||||
let feature = geojson;
|
||||
if(!(feature instanceof MapFeature)){
|
||||
feature = new MapFeature(geojson)
|
||||
}
|
||||
|
||||
geojson[FEATURE_ID] = full_id
|
||||
this.featuresById[full_id] = geojson
|
||||
if(!feature.id){
|
||||
let full_id = idPrefix+"#"+(geojson?.properties?.id || geojson?.properties?.[FEATURE_INDEX])
|
||||
feature.id = full_id
|
||||
}
|
||||
|
||||
if(this.featuresById[feature.id]){
|
||||
console.warn(`Warning: a feature with ID "${feature.id}" already exists in database`)
|
||||
}
|
||||
|
||||
this.featuresById[feature.id] = feature
|
||||
|
||||
let event = new Event("newfeature")
|
||||
event.ref = full_id
|
||||
event.feature = geojson
|
||||
event.ref = feature.id
|
||||
event.feature = feature
|
||||
this.dispatchEvent(event)
|
||||
|
||||
all_ids.push(full_id)
|
||||
all_ids.push(feature.id)
|
||||
|
||||
} else if(geojson.type == "FeatureCollection") {
|
||||
|
||||
|
|
@ -115,15 +123,15 @@ export class PlaceDatabase extends EventTarget {
|
|||
idPrefix += (idPrefix != "" ? "-" : "")+geojson.name
|
||||
}
|
||||
|
||||
if(geojson?.properties?.[FEATURE_I]){
|
||||
idPrefix += (idPrefix != "" ? "-" : "")+geojson.properties[FEATURE_I]
|
||||
if(geojson?.properties?.[FEATURE_INDEX]){
|
||||
idPrefix += (idPrefix != "" ? "-" : "")+geojson.properties[FEATURE_INDEX]
|
||||
}
|
||||
|
||||
for(let [i, feature] of Object.entries(geojson.features)){
|
||||
|
||||
feature.properties = {
|
||||
...(feature.properties || {}),
|
||||
[FEATURE_I]: i
|
||||
[FEATURE_INDEX]: i
|
||||
}
|
||||
|
||||
let id = this.addFeature(feature, {
|
||||
|
|
@ -159,19 +167,21 @@ export class PlaceDatabase extends EventTarget {
|
|||
this.field("synonyms")
|
||||
|
||||
for(let [id, feature] of Object.entries(database.featuresById)){
|
||||
let synonyms = ""
|
||||
let sym = feature.mapSymbol;
|
||||
|
||||
if(feature.properties["n couchage"] > 0){
|
||||
synonyms += SLEEPING_SYNONYMS.join(" ")
|
||||
let synonyms = []
|
||||
|
||||
if(sym.genericName){
|
||||
synonyms.push(sym.genericName)
|
||||
}
|
||||
|
||||
if(feature.properties["toilettes"]){
|
||||
synonyms += " "+TOILETTES_SYNONYMS.join(" ")
|
||||
if(sym.indexSynonyms){
|
||||
synonyms.push(...sym.indexSynonyms)
|
||||
}
|
||||
|
||||
this.add({
|
||||
id,
|
||||
name: feature.properties.name,
|
||||
name: feature.properties.name || sym.genericName,
|
||||
synonyms
|
||||
})
|
||||
}
|
||||
|
|
@ -184,15 +194,27 @@ export class PlaceDatabase extends EventTarget {
|
|||
let default_database = new PlaceDatabase()
|
||||
|
||||
await Promise.all([
|
||||
default_database.loadGeojson(new URL("../couches/aire-de-jeux.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/autogestion.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/bac-a-sable.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/batiments.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/piscine.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/terrain-de-basket.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/pieces-batiments.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/braseros.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/camping.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/dons.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/eau-potable.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/espace-camp.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/espacemiam.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/marabouts.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/medic.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/parkings.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/pieces-batiments.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/piscine.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/poubelles.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/scenes.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/terrain-de-basket.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/wifi.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/zones-interdite.geojson", import.meta.url), {batch: true}),
|
||||
default_database.loadGeojson(new URL("../couches/parkings.geojson", import.meta.url), {batch: true}),
|
||||
])
|
||||
])
|
||||
|
||||
default_database.buildIndex()
|
||||
|
||||
|
|
@ -201,32 +223,51 @@ export class PlaceDatabase extends EventTarget {
|
|||
|
||||
}
|
||||
|
||||
const SLEEPING_SYNONYMS = [
|
||||
"dodo",
|
||||
"dortoir",
|
||||
"mimir",
|
||||
"dormir",
|
||||
"lit"
|
||||
]
|
||||
const POINT_FEATURE = Symbol("Point feature")
|
||||
|
||||
const TOILETTES_SYNONYMS = [
|
||||
"caca",
|
||||
"pipi",
|
||||
"cabinets",
|
||||
"water-closet",
|
||||
"latrines",
|
||||
"🚽",
|
||||
"double véssé",
|
||||
"chaise percée",
|
||||
"WC",
|
||||
"waters",
|
||||
"toilettes",
|
||||
"toilette",
|
||||
"chiotte",
|
||||
"chiottes",
|
||||
"le trône",
|
||||
"le trones",
|
||||
"pièce mystère",
|
||||
"backroom",
|
||||
"retailleau"
|
||||
]
|
||||
export class MapFeature {
|
||||
constructor(geojson){
|
||||
Object.assign(this, geojson)
|
||||
}
|
||||
|
||||
get id(){
|
||||
return this[FEATURE_ID]
|
||||
}
|
||||
|
||||
set id(value){
|
||||
this[FEATURE_ID] = value
|
||||
}
|
||||
|
||||
get mapSymbol(){
|
||||
return MapSymbol.fromFeature(this)
|
||||
}
|
||||
|
||||
asPoint(){
|
||||
if(!this[POINT_FEATURE]){
|
||||
if(!this.geometry){
|
||||
debugger;
|
||||
}
|
||||
if(this.geometry.type != "Point"){
|
||||
let point_feature = turf.centerOfMass(this)
|
||||
point_feature.properties = this.properties
|
||||
point_feature = new MapSubFeature(point_feature, this)
|
||||
this[POINT_FEATURE] = point_feature
|
||||
} else {
|
||||
this[POINT_FEATURE] = this
|
||||
}
|
||||
}
|
||||
return this[POINT_FEATURE]
|
||||
}
|
||||
}
|
||||
|
||||
const PARENT_FEATURE = Symbol("Parent feature")
|
||||
export class MapSubFeature extends MapFeature {
|
||||
constructor(geojson, parent){
|
||||
super(geojson)
|
||||
this[PARENT_FEATURE] = parent
|
||||
}
|
||||
|
||||
get parentFeature(){
|
||||
return this[PARENT_FEATURE]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
204
js/symbols.js
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
import { MapFeature } from "./places.js"
|
||||
|
||||
export class MapSymbol {
|
||||
|
||||
/**
|
||||
* Solid background color of this area (if any)
|
||||
* @type {undefined|string}
|
||||
*/
|
||||
backgroundColor = undefined
|
||||
|
||||
/**
|
||||
* Background raster tiled image to put on top of solid background (if any)
|
||||
* @type {undefined|string|URL}
|
||||
*/
|
||||
backgroundUrl = undefined
|
||||
|
||||
/**
|
||||
* Border color of area (if any)
|
||||
* @type {undefined|string}
|
||||
*/
|
||||
borderColor = undefined
|
||||
|
||||
/**
|
||||
* Marker URL to place on feature (if point) or on centroid (if area)
|
||||
* @type {undefined|string|URL}
|
||||
*/
|
||||
markerUrl = undefined
|
||||
|
||||
/**
|
||||
* Generic name of this feature if no more precise name is given
|
||||
* @type {undefined|string}
|
||||
*/
|
||||
genericName = undefined
|
||||
|
||||
/**
|
||||
* A list of sysnonyms for this feature for full text indexing
|
||||
* @type {string[]}
|
||||
*/
|
||||
indexSynonyms = []
|
||||
|
||||
clone(){
|
||||
let new_symb = new MapSymbol()
|
||||
Object.assign(new_symb, this)
|
||||
return new_symb
|
||||
}
|
||||
|
||||
static fromFeature(feature){
|
||||
return getSymbolForFeature(feature)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a map symbol from feature properties
|
||||
* @param {MapFeature|Object} feature
|
||||
*/
|
||||
function getSymbolForFeature(feature){
|
||||
let sym = getBaseSymbolForFeature(feature);
|
||||
|
||||
if(feature.properties["color"]){
|
||||
sym = sym.clone()
|
||||
sym.backgroundColor = feature.properties["color"]
|
||||
sym.borderColor = feature.properties["color"]
|
||||
}
|
||||
|
||||
return sym
|
||||
}
|
||||
|
||||
function getBaseSymbolForFeature(feature){
|
||||
|
||||
if(feature.properties["wifi"]){
|
||||
return WIFI_SYMBOL
|
||||
}
|
||||
|
||||
if(feature.properties["zone-interdite"]){
|
||||
return VERBOTEN_AREA_SYMBOL
|
||||
}
|
||||
|
||||
if(feature.properties["piscine"]){
|
||||
return SWIMMING_POOL_SYMBOL
|
||||
}
|
||||
|
||||
if(feature.properties["Parking"]){
|
||||
return PARKING_SYMBOL
|
||||
}
|
||||
|
||||
if(feature.properties["n couchage"] > 0){
|
||||
return SLEEPING_SYMBOL
|
||||
}
|
||||
|
||||
if(feature.properties["toilettes"]){
|
||||
return TOILETS_SYMBOL
|
||||
}
|
||||
|
||||
if(feature.properties["douches"]){
|
||||
return SHOWER_SYMBOL
|
||||
}
|
||||
|
||||
if(feature.properties["eau potable"]){
|
||||
return DRINKING_WATER_SYMBOL
|
||||
}
|
||||
|
||||
if(feature.properties["batiment"] || feature.properties["piece-batiment"]){
|
||||
return BUILDING_SYMBOL
|
||||
}
|
||||
|
||||
return DEFAULT_SYMBOL
|
||||
}
|
||||
|
||||
// PREDEFINED Symbols
|
||||
|
||||
export const DEFAULT_SYMBOL = new MapSymbol()
|
||||
{
|
||||
DEFAULT_SYMBOL.markerUrl = new URL("../icons/default-marker.svg", import.meta.url)
|
||||
DEFAULT_SYMBOL.backgroundColor = "white"
|
||||
DEFAULT_SYMBOL.borderColor = "white"
|
||||
}
|
||||
|
||||
export const SLEEPING_SYMBOL = new MapSymbol()
|
||||
{
|
||||
SLEEPING_SYMBOL.markerUrl = new URL("../icons/dortoir.svg", import.meta.url)
|
||||
SLEEPING_SYMBOL.genericName = "Dortoir"
|
||||
SLEEPING_SYMBOL.indexSynonyms = [
|
||||
"dodo",
|
||||
"dortoir",
|
||||
"mimir",
|
||||
"dormir",
|
||||
"lit"
|
||||
]
|
||||
}
|
||||
|
||||
export const DRINKING_WATER_SYMBOL = new MapSymbol()
|
||||
{
|
||||
DRINKING_WATER_SYMBOL.markerUrl = new URL("../icons/eau-potable.svg", import.meta.url)
|
||||
DRINKING_WATER_SYMBOL.genericName = "Point d'eau potable"
|
||||
}
|
||||
|
||||
export const PARKING_SYMBOL = new MapSymbol()
|
||||
{
|
||||
PARKING_SYMBOL.markerUrl = new URL("../icons/parking.svg", import.meta.url)
|
||||
PARKING_SYMBOL.genericName = "Parking"
|
||||
PARKING_SYMBOL.backgroundColor = "#2d2d2d"
|
||||
PARKING_SYMBOL.borderColor = "#989898"
|
||||
}
|
||||
|
||||
export const TOILETS_SYMBOL = new MapSymbol()
|
||||
{
|
||||
TOILETS_SYMBOL.markerUrl = new URL("../icons/toilettes.svg", import.meta.url)
|
||||
TOILETS_SYMBOL.genericName = "Toilettes"
|
||||
TOILETS_SYMBOL.indexSynonyms = [
|
||||
"caca",
|
||||
"pipi",
|
||||
"cabinets",
|
||||
"water-closet",
|
||||
"latrines",
|
||||
"🚽",
|
||||
"double véssé",
|
||||
"chaise percée",
|
||||
"WC",
|
||||
"waters",
|
||||
"toilettes",
|
||||
"toilette",
|
||||
"chiotte",
|
||||
"chiottes",
|
||||
"le trône",
|
||||
"le trones",
|
||||
"pièce mystère",
|
||||
"backroom",
|
||||
"retailleau"
|
||||
]
|
||||
}
|
||||
|
||||
export const SHOWER_SYMBOL = new MapSymbol()
|
||||
{
|
||||
SHOWER_SYMBOL.markerUrl = new URL("../icons/douches.svg", import.meta.url)
|
||||
SHOWER_SYMBOL.genericName = "Douche"
|
||||
}
|
||||
|
||||
export const SWIMMING_POOL_SYMBOL = new MapSymbol()
|
||||
{
|
||||
SWIMMING_POOL_SYMBOL.markerUrl = new URL("../icons/piscine.svg", import.meta.url)
|
||||
SWIMMING_POOL_SYMBOL.genericName = "Piscine"
|
||||
SWIMMING_POOL_SYMBOL.backgroundColor = "#366d73"
|
||||
SWIMMING_POOL_SYMBOL.borderColor = "#366d73"
|
||||
}
|
||||
|
||||
export const VERBOTEN_AREA_SYMBOL = new MapSymbol()
|
||||
{
|
||||
VERBOTEN_AREA_SYMBOL.genericName = "Zone interdite"
|
||||
VERBOTEN_AREA_SYMBOL.backgroundColor = "#992700"
|
||||
VERBOTEN_AREA_SYMBOL.borderColor = "#992700"
|
||||
}
|
||||
|
||||
export const BUILDING_SYMBOL = new MapSymbol()
|
||||
{
|
||||
BUILDING_SYMBOL.genericName = "Batiment"
|
||||
BUILDING_SYMBOL.backgroundColor = "#5a5a5a"
|
||||
BUILDING_SYMBOL.borderColor = "white"
|
||||
}
|
||||
|
||||
export const WIFI_SYMBOL = new MapSymbol()
|
||||
{
|
||||
WIFI_SYMBOL.genericName = "Wifi"
|
||||
WIFI_SYMBOL.markerUrl = new URL("../icons/wifi.svg", import.meta.url)
|
||||
}
|
||||