From 1fc35b33eacf0f06370fc14798f65f5ec0972195 Mon Sep 17 00:00:00 2001 From: Hsieh Chin Fan Date: Thu, 31 Oct 2024 17:11:55 +0800 Subject: feat: patch 7ee1ad6 * add spinning circle for Networking UX * display marker for each results --- src/MenuItem.mjs | 75 ++++++++++++++++++++++++++++++++++++++++------------ src/css/dumbymap.css | 18 +++++++++++++ src/dumbymap.mjs | 13 ++++++--- 3 files changed, 86 insertions(+), 20 deletions(-) (limited to 'src') 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 @@ import { shiftByWindow } from './utils.mjs' import { addMarkerByPoint } from './dumbyUtils.mjs' /* eslint-disable-next-line no-unused-vars */ -import { GeoLink, getMarkersFromMaps, removeLeaderLines } from './Link.mjs' +import { GeoLink, getMarkersFromMaps, getMarkersByGeoLink, removeLeaderLines, updateMapCameraByMarker } from './Link.mjs' import * as markers from './marker.mjs' import { parseConfigsFromYaml } from 'mapclay' @@ -587,25 +587,66 @@ export const editMap = (map, dumbymap) => { }) } -export const addLinkbyNominatim = (range) => { +/** + * addLinkbyGeocoding. + * + * @param {Range} range + */ +export const addLinkbyGeocoding = (range) => { return Item({ text: 'Add Link by Geocoding', + className: ['keep-menu'], + onclick: async (e) => { + /** Add spinning circle for Network */ + e.target.classList.add('with-spinning-circle') + const menu = e.target.closest('.dumby-menu') + + if (!menu) return + /** Geocoding by Nominatim */ + // TODO Add more params like limit: + // https://nominatim.org/release-docs/latest/api/Search/ + const query = range.toString() + const response = await fetch(`https://nominatim.openstreetmap.org/search?q=${query.toString()}&format=json`) + const places = await response.json() + menu.replaceChildren() + + // Show Message if no result found + if (places.length === 0) { + menu.appendChild(Item({ text: 'No Result Found' })) + return + } + + // Add items for each results + const items = places.map(geocodingResult((a) => { + a.className = 'not-geolink from-geocoding' + a.textContent = query + range.deleteContents() + range.insertNode(a) + })) + menu.replaceChildren(...items) + }, + }) +} + +export const geocodingResult = (callback) => (result) => { + const item = Item({ + text: result.display_name, onclick: () => { - const place = range.toString() - fetch(`https://nominatim.openstreetmap.org/search?q=${place.toString()}&format=json`) - .then(res => res.json()) - .then(places => { - if (places.length === 0) return - console.log('nomiatim', places) - range.deleteContents() - places.forEach(p => { - const a = document.createElement('a') - a.className = 'not-geolink from-geocoding' - a.href = `geo:${p.lat},${p.lon}?name=${p.name}&osm=${p.osm_type}/${p.osm_id}` - a.textContent = place - range.insertNode(a) - }) - }) + const a = document.createElement('a') + a.href = `geo:${result.lat},${result.lon}?name=${result.name}&osm=${result.osm_type}/${result.osm_id}` + a.title = result.display_name + callback(a) }, }) + item.onmouseover = () => { + const markers = getMarkersFromMaps( + [result.lon, result.lat], + { type: 'circle', title: result.display_name }, + ) + markers.forEach(updateMapCameraByMarker([result.lon, result.lat])) + item.onmouseout = () => { + markers.forEach(m => m.remove()) + } + } + return item } 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 { } } +@keyframes spin { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } +} + .external::after { content: ''; display: inline-block; @@ -747,3 +757,11 @@ textarea .edit-map { font-size: 1.1rem; line-height: 1.5; } + +.with-spinning-circle::after { + content: '\21BB'; + display: inline-block; + margin-left: 1rem; + + animation: spin 2s linear infinite; +} 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, { /** MENU: Menu Items for Context Menu */ container.oncontextmenu = e => { + /** Check if OK to show custom menu over context menu */ if (container.dataset.menu === 'disabled') return container.querySelectorAll('.dumby-menu').forEach(m => m.remove()) @@ -554,6 +555,10 @@ export const generateMaps = (container, { container.appendChild(menu) const containerRect = container.getBoundingClientRect() new window.MutationObserver(() => { + if (menu.childElementCount === 0) { + menu.style.display = 'none' + return + } menu.style.display = 'block' menu.style.left = (e.pageX - containerRect.left + 10) + 'px' menu.style.top = (e.pageY - containerRect.top + 5) + 'px' @@ -565,8 +570,10 @@ export const generateMaps = (container, { if (rangeSelected) { // TODO check click is inside selection const range = document.getSelection().getRangeAt(0) - menu.appendChild(menuItem.addLinkbyNominatim(range)) + menu.appendChild(menuItem.addLinkbyGeocoding(range)) + return menu } + /** Menu Item for editing map */ const mapEditor = e.target.closest('.edit-map') if (mapEditor) { @@ -574,7 +581,7 @@ export const generateMaps = (container, { text: 'Finish Editig', onclick: () => mapEditor.blur(), })) - return + return menu } /** Menu Items for Links */ @@ -621,7 +628,7 @@ export const generateMaps = (container, { if (linkWithLine) { menu.appendChild(menuItem.setLeaderLineType(linkWithLine)) - return + return menu } /** Menu Items for map */ -- cgit v1.2.3-70-g09d2