aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorHsieh Chin Fan <pham@topo.tw>2024-10-31 17:11:55 +0800
committerHsieh Chin Fan <pham@topo.tw>2024-11-03 14:01:05 +0800
commit1fc35b33eacf0f06370fc14798f65f5ec0972195 (patch)
treec745d7c1691d4baa92d208bcee26abacb5485d0c
parent11ff731337c6823e74821d06457972c6d0528c34 (diff)
feat: patch 7ee1ad6
* add spinning circle for Networking UX * display marker for each results
-rw-r--r--src/MenuItem.mjs75
-rw-r--r--src/css/dumbymap.css18
-rw-r--r--src/dumbymap.mjs13
3 files changed, 86 insertions, 20 deletions
diff --git a/src/MenuItem.mjs b/src/MenuItem.mjs
index 84a1405..464dd2d 100644
--- a/src/MenuItem.mjs
+++ b/src/MenuItem.mjs
@@ -1,7 +1,7 @@
1import { shiftByWindow } from './utils.mjs' 1import { 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, removeLeaderLines } from './Link.mjs' 4import { GeoLink, getMarkersFromMaps, getMarkersByGeoLink, removeLeaderLines, updateMapCameraByMarker } 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
@@ -587,25 +587,66 @@ export const editMap = (map, dumbymap) => {
587 }) 587 })
588} 588}
589 589
590export const addLinkbyNominatim = (range) => { 590/**
591 * addLinkbyGeocoding.
592 *
593 * @param {Range} range
594 */
595export const addLinkbyGeocoding = (range) => {
591 return Item({ 596 return Item({
592 text: 'Add Link by Geocoding', 597 text: 'Add Link by Geocoding',
598 className: ['keep-menu'],
599 onclick: async (e) => {
600 /** Add spinning circle for Network */
601 e.target.classList.add('with-spinning-circle')
602 const menu = e.target.closest('.dumby-menu')
603
604 if (!menu) return
605 /** Geocoding by Nominatim */
606 // TODO Add more params like limit:
607 // https://nominatim.org/release-docs/latest/api/Search/
608 const query = range.toString()
609 const response = await fetch(`https://nominatim.openstreetmap.org/search?q=${query.toString()}&format=json`)
610 const places = await response.json()
611 menu.replaceChildren()
612
613 // Show Message if no result found
614 if (places.length === 0) {
615 menu.appendChild(Item({ text: 'No Result Found' }))
616 return
617 }
618
619 // Add items for each results
620 const items = places.map(geocodingResult((a) => {
621 a.className = 'not-geolink from-geocoding'
622 a.textContent = query
623 range.deleteContents()
624 range.insertNode(a)
625 }))
626 menu.replaceChildren(...items)
627 },
628 })
629}
630
631export const geocodingResult = (callback) => (result) => {
632 const item = Item({
633 text: result.display_name,
593 onclick: () => { 634 onclick: () => {
594 const place = range.toString() 635 const a = document.createElement('a')
595 fetch(`https://nominatim.openstreetmap.org/search?q=${place.toString()}&format=json`) 636 a.href = `geo:${result.lat},${result.lon}?name=${result.name}&osm=${result.osm_type}/${result.osm_id}`
596 .then(res => res.json()) 637 a.title = result.display_name
597 .then(places => { 638 callback(a)
598 if (places.length === 0) return
599 console.log('nomiatim', places)
600 range.deleteContents()
601 places.forEach(p => {
602 const a = document.createElement('a')
603 a.className = 'not-geolink from-geocoding'
604 a.href = `geo:${p.lat},${p.lon}?name=${p.name}&osm=${p.osm_type}/${p.osm_id}`
605 a.textContent = place
606 range.insertNode(a)
607 })
608 })
609 }, 639 },
610 }) 640 })
641 item.onmouseover = () => {
642 const markers = getMarkersFromMaps(
643 [result.lon, result.lat],
644 { type: 'circle', title: result.display_name },
645 )
646 markers.forEach(updateMapCameraByMarker([result.lon, result.lat]))
647 item.onmouseout = () => {
648 markers.forEach(m => m.remove())
649 }
650 }
651 return item
611} 652}
diff --git a/src/css/dumbymap.css b/src/css/dumbymap.css
index f0b4575..4b3aa52 100644
--- a/src/css/dumbymap.css
+++ b/src/css/dumbymap.css
@@ -48,6 +48,16 @@ root {
48 } 48 }
49} 49}
50 50
51@keyframes spin {
52 0% {
53 transform: rotate(0deg);
54 }
55
56 100% {
57 transform: rotate(360deg);
58 }
59}
60
51.external::after { 61.external::after {
52 content: ''; 62 content: '';
53 display: inline-block; 63 display: inline-block;
@@ -747,3 +757,11 @@ textarea .edit-map {
747 font-size: 1.1rem; 757 font-size: 1.1rem;
748 line-height: 1.5; 758 line-height: 1.5;
749} 759}
760
761.with-spinning-circle::after {
762 content: '\21BB';
763 display: inline-block;
764 margin-left: 1rem;
765
766 animation: spin 2s linear infinite;
767}
diff --git a/src/dumbymap.mjs b/src/dumbymap.mjs
index 77f3515..217c1b6 100644
--- a/src/dumbymap.mjs
+++ b/src/dumbymap.mjs
@@ -534,6 +534,7 @@ export const generateMaps = (container, {
534 534
535 /** MENU: Menu Items for Context Menu */ 535 /** MENU: Menu Items for Context Menu */
536 container.oncontextmenu = e => { 536 container.oncontextmenu = e => {
537 /** Check if OK to show custom menu over context menu */
537 if (container.dataset.menu === 'disabled') return 538 if (container.dataset.menu === 'disabled') return
538 539
539 container.querySelectorAll('.dumby-menu').forEach(m => m.remove()) 540 container.querySelectorAll('.dumby-menu').forEach(m => m.remove())
@@ -554,6 +555,10 @@ export const generateMaps = (container, {
554 container.appendChild(menu) 555 container.appendChild(menu)
555 const containerRect = container.getBoundingClientRect() 556 const containerRect = container.getBoundingClientRect()
556 new window.MutationObserver(() => { 557 new window.MutationObserver(() => {
558 if (menu.childElementCount === 0) {
559 menu.style.display = 'none'
560 return
561 }
557 menu.style.display = 'block' 562 menu.style.display = 'block'
558 menu.style.left = (e.pageX - containerRect.left + 10) + 'px' 563 menu.style.left = (e.pageX - containerRect.left + 10) + 'px'
559 menu.style.top = (e.pageY - containerRect.top + 5) + 'px' 564 menu.style.top = (e.pageY - containerRect.top + 5) + 'px'
@@ -565,8 +570,10 @@ export const generateMaps = (container, {
565 if (rangeSelected) { 570 if (rangeSelected) {
566 // TODO check click is inside selection 571 // TODO check click is inside selection
567 const range = document.getSelection().getRangeAt(0) 572 const range = document.getSelection().getRangeAt(0)
568 menu.appendChild(menuItem.addLinkbyNominatim(range)) 573 menu.appendChild(menuItem.addLinkbyGeocoding(range))
574 return menu
569 } 575 }
576
570 /** Menu Item for editing map */ 577 /** Menu Item for editing map */
571 const mapEditor = e.target.closest('.edit-map') 578 const mapEditor = e.target.closest('.edit-map')
572 if (mapEditor) { 579 if (mapEditor) {
@@ -574,7 +581,7 @@ export const generateMaps = (container, {
574 text: 'Finish Editig', 581 text: 'Finish Editig',
575 onclick: () => mapEditor.blur(), 582 onclick: () => mapEditor.blur(),
576 })) 583 }))
577 return 584 return menu
578 } 585 }
579 586
580 /** Menu Items for Links */ 587 /** Menu Items for Links */
@@ -621,7 +628,7 @@ export const generateMaps = (container, {
621 628
622 if (linkWithLine) { 629 if (linkWithLine) {
623 menu.appendChild(menuItem.setLeaderLineType(linkWithLine)) 630 menu.appendChild(menuItem.setLeaderLineType(linkWithLine))
624 return 631 return menu
625 } 632 }
626 633
627 /** Menu Items for map */ 634 /** Menu Items for map */