aboutsummaryrefslogtreecommitdiffstats
path: root/src/components
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2023-08-29 21:19:03 -0700
committerAdam Soltys <[email protected]>2023-08-29 21:19:03 -0700
commitfb6345ee9f072b278dd2bd74d0a595fd2ac14972 (patch)
tree049acc50b37a46c4556ca9882a888e7dedbcd551 /src/components
parentaade50c019c31824f6eeffa93ebd04d0647dede6 (diff)
downloadcoinos-ui-fb6345ee9f072b278dd2bd74d0a595fd2ac14972.tar.gz
coinos-ui-fb6345ee9f072b278dd2bd74d0a595fd2ac14972.zip
tooltip collision attempts
Diffstat (limited to 'src/components')
-rw-r--r--src/components/LocationsMap.svelte237
1 files changed, 223 insertions, 14 deletions
diff --git a/src/components/LocationsMap.svelte b/src/components/LocationsMap.svelte
index 37dd60ba..a5215e9a 100644
--- a/src/components/LocationsMap.svelte
+++ b/src/components/LocationsMap.svelte
@@ -39,23 +39,23 @@
const L = await import('leaflet');
map = L.map(mapElement, {
- zoomSnap: 0,
- attributionControl: false,
- }).setView([49.26, -123.05], 12);
-
+ zoomSnap: 0,
+ zoomControl: false,
+ attributionControl: false
+ }).setView([49.26, -123.05], 12.5);
const myCustomColour = '#F7931A';
const markerHtmlStyles = `
background-color: ${myCustomColour};
- width: 1.2rem;
- height: 1.2rem;
+ width: 2rem;
+ height: 2rem;
display: block;
position: relative;
border-radius: 100% 100% 0;
transform: rotate(45deg);
opacity: 0.9;
- border: 1px solid #666`;
+ border: 5px solid #000`;
const icon = L.divIcon({
className: 'my-custom-pin',
@@ -178,18 +178,227 @@
marker.addTo(map);
});
- // map.fitBounds(locations.map(({ osm_json: { lat, lon } }) => [lat, lon]));
+ tooltips = Array.from(document.querySelectorAll('.leaflet-tooltip'));
}
});
+ const tenIterations = () => {
+ let anyAdjustment = true;
+ for (let i = 0; i < 10; i++) {
+ if (anyAdjustment) iterate();
+ else break;
+ }
+ };
+
+ const iterate = () => {
+ let anyAdjustment = false;
+
+ for (const tooltipA of tooltips) {
+ for (const tooltipB of tooltips) {
+ if (tooltipA === tooltipB) continue;
+
+ if (areOverlapping(getBoundingRect(tooltipA), getBoundingRect(tooltipB))) {
+ const originalPosA = {
+ top: parseInt(tooltipA.dataset.originalTop, 10),
+ left: parseInt(tooltipA.dataset.originalLeft, 10)
+ };
+ const direction = ['up', 'down', 'left', 'right'][Math.floor(Math.random() * 4)];
+
+ adjustPosition(tooltipA, direction);
+
+ const adjustedPosA = {
+ top: parseInt(tooltipA.style.top, 10),
+ left: parseInt(tooltipA.style.left, 10)
+ };
+ console.log(adjustedPosA);
+ const distanceFromOriginalA = Math.sqrt(
+ Math.pow(adjustedPosA.top - originalPosA.top, 2) +
+ Math.pow(adjustedPosA.left - originalPosA.left, 2)
+ );
+
+ console.log('DIST', distanceFromOriginalA);
+
+ if (distanceFromOriginalA > MAX_DISTANCE) {
+ // If tooltip has strayed too far from the marker, revert the last movement.
+ adjustPosition(
+ tooltipA,
+ {
+ up: 'down',
+ down: 'up',
+ left: 'right',
+ right: 'left'
+ }[direction]
+ );
+ } else {
+ anyAdjustment = true;
+ }
+ }
+ }
+ }
+
+ return anyAdjustment;
+ };
+
+ const MAX_ITERATIONS = 80;
+ const MAX_DISTANCE = 300; // maximum distance from the marker
+ const ADJUSTMENT_FACTOR = 10;
+
+ let tooltips;
+
+ const getBoundingRect = (elem) => {
+ return elem.getBoundingClientRect();
+ };
+
+ const areOverlapping = (rect1, rect2) => {
+ return !(
+ rect1.right < rect2.left ||
+ rect1.left > rect2.right ||
+ rect1.bottom < rect2.top ||
+ rect1.top > rect2.bottom
+ );
+ };
+
+ const adjustPosition = (tooltip, direction) => {
+ let computedStyle = getComputedStyle(tooltip);
+ const currentTop = parseInt(computedStyle.top);
+ const currentLeft = parseInt(computedStyle.left);
+ // console.log(currentTop, currentLeft);
+ switch (direction) {
+ case 'up':
+ tooltip.style.top = currentTop - ADJUSTMENT_FACTOR + 'px';
+ break;
+ case 'down':
+ tooltip.style.top = currentTop + ADJUSTMENT_FACTOR + 'px';
+ break;
+ case 'left':
+ tooltip.style.left = currentLeft - ADJUSTMENT_FACTOR + 'px';
+ break;
+ case 'right':
+ tooltip.style.left = currentLeft + ADJUSTMENT_FACTOR + 'px';
+ break;
+ }
+ };
+
+ function initializeGrid(tooltips) {
+ const grid = [];
+ const gridSize = 10; // Adjust based on how granular you want the grid to be.
+
+ console.log(tooltips.length)
+
+ tooltips.forEach((tooltip) => {
+ const style = getComputedStyle(tooltip);
+
+ const position = {
+ left: parseInt(style.left, 10),
+ top: parseInt(style.top, 10)
+ };
+
+ const size = {
+ width: parseInt(style.width, 10),
+ height: parseInt(style.height, 10)
+ };
+
+ for (let y = position.top; y < position.top + size.height; y += gridSize) {
+ for (let x = position.left; x < position.left + size.width; x += gridSize) {
+ const key = `${Math.floor(x / gridSize)}-${Math.floor(y / gridSize)}`;
+ grid[key] = true;
+ }
+ }
+ });
+
+ return grid;
+ }
+
+ function checkOverlap(position, size, grid, gridSize = 10) {
+ for (let y = position.top; y < position.top + size.height; y += gridSize) {
+ for (let x = position.left; x < position.left + size.width; x += gridSize) {
+ const key = `${Math.floor(x / gridSize)}-${Math.floor(y / gridSize)}`;
+ if (grid[key]) return true;
+ }
+ }
+ return false;
+ }
+
+ function findClosestAvailableSpace(position, size, grid, gridSize = 10) {
+ let bestPosition = null;
+ let bestDistance = Infinity;
+
+ for (let y = 0; y < window.innerHeight; y += gridSize) {
+ for (let x = 0; x < window.innerWidth; x += gridSize) {
+ const testPosition = { left: x, top: y };
+ if (!checkOverlap(testPosition, size, grid, gridSize)) {
+ const distance = Math.sqrt(
+ Math.pow(position.left - testPosition.left, 2) +
+ Math.pow(position.top - testPosition.top, 2)
+ );
+
+ if (distance < bestDistance) {
+ bestDistance = distance;
+ bestPosition = testPosition;
+ }
+ }
+ }
+ }
+
+ return bestDistance < MAX_DISTANCE ? bestPosition : position;
+ }
+
+ function positionTooltips() {
+ console.log("HI");
+ const grid = initializeGrid(tooltips);
+ const gridSize = 10;
+
+ console.log("GRID", grid)
+
+ tooltips.forEach((tooltip) => {
+ const style = getComputedStyle(tooltip);
+
+ const position = {
+ left: parseInt(style.left, 10),
+ top: parseInt(style.top, 10)
+ };
+
+ const size = {
+ width: parseInt(style.width, 10),
+ height: parseInt(style.height, 10)
+ };
+
+ const overlap = checkOverlap(position, size, grid, gridSize);
+ console.log("OVERLAP", overlap, tooltip.innerHTML)
+ if (overlap) {
+ const newSpace = findClosestAvailableSpace(position, size, grid, gridSize);
+ if (newSpace) {
+ console.log("NEWSPACE", newSpace)
+ tooltip.style.left = newSpace.left + 'px';
+ tooltip.style.top = newSpace.top + 'px';
+
+ for (let y = position.top; y < position.top + size.height; y += gridSize) {
+ for (let x = position.left; x < position.left + size.width; x += gridSize) {
+ const key = `${Math.floor(x / gridSize)}-${Math.floor(y / gridSize)}`;
+ grid[key] = false;
+ }
+ }
+
+ // Updating grid with new tooltip position
+ for (let y = newSpace.top; y < newSpace.top + size.height; y += gridSize) {
+ for (let x = newSpace.left; x < newSpace.left + size.width; x += gridSize) {
+ const key = `${Math.floor(x / gridSize)}-${Math.floor(y / gridSize)}`;
+ grid[key] = true;
+ }
+ }
+ }
+ }
+ });
+ }
+
+
onDestroy(async () => map && 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>
+<!-- <div class="mx-auto w-[14043px] h-[9933px] w-full z-0" bind:this={mapElement} /> -->
+<div class="mx-auto w-[1000px] h-[600px] w-full z-0" bind:this={mapElement} />
+
+<button on:click={positionTooltips}>Iterate</button>
<style>
@import 'leaflet/dist/leaflet.css';
@@ -197,7 +406,7 @@
:global(.leaflet-tooltip) {
border: none;
border-radius: 4px;
- font-size: 12px;
+ font-size: 1rem;
font-weight: bolder;
color: black;
background-color: rgba(255, 255, 255, 0.5);