diff options
| author | Hsieh Chin Fan <pham@topo.tw> | 2024-10-31 17:11:55 +0800 |
|---|---|---|
| committer | Hsieh Chin Fan <pham@topo.tw> | 2024-11-03 14:01:05 +0800 |
| commit | 1fc35b33eacf0f06370fc14798f65f5ec0972195 (patch) | |
| tree | c745d7c1691d4baa92d208bcee26abacb5485d0c /src | |
| parent | 11ff731337c6823e74821d06457972c6d0528c34 (diff) | |
feat: patch 7ee1ad6
* add spinning circle for Networking UX
* display marker for each results
Diffstat (limited to 'src')
| -rw-r--r-- | src/MenuItem.mjs | 75 | ||||
| -rw-r--r-- | src/css/dumbymap.css | 18 | ||||
| -rw-r--r-- | src/dumbymap.mjs | 13 |
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 @@ | |||
| 1 | import { shiftByWindow } from './utils.mjs' | 1 | import { shiftByWindow } from './utils.mjs' |
| 2 | import { addMarkerByPoint } from './dumbyUtils.mjs' | 2 | import { addMarkerByPoint } from './dumbyUtils.mjs' |
| 3 | /* eslint-disable-next-line no-unused-vars */ | 3 | /* eslint-disable-next-line no-unused-vars */ |
| 4 | import { GeoLink, getMarkersFromMaps, removeLeaderLines } from './Link.mjs' | 4 | import { GeoLink, getMarkersFromMaps, getMarkersByGeoLink, removeLeaderLines, updateMapCameraByMarker } from './Link.mjs' |
| 5 | import * as markers from './marker.mjs' | 5 | import * as markers from './marker.mjs' |
| 6 | import { parseConfigsFromYaml } from 'mapclay' | 6 | import { parseConfigsFromYaml } from 'mapclay' |
| 7 | 7 | ||
| @@ -587,25 +587,66 @@ export const editMap = (map, dumbymap) => { | |||
| 587 | }) | 587 | }) |
| 588 | } | 588 | } |
| 589 | 589 | ||
| 590 | export const addLinkbyNominatim = (range) => { | 590 | /** |
| 591 | * addLinkbyGeocoding. | ||
| 592 | * | ||
| 593 | * @param {Range} range | ||
| 594 | */ | ||
| 595 | export 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 | |||
| 631 | export 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 */ |