Add options to oh-map-page & fix initial positioning (#599)
Fixes #588. Allows to select a tile provider from http://leaflet-extras.github.io/leaflet-providers/preview/ Close #589. Signed-off-by: Yannick Schaus <github@schaus.net>pull/603/head
parent
e7908dc9a3
commit
4508a88c2c
|
@ -10952,6 +10952,11 @@
|
|||
"resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.7.1.tgz",
|
||||
"integrity": "sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw=="
|
||||
},
|
||||
"leaflet-providers": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/leaflet-providers/-/leaflet-providers-1.11.0.tgz",
|
||||
"integrity": "sha512-eu/28vrWZqxv9+fXze/4ZwbjHgaWjyeLS5fDtk95W/myDBRAyaAca/5an6WFSheYyhohuLy94vpBLuGHFXiJog=="
|
||||
},
|
||||
"left-pad": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz",
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
"framework7-vue": "^5.7.12",
|
||||
"later-again": "^0.1.1",
|
||||
"leaflet": "^1.7.1",
|
||||
"leaflet-providers": "^1.11.0",
|
||||
"moo": "^0.5.1",
|
||||
"nearley": "^2.19.6",
|
||||
"pkce-challenge": "^2.1.0",
|
||||
|
|
|
@ -1,12 +1,30 @@
|
|||
// definitions for the map page & markers
|
||||
|
||||
import { WidgetDefinition, pt, pi, pg, pd } from '../helpers'
|
||||
import { WidgetDefinition, pt, pb, pi, pg, pd } from '../helpers'
|
||||
import { actionGroup, actionParams } from '../actions'
|
||||
|
||||
const LabelParam = () => pt('label', 'Label', 'The label on the marker')
|
||||
const ItemParam = () => pi('item', 'Item', 'The Location item this marker will be centered on')
|
||||
const LocationParam = () => pt('location', 'Fixed location', 'The fixed position of the marker if no item is configured or its coordinates are invalid').c('location')
|
||||
|
||||
export const OhMapPageDefinition = () => new WidgetDefinition('oh-map-page', 'Map page', 'Displays markers on a map')
|
||||
.params([
|
||||
pt('initialCenter', 'Initial Center', 'The center to use when no markers are present or have valid positions').c('location'),
|
||||
pt('initialZoom', 'Initial Zoom Level', 'The zoom level to use when no markers are present or have valid positions'),
|
||||
pb('noZoomOrDrag', 'Disable Zooming & Dragging', 'Disable the ability to zoom and drag'),
|
||||
pb('noZoomAnimation', 'No Zoom Animation', 'Change zoom levels without animation, can also avoid graphic glitches with persistent tooltips'),
|
||||
pb('noMarkerZoomAnimation', 'Hide Markers during Zoom Animation').a(),
|
||||
pt('tileLayerProvider', 'Provider for the background tiles', 'The provider of tiles to use for the background of the map. ' +
|
||||
'Use one from <a class="external text-color-blue" target="_blank" href="http://leaflet-extras.github.io/leaflet-providers/preview/">Leaflet Providers</a>, ' +
|
||||
'Some providers will not work until you set options, like access tokens, in the <code>tileLayerProviderOptions</code> parameter (in Code view). ' +
|
||||
'See <a class="external text-color-blue" target="_blank" href="https://github.com/leaflet-extras/leaflet-providers#providers-requiring-registration">here</a> for more info. ' +
|
||||
'The default is CartoDB, the variant depending on the dark mode setting.'),
|
||||
pt('overlayTileLayerProvider', 'Provider for the overlay tiles', 'The provider of tiles to use for the overlay layer above the background of the map. ' +
|
||||
'Use one from <a class="external text-color-blue" target="_blank" href="http://leaflet-extras.github.io/leaflet-providers/preview/">Leaflet Providers</a>, ' +
|
||||
'Some providers will not work until you set options, like access tokens, in the <code>overlayTileLayerProviderOptions</code> parameter (in Code view). ' +
|
||||
'See <a class="external text-color-blue" target="_blank" href="https://github.com/leaflet-extras/leaflet-providers#providers-requiring-registration">here</a> for more info. ')
|
||||
])
|
||||
|
||||
export const OhMapMarkerDefinition = () => new WidgetDefinition('oh-map-marker', 'Map Marker', 'An icon on a map', 'map_pin')
|
||||
.paramGroup(pg('marker', 'Marker', 'General marker settings'), [
|
||||
LabelParam(),
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
export { default as OhMapPage } from './oh-map-page.vue'
|
||||
export { default as OhMapMarker } from './oh-map-marker.vue'
|
||||
export { default as OhMapCircleMarker } from './oh-map-circle-marker.vue'
|
||||
|
|
|
@ -5,14 +5,12 @@
|
|||
:zoom="zoom"
|
||||
:center="center"
|
||||
:options="mapOptions"
|
||||
:zoom-animation="!config.noZoomAnimation"
|
||||
:marker-zoom-animation="!config.noMarkerZoomAnimation"
|
||||
class="oh-map-page-lmap"
|
||||
:class="{ 'with-tabbar': context.tab }"
|
||||
@update:center="centerUpdate"
|
||||
@update:zoom="zoomUpdate">
|
||||
<l-tile-layer
|
||||
:url="url"
|
||||
:attribution="attribution"
|
||||
/>
|
||||
<l-feature-group ref="featureGroup" v-if="context.component.slots">
|
||||
<component v-for="(marker, idx) in context.component.slots.default" :key="idx"
|
||||
:is="markerComponent(marker)" :context="childContext(marker)" @update="onMarkerUpdate" />
|
||||
|
@ -32,13 +30,17 @@
|
|||
|
||||
<script>
|
||||
import mixin from '../widget-mixin'
|
||||
import { latLng, Icon } from 'leaflet'
|
||||
import { tileLayer, latLng, Icon } from 'leaflet'
|
||||
import { LMap, LTileLayer, LFeatureGroup } from 'vue2-leaflet'
|
||||
import 'leaflet/dist/leaflet.css'
|
||||
|
||||
import { OhMapPageDefinition } from '@/assets/definitions/widgets/map'
|
||||
|
||||
import OhMapMarker from './oh-map-marker.vue'
|
||||
import OhMapCircleMarker from './oh-map-circle-marker.vue'
|
||||
|
||||
import 'leaflet-providers'
|
||||
|
||||
delete Icon.Default.prototype._getIconUrl
|
||||
Icon.Default.mergeOptions({
|
||||
iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
|
||||
|
@ -55,22 +57,61 @@ export default {
|
|||
OhMapMarker,
|
||||
OhMapCircleMarker
|
||||
},
|
||||
widget: OhMapPageDefinition,
|
||||
data () {
|
||||
return {
|
||||
zoom: 13,
|
||||
zoom: this.context.component.config.initialZoom || 4,
|
||||
currentZoom: 13,
|
||||
currentCenter: null,
|
||||
center: latLng(52.5200066, 13.4049540),
|
||||
center: (this.context.component.config.initialCenter) ? latLng(this.context.component.config.initialCenter.split(',')) : latLng(48, 6),
|
||||
// url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
url: `https://a.basemaps.cartocdn.com/${this.$f7.data.themeOptions.dark}_all/{z}/{x}/{y}.png`,
|
||||
attribution: '© <a class="external" target="_blank" href="http://osm.org/copyright">OpenStreetMap</a>, © <a class="external" target="_blank" href="https://carto.com/attribution/">CARTO</a>',
|
||||
showMap: true,
|
||||
mapOptions: {
|
||||
zoomSnap: 0.5
|
||||
}
|
||||
showMap: true
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.setBackgroundLayer()
|
||||
this.onMarkerUpdate()
|
||||
},
|
||||
computed: {
|
||||
mapOptions () {
|
||||
return Object.assign({
|
||||
zoomSnap: 0.1
|
||||
}, this.config.noZoomOrDrag ? {
|
||||
dragging: false,
|
||||
touchZoom: false,
|
||||
doubleClickZoom: false,
|
||||
scrollWheelZoom: false,
|
||||
zoomControl: false
|
||||
} : {})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setBackgroundLayer () {
|
||||
const defaultProvider = (this.$f7.data.themeOptions.dark === 'dark') ? 'CartoDB.DarkMatter' : 'CartoDB.Positron'
|
||||
const provider = this.config.tileLayerProvider || defaultProvider
|
||||
let layer, overlayLayer
|
||||
try {
|
||||
layer = tileLayer.provider(provider, this.config.tileLayerProviderOptions)
|
||||
} catch {
|
||||
layer = tileLayer.provider(defaultProvider)
|
||||
}
|
||||
layer.addTo(this.$refs.map.mapObject)
|
||||
|
||||
if (this.config.overlayTileLayerProvider) {
|
||||
try {
|
||||
overlayLayer = tileLayer.provider(this.config.overlayTileLayerProvider, this.config.overlayTileLayerProviderOptions)
|
||||
} catch {}
|
||||
// Workaround for OpenWeatherMap - the old URLs need the "_new" suffix
|
||||
// See: https://openweathermap.org/api/weathermaps
|
||||
if (overlayLayer._url.indexOf('openweather') > 0) {
|
||||
overlayLayer._url = overlayLayer._url.replace('{variant}', '{variant}_new')
|
||||
}
|
||||
overlayLayer.addTo(this.$refs.map.mapObject)
|
||||
}
|
||||
this.$refs.map.mapObject.invalidateSize()
|
||||
},
|
||||
zoomUpdate (zoom) {
|
||||
this.currentZoom = zoom
|
||||
},
|
||||
|
|
|
@ -28,6 +28,14 @@
|
|||
|
||||
<f7-block class="block-narrow" style="padding-bottom: 8rem" v-if="ready && !previewMode">
|
||||
<f7-col>
|
||||
<f7-block-title>Page Configuration</f7-block-title>
|
||||
<config-sheet
|
||||
:parameterGroups="pageWidgetDefinition.props.parameterGroups || []"
|
||||
:parameters="pageWidgetDefinition.props.parameters || []"
|
||||
:configuration="page.config"
|
||||
@updated="dirty = true"
|
||||
/>
|
||||
|
||||
<f7-block-title>Markers</f7-block-title>
|
||||
<f7-menu v-if="clipboardType === 'oh-map-marker'">
|
||||
<f7-menu-item style="margin-left: auto" icon-f7="map" dropdown>
|
||||
|
@ -70,7 +78,7 @@
|
|||
</f7-tab>
|
||||
|
||||
<f7-tab id="code" @tab:show="() => { this.currentTab = 'code' }" :tab-active="currentTab === 'code'">
|
||||
<editor v-if="currentTab === 'code'" :style="{ opacity: previewMode ? '0' : '' }" class="page-code-editor" mode="application/vnd.openhab.uicomponent;type=map" :value="pageYaml" @input="(value) => pageYaml = value" />
|
||||
<editor v-if="currentTab === 'code'" :style="{ opacity: previewMode ? '0' : '' }" class="page-code-editor" mode="application/vnd.openhab.uicomponent+yaml;type=map" :value="pageYaml" @input="(value) => pageYaml = value" />
|
||||
<!-- <pre class="yaml-message padding-horizontal" :class="[yamlError === 'OK' ? 'text-color-green' : 'text-color-red']">{{yamlError}}</pre> -->
|
||||
|
||||
<oh-map-page class="map-page" v-if="ready && previewMode" :context="context" :key="pageKey + '2'" />
|
||||
|
@ -105,6 +113,10 @@ import PageDesigner from '../pagedesigner-mixin'
|
|||
|
||||
import YAML from 'yaml'
|
||||
|
||||
import { TileLayer } from 'leaflet'
|
||||
import 'leaflet-providers'
|
||||
|
||||
import OhMapPage from '@/components/widgets/map/oh-map-page.vue'
|
||||
import OhMapMarker from '@/components/widgets/map/oh-map-marker.vue'
|
||||
import OhMapCircleMarker from '@/components/widgets/map/oh-map-circle-marker.vue'
|
||||
|
||||
|
@ -115,16 +127,63 @@ const ConfigurableWidgets = {
|
|||
|
||||
import PageSettings from '@/components/pagedesigner/page-settings.vue'
|
||||
|
||||
import ConfigSheet from '@/components/config/config-sheet.vue'
|
||||
|
||||
export default {
|
||||
mixins: [PageDesigner],
|
||||
components: {
|
||||
'editor': () => import('@/components/config/controls/script-editor.vue'),
|
||||
'oh-map-page': () => import('@/components/widgets/map/oh-map-page.vue'),
|
||||
PageSettings
|
||||
OhMapPage,
|
||||
PageSettings,
|
||||
ConfigSheet
|
||||
},
|
||||
props: ['createMode', 'uid'],
|
||||
data () {
|
||||
// populate the list of tile providers with variants
|
||||
const isOverlay = function (providerName) {
|
||||
// https://github.com/leaflet-extras/leaflet-providers/blob/bc7482c62f1bbe3737682777716ec946e052deb6/preview/preview.js#L56
|
||||
var overlayPatterns = [
|
||||
'^(OpenWeatherMap|OpenSeaMap)',
|
||||
'OpenMapSurfer.(Hybrid|AdminBounds|ContourLines|Hillshade|ElementsAtRisk)',
|
||||
'Stamen.Toner(Hybrid|Lines|Labels)',
|
||||
'Hydda.RoadsAndLabels',
|
||||
'^JusticeMap',
|
||||
'OpenPtMap',
|
||||
'OpenRailwayMap',
|
||||
'OpenFireMap',
|
||||
'SafeCast',
|
||||
'WaymarkedTrails.(hiking|cycling|mtb|slopes|riding|skating)'
|
||||
]
|
||||
|
||||
return providerName.match('(' + overlayPatterns.join('|') + ')') !== null
|
||||
}
|
||||
const tileProviders = TileLayer.Provider.providers
|
||||
let pageWidgetDefinition = OhMapPage.widget()
|
||||
let tileLayerProviderOptions = []
|
||||
let overlayTileLayerProviderOptions = []
|
||||
for (const providerKey in tileProviders) {
|
||||
let option, options
|
||||
if (tileProviders[providerKey].variants) {
|
||||
for (const providerVariantKey in tileProviders[providerKey].variants) {
|
||||
option = providerKey + '.' + providerVariantKey
|
||||
options = isOverlay(option) ? overlayTileLayerProviderOptions : tileLayerProviderOptions
|
||||
options.push({ value: option, label: option })
|
||||
}
|
||||
} else {
|
||||
option = providerKey
|
||||
options = isOverlay(option) ? overlayTileLayerProviderOptions : tileLayerProviderOptions
|
||||
options.push({ value: option, label: option })
|
||||
}
|
||||
}
|
||||
const tileProviderParam = pageWidgetDefinition.props.parameters.find((p) => p.name === 'tileLayerProvider')
|
||||
tileProviderParam.limitToOptions = true
|
||||
tileProviderParam.options = tileLayerProviderOptions
|
||||
const overlayTileProviderParam = pageWidgetDefinition.props.parameters.find((p) => p.name === 'overlayTileLayerProvider')
|
||||
overlayTileProviderParam.limitToOptions = true
|
||||
overlayTileProviderParam.options = overlayTileLayerProviderOptions
|
||||
|
||||
return {
|
||||
pageWidgetDefinition: pageWidgetDefinition,
|
||||
forceEditMode: true,
|
||||
page: {
|
||||
uid: 'page_' + this.$f7.utils.id(),
|
||||
|
@ -173,6 +232,7 @@ export default {
|
|||
},
|
||||
toYaml () {
|
||||
this.pageYaml = YAML.stringify({
|
||||
component: this.page.component,
|
||||
config: this.page.config,
|
||||
markers: this.page.slots.default
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue