aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorHsieh Chin Fan <pham@topo.tw>2024-11-03 13:58:38 +0800
committerHsieh Chin Fan <pham@topo.tw>2024-11-03 14:36:15 +0800
commitf4910b66e74034db14619ee384dc261423dc19fc (patch)
tree78382b3bb600b61a43b48d417cfbe3873d8da623
parent3086cc484857dea32a33f829ec173adaf0cf8fbe (diff)
feat: use bbox to update camera for result of Geocoding
* show markers from all Geocoding Results * update mapclay for latest updateCamera method * 3 steps for camera animation: 1. zoom out to bbox which contains all Geocoding Result 2. pan to marker of hovered result 3. zoom in to bbox from nonimatim query * remove markers except selected Geocoding Result
-rw-r--r--package.json2
-rw-r--r--src/Link.mjs2
-rw-r--r--src/MenuItem.mjs65
-rw-r--r--src/utils.mjs1
4 files changed, 53 insertions, 17 deletions
diff --git a/package.json b/package.json
index a08a286..64ed496 100644
--- a/package.json
+++ b/package.json
@@ -44,7 +44,7 @@
44 "cssprefix": "^2.0.17", 44 "cssprefix": "^2.0.17",
45 "easymde": "^2.18.0", 45 "easymde": "^2.18.0",
46 "leader-line": "^1.0.7", 46 "leader-line": "^1.0.7",
47 "mapclay": "^0.9.0", 47 "mapclay": "^0.9.2",
48 "markdown-it": "^14.1.0", 48 "markdown-it": "^14.1.0",
49 "markdown-it-anchor": "^9.2.0", 49 "markdown-it-anchor": "^9.2.0",
50 "markdown-it-footnote": "^4.0.0", 50 "markdown-it-footnote": "^4.0.0",
diff --git a/src/Link.mjs b/src/Link.mjs
index 7678f3a..685de3a 100644
--- a/src/Link.mjs
+++ b/src/Link.mjs
@@ -227,7 +227,7 @@ const isAnchorVisible = anchor => {
227 */ 227 */
228export const updateMapCameraByMarker = lonLat => marker => { 228export const updateMapCameraByMarker = lonLat => marker => {
229 const renderer = marker.closest('.mapclay')?.renderer 229 const renderer = marker.closest('.mapclay')?.renderer
230 renderer.updateCamera({ center: lonLat }, true) 230 renderer?.updateCamera?.({ center: lonLat, animation: true })
231} 231}
232 232
233/** 233/**
diff --git a/src/MenuItem.mjs b/src/MenuItem.mjs
index 6c6e6cf..8bee5c1 100644
--- a/src/MenuItem.mjs
+++ b/src/MenuItem.mjs
@@ -1,7 +1,7 @@
1import { shiftByWindow } from './utils.mjs' 1import { onRemove, shiftByWindow } from './utils.mjs'
2import { addMarkerByPoint } from './dumbyUtils.mjs' 2import { addMarkerByPoint } from './dumbyUtils.mjs'
3/* eslint-disable-next-line no-unused-vars */ 3/* eslint-disable-next-line no-unused-vars */
4import { GeoLink, getMarkersFromMaps, getMarkersByGeoLink, removeLeaderLines, updateMapCameraByMarker } from './Link.mjs' 4import { GeoLink, getMarkersFromMaps, getMarkersByGeoLink, removeLeaderLines } from './Link.mjs'
5import * as markers from './marker.mjs' 5import * as markers from './marker.mjs'
6import { parseConfigsFromYaml } from 'mapclay' 6import { parseConfigsFromYaml } from 'mapclay'
7 7
@@ -606,8 +606,8 @@ export const addLinkbyGeocoding = (range) => {
606 /** Add spinning circle for Network */ 606 /** Add spinning circle for Network */
607 e.target.classList.add('with-spinning-circle') 607 e.target.classList.add('with-spinning-circle')
608 const menu = e.target.closest('.dumby-menu') 608 const menu = e.target.closest('.dumby-menu')
609
610 if (!menu) return 609 if (!menu) return
610
611 /** Geocoding by Nominatim */ 611 /** Geocoding by Nominatim */
612 // TODO Add more params like limit: 612 // TODO Add more params like limit:
613 // https://nominatim.org/release-docs/latest/api/Search/ 613 // https://nominatim.org/release-docs/latest/api/Search/
@@ -623,36 +623,71 @@ export const addLinkbyGeocoding = (range) => {
623 } 623 }
624 624
625 // Add items for each results 625 // Add items for each results
626 const items = places.map(geocodingResult((a) => { 626 const bbox = places.map(p => p.boundingbox).reduce((acc, cur) => [
627 Math.min(acc[0], cur[0]),
628 Math.max(acc[1], cur[1]),
629 Math.min(acc[2], cur[2]),
630 Math.max(acc[3], cur[3]),
631 ])
632 const bounds = [[bbox[2], bbox[0]], [bbox[3], bbox[1]]]
633 const items = places.map(geocodingResult(bounds, (a) => {
627 a.className = 'not-geolink from-geocoding' 634 a.className = 'not-geolink from-geocoding'
628 a.textContent = query 635 a.textContent = query
629 range.deleteContents() 636 range.deleteContents()
630 range.insertNode(a) 637 range.insertNode(a)
631 })) 638 }))
632 menu.replaceChildren(...items) 639 menu.replaceChildren(...items)
640 shiftByWindow(menu)
633 }, 641 },
634 }) 642 })
635} 643}
636 644
637export const geocodingResult = (callback) => (result) => { 645/**
646 * geocodingResult.
647 *
648 * @param {Array<Number[]>} bounds - boundingbox in format: [minLon, minLat, maxLon, maxLat]
649 * @param {Function} callback
650 */
651export const geocodingResult = (bounds, callback) => (result) => {
638 const item = Item({ 652 const item = Item({
639 text: result.display_name, 653 text: result.display_name,
640 onclick: () => { 654 onclick: (e) => {
655 e.target.classList.add('clicked')
656
641 const a = document.createElement('a') 657 const a = document.createElement('a')
642 a.href = `geo:${result.lat},${result.lon}?name=${result.name}&osm=${result.osm_type}/${result.osm_id}` 658 a.href = `geo:${result.lat},${result.lon}` +
659 `?name=${result.name}` +
660 `&osm=${result.osm_type}/${result.osm_id}`
643 a.title = result.display_name 661 a.title = result.display_name
644 callback(a) 662 callback(a)
645 }, 663 },
646 }) 664 })
665
666 const xy = [result.lon, result.lat]
667
668 const markers = getMarkersFromMaps(xy, {
669 type: 'circle',
670 title: result.display_name,
671 })
672 const bbox = result.boundingbox
673 const resultBounds = [[bbox[2], bbox[0]], [bbox[3], bbox[1]]]
674
647 item.onmouseover = () => { 675 item.onmouseover = () => {
648 const markers = getMarkersFromMaps( 676 markers.forEach(async marker => {
649 [result.lon, result.lat], 677 const renderer = marker.closest('.mapclay')?.renderer
650 { type: 'circle', title: result.display_name }, 678 await renderer.updateCamera({ bounds, duration: 1000, animation: true, padding: 20 })
651 ) 679 await renderer.updateCamera({ center: xy, duration: 600, animation: true })
652 markers.forEach(updateMapCameraByMarker([result.lon, result.lat])) 680 await renderer.updateCamera({ bounds: resultBounds, duration: 1500, animation: true, padding: 20 })
653 item.onmouseout = () => { 681 })
654 markers.forEach(m => m.remove())
655 }
656 } 682 }
683
684 setTimeout(() => {
685 onRemove(item.closest('.menu'), () => {
686 if (item.classList.contains('clicked')) return
687 markers.forEach(marker => marker.remove())
688 }),
689 100
690 })
691
657 return item 692 return item
658} 693}
diff --git a/src/utils.mjs b/src/utils.mjs
index c0da23a..4cce323 100644
--- a/src/utils.mjs
+++ b/src/utils.mjs
@@ -113,6 +113,7 @@ export function debounce (func, delay = 1000) {
113 * @param {HTMLElement} element 113 * @param {HTMLElement} element
114 */ 114 */
115export const shiftByWindow = element => { 115export const shiftByWindow = element => {
116 delete element.style.transform
116 const rect = element.getBoundingClientRect() 117 const rect = element.getBoundingClientRect()
117 const offsetX = window.innerWidth - rect.left - rect.width 118 const offsetX = window.innerWidth - rect.left - rect.width
118 const offsetY = window.innerHeight - rect.top - rect.height 119 const offsetY = window.innerHeight - rect.top - rect.height