Page Menu
Home
Sealhub
Search
Configure Global Search
Log In
Files
F1374501
map-with-pins.stimulus.ts
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
3 KB
Referenced Files
None
Subscribers
None
map-with-pins.stimulus.ts
View Options
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/consistent-type-assertions */
/* eslint-disable @typescript-eslint/no-explicit-any */
import
{
Controller
}
from
"stimulus"
;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
import
{
addJS
}
from
"@sealcode/add-to-head"
;
declare
global
{
interface
Window
{
L
:
typeof
import
(
"leaflet"
);
}
}
type
Pin
=
{
title
:
string
;
address
:
string
;
coordinates
:
string
;
button
:
{
link
:
string
;
text
:
string
};
};
function
parseCoords
(
s
:
string
)
:
[
number
,
number
]
{
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const
result
=
s
.
split
(
","
).
map
((
x
)
=>
parseFloat
(
x
.
trim
()))
as
[
number
,
number
];
return
result
;
}
function
decodeHTMLEntities
(
text
:
string
)
{
const
entities
=
[
[
"amp"
,
"&"
],
[
"apos"
,
"'"
],
[
"#x27"
,
"'"
],
[
"#x2F"
,
"/"
],
[
"#39"
,
"'"
],
[
"#47"
,
"/"
],
[
"lt"
,
"<"
],
[
"gt"
,
">"
],
[
"nbsp"
,
" "
],
[
"quot"
,
'"'
],
];
for
(
let
i
=
0
,
max
=
entities
.
length
;
i
<
max
;
++
i
)
text
=
text
.
replace
(
new
RegExp
(
"&"
+
entities
[
i
][
0
]
+
";"
,
"g"
),
entities
[
i
][
1
]);
return
text
;
}
export
default
class
MapWithPins
extends
Controller
{
id
:
string
;
map
:
L
.
Map
;
initiated
=
false
;
resizeObserver
:
ResizeObserver
;
static
values
=
{
pins
:
String
,
};
async
connect
()
{
if
(
this
.
initiated
)
{
this
.
map
.
remove
();
}
await
addJS
(
"https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
);
this
.
initiateMap
();
}
disconnect
()
{
this
.
map
.
remove
();
this
.
initiated
=
false
;
this
.
resizeObserver
?
.
disconnect
();
}
initiateMap
()
{
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
this
.
map
=
window
.
L
.
map
(
this
.
element
as
HTMLElement
,
{
dragging
:
"ontouchstart"
in
document
.
documentElement
,
scrollWheelZoom
:
false
,
});
if
(
window
.
ResizeObserver
)
{
this
.
resizeObserver
=
new
ResizeObserver
(()
=>
{
this
.
map
.
invalidateSize
();
});
}
this
.
resizeObserver
?
.
observe
(
this
.
element
);
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
window
.
L
.
tileLayer
(
"https://tile.openstreetmap.org/{z}/{x}/{y}.png"
,
{
maxZoom
:
19
,
attribution
:
'© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
,
}).
addTo
(
this
.
map
);
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const
pins
=
JSON
.
parse
(
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument
decodeHTMLEntities
(
this
.
element
.
getAttribute
(
"data-map-with-pins-pins-value"
))
)
as
Pin
[];
pins
.
forEach
((
pin
)
=>
this
.
addPin
(
pin
));
this
.
initiated
=
true
;
}
async
pinsValueChanged
()
{
if
(
this
.
initiated
)
{
await
this
.
connect
();
}
}
addPin
(
pin
:
Pin
)
{
const
pinIcon
=
window
.
L
.
icon
({
iconUrl
:
"/pin-icon.svg"
,
iconSize
:
[
29
,
41
],
iconAnchor
:
[
14
,
40
],
popupAnchor
:
[
-
3
,
14
],
});
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
window
.
L
.
marker
(
parseCoords
(
pin
.
coordinates
),
{
icon
:
pinIcon
,
}).
addTo
(
this
.
map
);
window
.
L
.
popup
({
closeButton
:
false
,
autoClose
:
false
,
closeOnEscapeKey
:
false
,
closeOnClick
:
false
,
className
:
"popup"
,
offset
:
[
0
,
-
32
],
})
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
.
setLatLng
(
parseCoords
(
pin
.
coordinates
))
.
setContent
(
/* HTML */
`<div class="popup-content">
<p class="title">
${
pin
.
title
}
</p>
<p class="address">
${
pin
.
address
}
</p>
<a class="button" href="
${
pin
.
button
.
link
}
">
${
pin
.
button
.
text
}
</a>
</div> `
)
.
addTo
(
this
.
map
);
this
.
map
.
setView
(
parseCoords
(
pin
.
coordinates
),
13
);
}
}
File Metadata
Details
Attached
Mime Type
text/html
Expires
Mon, Feb 24, 22:52 (1 d, 4 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
610353
Default Alt Text
map-with-pins.stimulus.ts (3 KB)
Attached To
Mode
rPLAY Sealious playground
Attached
Detach File
Event Timeline
Log In to Comment