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
Yannick Schaus 2020-12-07 14:44:58 +01:00 committed by GitHub
parent e7908dc9a3
commit 4508a88c2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 141 additions and 15 deletions

View File

@ -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",

View File

@ -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",

View File

@ -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(),

View File

@ -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'

View File

@ -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: '&copy; <a class="external" target="_blank" href="http://osm.org/copyright">OpenStreetMap</a>, &copy; <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
},

View File

@ -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
})