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",
|
"resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.7.1.tgz",
|
||||||
"integrity": "sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw=="
|
"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": {
|
"left-pad": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz",
|
||||||
|
|
|
@ -67,6 +67,7 @@
|
||||||
"framework7-vue": "^5.7.12",
|
"framework7-vue": "^5.7.12",
|
||||||
"later-again": "^0.1.1",
|
"later-again": "^0.1.1",
|
||||||
"leaflet": "^1.7.1",
|
"leaflet": "^1.7.1",
|
||||||
|
"leaflet-providers": "^1.11.0",
|
||||||
"moo": "^0.5.1",
|
"moo": "^0.5.1",
|
||||||
"nearley": "^2.19.6",
|
"nearley": "^2.19.6",
|
||||||
"pkce-challenge": "^2.1.0",
|
"pkce-challenge": "^2.1.0",
|
||||||
|
|
|
@ -1,12 +1,30 @@
|
||||||
// definitions for the map page & markers
|
// 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'
|
import { actionGroup, actionParams } from '../actions'
|
||||||
|
|
||||||
const LabelParam = () => pt('label', 'Label', 'The label on the marker')
|
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 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')
|
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')
|
export const OhMapMarkerDefinition = () => new WidgetDefinition('oh-map-marker', 'Map Marker', 'An icon on a map', 'map_pin')
|
||||||
.paramGroup(pg('marker', 'Marker', 'General marker settings'), [
|
.paramGroup(pg('marker', 'Marker', 'General marker settings'), [
|
||||||
LabelParam(),
|
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 OhMapMarker } from './oh-map-marker.vue'
|
||||||
export { default as OhMapCircleMarker } from './oh-map-circle-marker.vue'
|
export { default as OhMapCircleMarker } from './oh-map-circle-marker.vue'
|
||||||
|
|
|
@ -5,14 +5,12 @@
|
||||||
:zoom="zoom"
|
:zoom="zoom"
|
||||||
:center="center"
|
:center="center"
|
||||||
:options="mapOptions"
|
:options="mapOptions"
|
||||||
|
:zoom-animation="!config.noZoomAnimation"
|
||||||
|
:marker-zoom-animation="!config.noMarkerZoomAnimation"
|
||||||
class="oh-map-page-lmap"
|
class="oh-map-page-lmap"
|
||||||
:class="{ 'with-tabbar': context.tab }"
|
:class="{ 'with-tabbar': context.tab }"
|
||||||
@update:center="centerUpdate"
|
@update:center="centerUpdate"
|
||||||
@update:zoom="zoomUpdate">
|
@update:zoom="zoomUpdate">
|
||||||
<l-tile-layer
|
|
||||||
:url="url"
|
|
||||||
:attribution="attribution"
|
|
||||||
/>
|
|
||||||
<l-feature-group ref="featureGroup" v-if="context.component.slots">
|
<l-feature-group ref="featureGroup" v-if="context.component.slots">
|
||||||
<component v-for="(marker, idx) in context.component.slots.default" :key="idx"
|
<component v-for="(marker, idx) in context.component.slots.default" :key="idx"
|
||||||
:is="markerComponent(marker)" :context="childContext(marker)" @update="onMarkerUpdate" />
|
:is="markerComponent(marker)" :context="childContext(marker)" @update="onMarkerUpdate" />
|
||||||
|
@ -32,13 +30,17 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import mixin from '../widget-mixin'
|
import mixin from '../widget-mixin'
|
||||||
import { latLng, Icon } from 'leaflet'
|
import { tileLayer, latLng, Icon } from 'leaflet'
|
||||||
import { LMap, LTileLayer, LFeatureGroup } from 'vue2-leaflet'
|
import { LMap, LTileLayer, LFeatureGroup } from 'vue2-leaflet'
|
||||||
import 'leaflet/dist/leaflet.css'
|
import 'leaflet/dist/leaflet.css'
|
||||||
|
|
||||||
|
import { OhMapPageDefinition } from '@/assets/definitions/widgets/map'
|
||||||
|
|
||||||
import OhMapMarker from './oh-map-marker.vue'
|
import OhMapMarker from './oh-map-marker.vue'
|
||||||
import OhMapCircleMarker from './oh-map-circle-marker.vue'
|
import OhMapCircleMarker from './oh-map-circle-marker.vue'
|
||||||
|
|
||||||
|
import 'leaflet-providers'
|
||||||
|
|
||||||
delete Icon.Default.prototype._getIconUrl
|
delete Icon.Default.prototype._getIconUrl
|
||||||
Icon.Default.mergeOptions({
|
Icon.Default.mergeOptions({
|
||||||
iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
|
iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
|
||||||
|
@ -55,22 +57,61 @@ export default {
|
||||||
OhMapMarker,
|
OhMapMarker,
|
||||||
OhMapCircleMarker
|
OhMapCircleMarker
|
||||||
},
|
},
|
||||||
|
widget: OhMapPageDefinition,
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
zoom: 13,
|
zoom: this.context.component.config.initialZoom || 4,
|
||||||
currentZoom: 13,
|
currentZoom: 13,
|
||||||
currentCenter: null,
|
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://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||||
url: `https://a.basemaps.cartocdn.com/${this.$f7.data.themeOptions.dark}_all/{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>',
|
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,
|
showMap: true
|
||||||
mapOptions: {
|
}
|
||||||
zoomSnap: 0.5
|
},
|
||||||
}
|
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: {
|
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) {
|
zoomUpdate (zoom) {
|
||||||
this.currentZoom = zoom
|
this.currentZoom = zoom
|
||||||
},
|
},
|
||||||
|
|
|
@ -28,6 +28,14 @@
|
||||||
|
|
||||||
<f7-block class="block-narrow" style="padding-bottom: 8rem" v-if="ready && !previewMode">
|
<f7-block class="block-narrow" style="padding-bottom: 8rem" v-if="ready && !previewMode">
|
||||||
<f7-col>
|
<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-block-title>Markers</f7-block-title>
|
||||||
<f7-menu v-if="clipboardType === 'oh-map-marker'">
|
<f7-menu v-if="clipboardType === 'oh-map-marker'">
|
||||||
<f7-menu-item style="margin-left: auto" icon-f7="map" dropdown>
|
<f7-menu-item style="margin-left: auto" icon-f7="map" dropdown>
|
||||||
|
@ -70,7 +78,7 @@
|
||||||
</f7-tab>
|
</f7-tab>
|
||||||
|
|
||||||
<f7-tab id="code" @tab:show="() => { this.currentTab = 'code' }" :tab-active="currentTab === 'code'">
|
<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> -->
|
<!-- <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'" />
|
<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 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 OhMapMarker from '@/components/widgets/map/oh-map-marker.vue'
|
||||||
import OhMapCircleMarker from '@/components/widgets/map/oh-map-circle-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 PageSettings from '@/components/pagedesigner/page-settings.vue'
|
||||||
|
|
||||||
|
import ConfigSheet from '@/components/config/config-sheet.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [PageDesigner],
|
mixins: [PageDesigner],
|
||||||
components: {
|
components: {
|
||||||
'editor': () => import('@/components/config/controls/script-editor.vue'),
|
'editor': () => import('@/components/config/controls/script-editor.vue'),
|
||||||
'oh-map-page': () => import('@/components/widgets/map/oh-map-page.vue'),
|
OhMapPage,
|
||||||
PageSettings
|
PageSettings,
|
||||||
|
ConfigSheet
|
||||||
},
|
},
|
||||||
props: ['createMode', 'uid'],
|
props: ['createMode', 'uid'],
|
||||||
data () {
|
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 {
|
return {
|
||||||
|
pageWidgetDefinition: pageWidgetDefinition,
|
||||||
forceEditMode: true,
|
forceEditMode: true,
|
||||||
page: {
|
page: {
|
||||||
uid: 'page_' + this.$f7.utils.id(),
|
uid: 'page_' + this.$f7.utils.id(),
|
||||||
|
@ -173,6 +232,7 @@ export default {
|
||||||
},
|
},
|
||||||
toYaml () {
|
toYaml () {
|
||||||
this.pageYaml = YAML.stringify({
|
this.pageYaml = YAML.stringify({
|
||||||
|
component: this.page.component,
|
||||||
config: this.page.config,
|
config: this.page.config,
|
||||||
markers: this.page.slots.default
|
markers: this.page.slots.default
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue