aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/LocationsMap.svelte
blob: 765230060e36c926c9093fab8a8562a5f185e034 (plain) (blame)
1
2
3
4
5
6
7
8
9
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888 } /* Comment */
.highlight .err { color: #A61717; background-color: #E3D2D2 } /* Error */
.highlight .k { color: #080; font-weight: bold } /* Keyword */
.highlight .ch { color: #888 } /* Comment.Hashbang */
.highlight .cm { color: #888 } /* Comment.Multiline */
.highlight .cp { color: #C00; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888 } /* Comment.Single */
.highlight .cs { color: #C00; font-weight: bold; background-color: #FFF0F0 } /* Comment.Special */
.highlight .gd { color: #000; background-color: #FDD } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #A00 } /* Generic.Error */
.highlight .gh { color: #333 } /* Generic.Heading */
.highlight .gi { color: #000; background-color: #DFD } /* Generic.Inserted */
.highlight .go { color: #888 } /* Generic.Output */
.highlight .gp { color: #555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666 } /* Generic.Subheading */
.highlight .gt { color: #A00 } /* Generic.Traceback */
.highlight .kc { color: #080; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #080; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #080; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #080 } /* Keyword.Pseudo */
.highlight .kr { color: #080; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #00D; font-weight: bold } /* Literal.Number */
.highlight .s { color: #D20; background-color: #FFF0F0 } /* Literal.String */
.highlight .na { color: #369 } /* Name.Attribute */
.highlight .nb { color: #038 } /* Name.Builtin */
.highlight .nc { color: #B06; font-weight: bold } /* Name.Class */
.highlight .no { color: #036; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555 } /* Name.Decorator */
.highlight .ne { color: #B06; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #06B; font-weight: bold } /* Name.Function */
.highlight .nl { color: #369; font-style: italic } /* Name.Label */
.highlight .nn { color: #B06; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #369; font-weight: bold } /* Name.Property */
.highlight .nt { color: #B06; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #369 } /* Name.Variable */
.highlight .ow { color: #080 } /* Operator.Word */
.highlight .w { color: #BBB } /* Text.Whitespace */
.highlight .mb { color: #00D; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #00D; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #00D; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #00D; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #00D; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #D20; background-color: #FFF0F0 } /* Literal.String.Affix */
.highlight .sb { color: #D20; background-color: #FFF0F0 } /* Literal.String.Backtick */
.highlight .sc { color: #D20; background-color: #FFF0F0 } /* Literal.String.Char */
.highlight .dl { color: #D20; background-color: #FFF0F0 } /* Literal.String.Delimiter */
.highlight .sd { color: #D20; background-color: #FFF0F0 } /* Literal.String.Doc */
.highlight .s2 { color: #D20; background-color: #FFF0F0 } /* Literal.String.Double */
.highlight .se { color: #04D; background-color: #FFF0F0 } /* Literal.String.Escape */
.highlight .sh { color: #D20; background-color: #FFF0F0 } /* Literal.String.Heredoc */
.highlight .si { color: #33B; background-color: #FFF0F0 } /* Literal.String.Interpol */
.highlight .sx { color: #2B2; background-color: #F0FFF0 } /* Literal.String.Other */
.highlight .sr { color: #080; background-color: #FFF0FF } /* Literal.String.Regex */
.highlight .s1 { color: #D20; background-color: #FFF0F0 } /* Literal.String.Single */
.highlight .ss { color: #A60; background-color: #FFF0F0 } /* Literal.String.Symbol */
.highlight .bp { color: #038 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #06B; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #369 } /* Name.Variable.Class */
.highlight .vg { color: #D70 } /* Name.Variable.Global */
.highlight .vi { color: #33B } /* Name.Variable.Instance */
.highlight .vm { color: #369 } /* Name.Variable.Magic */
.highlight .il { color: #00D; font-weight: bold } /* Literal.Number.Integer.Long */
@tailwind base;
@tailwind components;
@tailwind utilities;

@font-face {
	font-family: 'PublicSans';
	src: url('/fonts/Public_Sans/static/PublicSans-Regular.ttf') format('truetype');
}

html {
	font-family: PublicSans, sans-serif;
}

::selection {
	color: black;
	background: #eaf2ff;
}

:fullscreen {
	background-color:pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888 } /* Comment */
.highlight .err { color: #A61717; background-color: #E3D2D2 } /* Error */
.highlight .k { color: #080; font-weight: bold } /* Keyword */
.highlight .ch { color: #888 } /* Comment.Hashbang */
.highlight .cm { color: #888 } /* Comment.Multiline */
.highlight .cp { color: #C00; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888 } /* Comment.Single */
.highlight .cs { color: #C00; font-weight: bold; background-color: #FFF0F0 } /* Comment.Special */
.highlight .gd { color: #000; background-color: #FDD } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #A00 } /* Generic.Error */
.highlight .gh { color: #333 } /* Generic.Heading */
.highlight .gi { color: #000; background-color: #DFD } /* Generic.Inserted */
.highlight .go { color: #888 } /* Generic.Output */
.highlight .gp { color: #555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666 } /* Generic.Subheading */
.highlight .gt { color: #A00 } /* Generic.Traceback */
.highlight .kc { color: #080; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #080; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #080; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #080 } /* Keyword.Pseudo */
.highlight .kr { color: #080; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #00D; font-weight: bold } /* Literal.Number */
.highlight .s { color: #D20; background-color: #FFF0F0 } /* Literal.String */
.highlight .na { color: #369 } /* Name.Attribute */
.highlight .nb { color: #038 } /* Name.Builtin */
.highlight .nc { color: #B06; font-weight: bold } /* Name.Class */
.highlight .no { color: #036; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555 } /* Name.Decorator */
.highlight .ne { color: #B06; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #06B; font-weight: bold } /* Name.Function */
.highlight .nl { color: #369; font-style: italic } /* Name.Label */
.highlight .nn { color: #B06; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #369; font-weight: bold } /* Name.Property */
.highlight .nt { color: #B06; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #369 } /* Name.Variable */
.highlight .ow { color: #080 } /* Operator.Word */
.highlight .w { color: #BBB } /* Text.Whitespace */
.highlight .mb { color: #00D; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #00D; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #00D; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #00D; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #00D; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #D20; background-color: #FFF0F0 } /* Literal.String.Affix */
.highlight .sb { color: #D20; background-color: #FFF0F0 } /* Literal.String.Backtick */
.highlight .sc { color: #D20; background-color: #FFF0F0 } /* Literal.String.Char */
.highlight .dl { color: #D20; background-color: #FFF0F0 } /* Literal.String.Delimiter */
.highlight .sd { color: #D20; background-color: #FFF0F0 } /* Literal.String.Doc */
.highlight .s2 { color: #D20; background-color: #FFF0F0 } /* Literal.String.Double */
.highlight .se { color: #04D; background-color: #FFF0F0 } /* Literal.String.Escape */
.highlight .sh { color: #D20; background-color: #FFF0F0 } /* Literal.String.Heredoc */
.highlight .si { color: #33B; background-color: #FFF0F0 } /* Literal.String.Interpol */
.highlight .sx { color: #2B2; background-color: #F0FFF0 } /* Literal.String.Other */
.highlight .sr { color: #080; background-color: #FFF0FF } /* Literal.String.Regex */
.highlight .s1 { color: #D20; background-color: #FFF0F0 } /* Literal.String.Single */
.highlight .ss { color: #A60; background-color: #FFF0F0 } /* Literal.String.Symbol */
.highlight .bp { color: #038 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #06B; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #369 } /* Name.Variable.Class */
.highlight .vg { color: #D70 } /* Name.Variable.Global */
.highlight .vi { color: #33B } /* Name.Variable.Instance */
.highlight .vm { color: #369 } /* Name.Variable.Magic */
.highlight .il { color: #00D; font-weight: bold } /* Literal.Number.Integer.Long */
<script>
	export let locations;

	import { onMount, onDestroy } from 'svelte';
	import { browser } from '$app/environment';

	import html2canvas from 'html2canvas';

	function captureHighResMap(mapElement, scale = 2) {
		// Backup original size
		let originalWidth = mapElement.offsetWidth;
		let originalHeight = mapElement.offsetHeight;

		// Scale the map element
		mapElement.style.transform = `scale(${scale})`;
		mapElement.style.transformOrigin = 'top left';
		mapElement.style.width = originalWidth * scale + 'px';
		mapElement.style.height = originalHeight * scale + 'px';

		return html2canvas(mapElement, {
			width: originalWidth * scale,
			height: originalHeight * scale,
			scale: scale
		}).then((canvas) => {
			// Restore the original size
			mapElement.style.transform = '';
			mapElement.style.width = originalWidth + 'px';
			mapElement.style.height = originalHeight + 'px';

			return canvas;
		});
	}

	let mapElement;
	let map;

	function updateLabelVisibility() {
		const zoom = map.getZoom();
		map.eachLayer((layer) => {
			if (layer.getTooltip) {
				const tooltip = layer.getTooltip();
				if (tooltip) {
					if (zoom > 14) {
						// Show labels at zoom levels greater than 14
						tooltip.setOpacity(1.0);
					} else {
						tooltip.setOpacity(0.0);
					}
				}
			}
		});
	}

	onMount(async () => {
		if (browser) {
			const L = await import('leaflet');

			map = L.map(mapElement, {
				zoomSnap: 0,
				attributionControl: false
			}).setView([49.26, -123.05], 12);

			const myCustomColour = '#F7931A';

			const markerHtmlStyles = `
			  background-color: ${myCustomColour};
			  width: 1.2rem;
			  height: 1.2rem;
			  display: block;
			  position: relative;
        border-radius: 100% 100% 0;
			  transform: rotate(45deg);
        opacity: 0.9;
			  border: 1px solid #666`;

			const icon = L.divIcon({
				className: 'my-custom-pin',
				iconAnchor: [0, 24],
				labelAnchor: [-6, 0],
				popupAnchor: [0, -36],
				html: `<span style="${markerHtmlStyles}" />`
			});

			locations = locations.filter(
				(location) =>
					location['osm_json'].tags &&
					location['osm_json'].tags['payment:coinos'] === 'yes' &&
					location['osm_json'].lat &&
					location['osm_json'].lon
			);

			L.tileLayer('https://stamen-tiles-{s}.a.ssl.fastly.net/toner/{z}/{x}/{y}.png', {
				maxZoom: 18,
				subdomains: ['a', 'b', 'c', 'd']
			}).addTo(map);

			const checkAddress = (location) => {
				if (location['addr:housenumber'] && location['addr:street'] && location['addr:city']) {
					return `${
						location['addr:housenumber'] +
						' ' +
						location['addr:street'] +
						', ' +
						location['addr:city']
					}`;
				} else if (location['addr:street'] && location['addr:city']) {
					return `${location['addr:street'] + ', ' + location['addr:city']}`;
				} else if (location['addr:city']) {
					return `${location['addr:city']}`;
				} else {
					return '';
				}
			};

			locations.forEach((location) => {
				if (location['deleted_at']) return;

				location = location['osm_json'];
				let marker = L.marker([location.lat, location.lon], { icon });

				if (location.tags && location.tags.name) {
					marker.bindTooltip(location.tags.name, { permanent: true }).openTooltip();
				}

				marker.bindPopup(
					`${
						location.tags && location.tags.name
							? `<span class='block'>${location.tags.name}</span>`
							: ''
					}

          <span class='block'>${location.tags && checkAddress(location.tags)}</span>

          ${
						location.tags && location.tags.phone
							? `<a href='tel:${location.tags.phone}' class='block'>${location.tags.phone}</a>`
							: ''
					}

          ${
						location.tags && location.tags.website
							? `<a href=${location.tags.website} target="_blank" rel="noreferrer" class='block'>${location.tags.website}</a>`
							: ''
					}

					${
						location.tags && location.tags['contact:twitter']
							? `<a href=${
									location.tags['contact:twitter'].startsWith('http')
										? location.tags['contact:twitter']
										: `https://twitter.com/${location.tags['contact:twitter']}`
							  } target="_blank" rel="noreferrer" class='block'>TWT: ${
									location.tags['contact:twitter']
							  }</a>`
							: ''
					}

	        ${
						location.tags && location.tags['contact:instagram']
							? `<a href=${
									location.tags['contact:instagram'].startsWith('http')
										? location.tags['contact:instagram']
										: `https://instagram.com/${location.tags['contact:instagram']}`
							  } target="_blank" rel="noreferrer" class='block'>IG: ${
									location.tags['contact:instagram']
							  }</a>`
							: ''
					}

	        ${
						location.tags && location.tags['contact:facebook']
							? `<a href=${
									location.tags['contact:facebook'].startsWith('http')
										? location.tags['contact:facebook']
										: `https://facebook.com/${location.tags['contact:facebook']}`
							  } target="_blank" rel="noreferrer" class='block'>FB: ${
									location.tags['contact:facebook']
							  }</a>`
							: ''
					}

	        ${
						location.tags && location.tags['contact:linkedin']
							? `<a href=${
									location.tags['contact:linkedin'].startsWith('http')
										? location.tags['contact:linkedin']
										: `https://linkedin.com/${location.tags['contact:linkedin']}`
							  } target="_blank" rel="noreferrer" class='block'>LI: ${
									location.tags['contact:linkedin']
							  }</a>`
							: ''
					}`
				);
				marker.addTo(map);
			});

			updateLabelVisibility();
			map.on('zoomend', updateLabelVisibility);
			// map.fitBounds(locations.map(({ osm_json: { lat, lon } }) => [lat, lon]));
		}
	});

	onDestroy(async () => {
    if (map) {
      map.off('zoomend', updateLabelVisibility);
      map.remove();
    } 
	});
</script>

<div class="container mx-auto max-w-4xl">
	<div class="flex w-full">
		<div class="mx-auto h-[550px] w-full z-0" bind:this={mapElement} />
	</div>
</div>

<style>
	@import 'leaflet/dist/leaflet.css';

	:global(.leaflet-tooltip) {
		border: none;
		border-radius: 4px;
		font-size: 12px;
		font-weight: bolder;
		color: black;
		background-color: rgba(255, 255, 255, 0.9);
    left: 1.3rem;
    top: -1rem;
	}
</style>