409 lines
12 KiB
JavaScript
409 lines
12 KiB
JavaScript
/* Copyright (c) 2015-2018 Jean-Marc VIGLINO,
|
|
released under the CeCILL-B license (French BSD license)
|
|
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
|
|
*/
|
|
|
|
import {unByKey as ol_Observable_unByKey} from 'ol/Observable.js'
|
|
import ol_control_Control from 'ol/control/Control.js'
|
|
import {transform as ol_proj_transform} from 'ol/proj.js'
|
|
import ol_ext_element from '../util/element.js'
|
|
import { toLonLat as ol_geohash_toLonLat } from '../geom/geohash.js'
|
|
import { fromLonLat as ol_geohash_fromLonLat } from '../geom/geohash.js'
|
|
|
|
/**
|
|
* Set an hyperlink that will return the user to the current map view.
|
|
* Just add a `permalink`property to layers to be handled by the control (and added in the url).
|
|
* The layer's permalink property is used to name the layer in the url.
|
|
* The control must be added after all layer are inserted in the map to take them into acount.
|
|
*
|
|
* @constructor
|
|
* @extends {ol_control_Control}
|
|
* @param {Object=} options
|
|
* @param {boolean} [options.urlReplace=true] replace url or not, default true
|
|
* @param {boolean|string} [options.localStorage=false] save current map view in localStorage, if 'position' only store map position
|
|
* @param {boolean} [options.geohash=false] use geohash instead of lonlat, default false
|
|
* @param {integer} [options.fixed=6] number of digit in coords, default 6
|
|
* @param {boolean} [options.anchor] use "#" instead of "?" in href
|
|
* @param {boolean} [options.visible=true] hide the button on the map, default true
|
|
* @param {boolean} [options.hidden] hide the button on the map, default false DEPRECATED: use visible instead
|
|
* @param {function} [options.onclick] a function called when control is clicked
|
|
* @param {number} [options.refreshDelay=500]
|
|
*/
|
|
var ol_control_Permalink = class olcontrolPermalink extends ol_control_Control {
|
|
constructor(opt_options) {
|
|
var options = opt_options || {}
|
|
|
|
var element = document.createElement('div')
|
|
super({
|
|
element: element,
|
|
target: options.target
|
|
})
|
|
|
|
var self = this
|
|
var button = document.createElement('button')
|
|
ol_ext_element.create('I', { parent: button })
|
|
this.replaceState_ = (options.urlReplace !== false)
|
|
this.fixed_ = options.fixed || 6
|
|
this.hash_ = options.anchor ? "#" : "?"
|
|
this._localStorage = options.localStorage
|
|
if (!this._localStorage) {
|
|
try {
|
|
localStorage.removeItem('ol@permalink')
|
|
} catch (e) { console.warn('Failed to access localStorage...')}
|
|
}
|
|
|
|
function linkto() {
|
|
if (typeof (options.onclick) == 'function'){
|
|
options.onclick(self.getLink())
|
|
} else {
|
|
self.setUrlReplace(!self.replaceState_)
|
|
}
|
|
}
|
|
button.addEventListener('click', linkto, false)
|
|
button.addEventListener('touchstart', linkto, false)
|
|
|
|
element.className = (options.className || "ol-permalink") + " ol-unselectable ol-control"
|
|
element.appendChild(button)
|
|
if (options.hidden || options.visible === false) ol_ext_element.hide(element)
|
|
|
|
this.set('geohash', options.geohash)
|
|
this.set('initial', false)
|
|
|
|
this.on('change', this.viewChange_.bind(this))
|
|
|
|
// Save search params
|
|
this.search_ = {}
|
|
var init = {}
|
|
var hash = document.location.hash || document.location.search || ''
|
|
// console.log('hash', hash)
|
|
if (this.replaceState_ && !hash && this._localStorage) {
|
|
try {
|
|
hash = localStorage['ol@permalink']
|
|
} catch (e) { console.warn('Failed to access localStorage...')}
|
|
}
|
|
if (hash) {
|
|
hash = hash.replace(/(^#|^\?)/, "").split("&")
|
|
for (var i = 0; i < hash.length; i++) {
|
|
var t = hash[i].split("=")
|
|
switch (t[0]) {
|
|
case 'lon':
|
|
case 'lat':
|
|
case 'z':
|
|
case 'r': {
|
|
init[t[0]] = t[1]
|
|
break
|
|
}
|
|
case 'gh': {
|
|
const ghash = t[1].split('-')
|
|
const lonlat = ol_geohash_toLonLat(ghash[0])
|
|
init.lon = lonlat[0]
|
|
init.lat = lonlat[1]
|
|
init.z = ghash[1]
|
|
break
|
|
}
|
|
case 'l': break
|
|
default: this.search_[t[0]] = t[1]
|
|
}
|
|
}
|
|
}
|
|
if (init.hasOwnProperty('lon')) {
|
|
this.set('initial', init)
|
|
}
|
|
this.set('refreshDelay', options.refreshDelay || 500)
|
|
|
|
// Decode permalink
|
|
if (this.replaceState_) this.setPosition()
|
|
}
|
|
|
|
/**
|
|
* Get the initial position passed by the url
|
|
*/
|
|
getInitialPosition() {
|
|
return this.get('initial')
|
|
}
|
|
|
|
/**
|
|
* Set the map instance the control associated with.
|
|
* @param {ol.Map} map The map instance.
|
|
*/
|
|
setMap(map) {
|
|
if (this._listener) {
|
|
ol_Observable_unByKey(this._listener.change)
|
|
ol_Observable_unByKey(this._listener.moveend)
|
|
}
|
|
this._listener = null
|
|
|
|
super.setMap.call(this, map)
|
|
|
|
// Get change
|
|
if (map) {
|
|
this._listener = {
|
|
change: map.getLayerGroup().on('change', this.layerChange_.bind(this)),
|
|
moveend: map.on('moveend', this.viewChange_.bind(this))
|
|
}
|
|
this.setPosition()
|
|
}
|
|
}
|
|
/** Get layer given a permalink name (permalink propertie in the layer)
|
|
* @param {string} the permalink to search for
|
|
* @param {Array<ol.layer>|undefined} an array of layer to search in
|
|
* @return {ol.layer|false}
|
|
*/
|
|
getLayerByLink(id, layers) {
|
|
if (!layers && this.getMap())
|
|
layers = this.getMap().getLayers().getArray()
|
|
for (var i = 0; i < layers.length; i++) {
|
|
if (layers[i].get('permalink') == id)
|
|
return layers[i]
|
|
// Layer Group
|
|
if (layers[i].getLayers) {
|
|
var li = this.getLayerByLink(id, layers[i].getLayers().getArray())
|
|
if (li)
|
|
return li
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
/** Set coordinates as geohash
|
|
* @param {boolean}
|
|
*/
|
|
setGeohash(b) {
|
|
this.set('geohash', b)
|
|
this.setUrlParam()
|
|
}
|
|
/** Set map position according to the current link
|
|
* @param {boolean} [force=false] if true set the position even if urlReplace is disabled
|
|
*/
|
|
setPosition(force) {
|
|
var map = this.getMap()
|
|
if (!map)
|
|
return
|
|
|
|
var hash = (this.replaceState_ || force) ? document.location.hash || document.location.search : ''
|
|
if (!hash && this._localStorage) {
|
|
try {
|
|
hash = localStorage['ol@permalink']
|
|
} catch (e) { console.warn('Failed to access localStorage...')}
|
|
}
|
|
if (!hash)
|
|
return
|
|
|
|
var i, t, param = {}
|
|
hash = hash.replace(/(^#|^\?)/, "").split("&")
|
|
for (i = 0; i < hash.length; i++) {
|
|
t = hash[i].split("=")
|
|
param[t[0]] = t[1]
|
|
}
|
|
if (param.gh) {
|
|
var ghash = param.gh.split('-')
|
|
var lonlat = ol_geohash_toLonLat(ghash[0])
|
|
param.lon = lonlat[0]
|
|
param.lat = lonlat[1]
|
|
param.z = ghash[1]
|
|
}
|
|
var c = ol_proj_transform([Number(param.lon), Number(param.lat)], 'EPSG:4326', map.getView().getProjection())
|
|
if (c[0] && c[1])
|
|
map.getView().setCenter(c)
|
|
if (param.z)
|
|
map.getView().setZoom(Number(param.z))
|
|
if (param.r)
|
|
map.getView().setRotation(Number(param.r))
|
|
|
|
// Reset layers visibility
|
|
function resetLayers(layers) {
|
|
if (!layers)
|
|
layers = map.getLayers().getArray()
|
|
for (var i = 0; i < layers.length; i++) {
|
|
if (layers[i].get('permalink')) {
|
|
layers[i].setVisible(false)
|
|
// console.log("hide "+layers[i].get('permalink'));
|
|
}
|
|
if (layers[i].getLayers) {
|
|
resetLayers(layers[i].getLayers().getArray())
|
|
}
|
|
}
|
|
}
|
|
|
|
if (param.l) {
|
|
resetLayers()
|
|
|
|
var l = param.l.split("|")
|
|
for (i = 0; i < l.length; i++) {
|
|
t = l[i].split(":")
|
|
var li = this.getLayerByLink(t[0])
|
|
var op = Number(t[1])
|
|
if (li) {
|
|
li.setOpacity(op)
|
|
li.setVisible(true)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Get the parameters added to the url. The object can be changed to add new values.
|
|
* @return {Object} a key value object added to the url as &key=value
|
|
* @api stable
|
|
*/
|
|
getUrlParams() {
|
|
return this.search_
|
|
}
|
|
/**
|
|
* Set a parameter to the url.
|
|
* @param {string} key the key parameter
|
|
* @param {string|undefined} value the parameter's value, if undefined or empty string remove the parameter
|
|
* @api stable
|
|
*/
|
|
setUrlParam(key, value) {
|
|
if (key) {
|
|
if (value === undefined || value === '')
|
|
delete (this.search_[encodeURIComponent(key)])
|
|
else
|
|
this.search_[encodeURIComponent(key)] = encodeURIComponent(value)
|
|
}
|
|
this.viewChange_()
|
|
}
|
|
/**
|
|
* Get a parameter url.
|
|
* @param {string} key the key parameter
|
|
* @return {string} the parameter's value or empty string if not set
|
|
* @api stable
|
|
*/
|
|
getUrlParam(key) {
|
|
return decodeURIComponent(this.search_[encodeURIComponent(key)] || '')
|
|
}
|
|
/**
|
|
* Has a parameter url.
|
|
* @param {string} key the key parameter
|
|
* @return {boolean}
|
|
* @api stable
|
|
*/
|
|
hasUrlParam(key) {
|
|
return this.search_.hasOwnProperty(encodeURIComponent(key))
|
|
}
|
|
/** Get the permalink
|
|
* @param {boolean|string} [search=false] false: return full link | true: return the search string only | 'position': return position string
|
|
* @return {permalink}
|
|
*/
|
|
getLink(search) {
|
|
var map = this.getMap()
|
|
var c = ol_proj_transform(map.getView().getCenter(), map.getView().getProjection(), 'EPSG:4326')
|
|
var z = Math.round(map.getView().getZoom() * 10) / 10
|
|
var r = map.getView().getRotation()
|
|
var l = this.layerStr_
|
|
|
|
// Change anchor
|
|
var anchor = (r ? "&r=" + (Math.round(r * 10000) / 10000) : "") + (l ? "&l=" + l : "")
|
|
if (this.get('geohash')) {
|
|
var ghash = ol_geohash_fromLonLat(c, 8)
|
|
anchor = "gh=" + ghash + '-' + z + anchor
|
|
} else {
|
|
anchor = "lon=" + c[0].toFixed(this.fixed_) + "&lat=" + c[1].toFixed(this.fixed_) + "&z=" + z + anchor
|
|
}
|
|
|
|
if (search === 'position')
|
|
return anchor
|
|
|
|
// Add other params
|
|
for (var i in this.search_) {
|
|
anchor += "&" + i + (typeof (this.search_[i]) !== 'undefined' ? "=" + this.search_[i] : '')
|
|
}
|
|
if (search)
|
|
return anchor
|
|
|
|
//return document.location.origin+document.location.pathname+this.hash_+anchor;
|
|
return document.location.protocol + "//" + document.location.host + document.location.pathname + this.hash_ + anchor
|
|
}
|
|
/** Check if urlreplace is on
|
|
* @return {boolean}
|
|
*/
|
|
getUrlReplace() {
|
|
return this.replaceState_
|
|
}
|
|
/** Enable / disable url replacement (replaceSate)
|
|
* @param {bool}
|
|
*/
|
|
setUrlReplace(replace) {
|
|
try {
|
|
this.replaceState_ = replace
|
|
if (!replace) {
|
|
var s = ""
|
|
for (var i in this.search_) {
|
|
s += (s == "" ? "?" : "&") + i + (typeof (this.search_[i]) !== 'undefined' ? "=" + this.search_[i] : '')
|
|
}
|
|
this.replaceUrl_(document.location.origin + document.location.pathname + s, true)
|
|
} else {
|
|
this.replaceUrl_(this.getLink(), true)
|
|
}
|
|
} catch (e) { /* ok */ }
|
|
/*
|
|
if (this._localStorage) {
|
|
localStorage['ol@permalink'] = this.getLink(true);
|
|
}
|
|
*/
|
|
}
|
|
/** Refresh the url
|
|
* @private
|
|
*/
|
|
replaceUrl_(url, force) {
|
|
clearTimeout(this.refreshTout_)
|
|
if (force) {
|
|
window.history.replaceState(null, null, url)
|
|
} else {
|
|
this.refreshTout_ = setTimeout(function() {
|
|
window.history.replaceState(null, null, url)
|
|
}, this.get('refreshDelay'))
|
|
}
|
|
}
|
|
/**
|
|
* On view change refresh link
|
|
* @param {ol.event} The map instance.
|
|
* @private
|
|
*/
|
|
viewChange_() {
|
|
try {
|
|
if (this.replaceState_) {
|
|
this.replaceUrl_(this.getLink())
|
|
}
|
|
} catch (e) { /* ok */ }
|
|
if (this._localStorage) {
|
|
try {
|
|
localStorage['ol@permalink'] = this.getLink(this._localStorage)
|
|
} catch (e) { console.warn('Failed to access localStorage...')}
|
|
}
|
|
}
|
|
/**
|
|
* Layer change refresh link
|
|
* @private
|
|
*/
|
|
layerChange_() {
|
|
// Prevent multiple change at the same time
|
|
if (this._tout) {
|
|
clearTimeout(this._tout)
|
|
this._tout = null
|
|
}
|
|
this._tout = setTimeout(function () {
|
|
this._tout = null
|
|
// Get layers
|
|
var l = ""
|
|
function getLayers(layers) {
|
|
for (var i = 0; i < layers.length; i++) {
|
|
if (layers[i].getVisible() && layers[i].get("permalink")) {
|
|
if (l)
|
|
l += "|"
|
|
l += layers[i].get("permalink") + ":" + layers[i].get("opacity")
|
|
}
|
|
// Layer Group
|
|
if (layers[i].getLayers)
|
|
getLayers(layers[i].getLayers().getArray())
|
|
}
|
|
}
|
|
getLayers(this.getMap().getLayers().getArray())
|
|
this.layerStr_ = l
|
|
|
|
this.viewChange_()
|
|
}.bind(this), 200)
|
|
}
|
|
}
|
|
|
|
export default ol_control_Permalink
|