mirror of
https://github.com/umap-project/umap.git
synced 2025-04-30 04:02:38 +02:00
Merge pull request #2057 from umap-project/icon-to-modules
chore: move icon.js to modules
This commit is contained in:
commit
5a33709cc9
8 changed files with 86 additions and 63 deletions
|
@ -1,5 +1,6 @@
|
|||
import { DomEvent, DomUtil, stamp } from '../../vendors/leaflet/leaflet-src.esm.js'
|
||||
import { translate } from './i18n.js'
|
||||
import * as Icon from './rendering/icon.js'
|
||||
|
||||
export default class Browser {
|
||||
constructor(map) {
|
||||
|
@ -34,14 +35,14 @@ export default class Browser {
|
|||
const colorBox = DomUtil.create('i', 'icon icon-16 feature-color', row)
|
||||
const title = DomUtil.create('span', 'feature-title', row)
|
||||
const symbol = feature._getIconUrl
|
||||
? U.Icon.prototype.formatUrl(feature._getIconUrl(), feature)
|
||||
? Icon.formatUrl(feature._getIconUrl(), feature)
|
||||
: null
|
||||
title.textContent = feature.getDisplayName() || '—'
|
||||
const bgcolor = feature.getPreviewColor()
|
||||
colorBox.style.backgroundColor = bgcolor
|
||||
if (symbol && symbol !== U.SCHEMA.iconUrl.default) {
|
||||
const icon = U.Icon.makeIconElement(symbol, colorBox)
|
||||
U.Icon.setIconContrast(icon, colorBox, symbol, bgcolor)
|
||||
const icon = Icon.makeElement(symbol, colorBox)
|
||||
Icon.setContrast(icon, colorBox, symbol, bgcolor)
|
||||
}
|
||||
const viewFeature = (e) => {
|
||||
feature.zoomTo({ ...e, callback: feature.view })
|
||||
|
|
|
@ -25,6 +25,7 @@ import { EditPanel, FullPanel, Panel } from './ui/panel.js'
|
|||
import Tooltip from './ui/tooltip.js'
|
||||
import URLs from './urls.js'
|
||||
import * as Utils from './utils.js'
|
||||
import * as Icon from './rendering/icon.js'
|
||||
import { DataLayer, LAYER_TYPES } from './data/layer.js'
|
||||
import { DataLayerPermissions, MapPermissions } from './permissions.js'
|
||||
import { Point, LineString, Polygon } from './data/features.js'
|
||||
|
@ -51,6 +52,7 @@ window.U = {
|
|||
FullPanel,
|
||||
Help,
|
||||
HTTPError,
|
||||
Icon,
|
||||
Importer,
|
||||
LAYER_TYPES,
|
||||
LeafletMarker,
|
||||
|
|
|
@ -1,15 +1,36 @@
|
|||
U.Icon = L.DivIcon.extend({
|
||||
statics: {
|
||||
RECENT: [],
|
||||
},
|
||||
import {
|
||||
DomEvent,
|
||||
DomUtil,
|
||||
DivIcon,
|
||||
Icon,
|
||||
} from '../../../vendors/leaflet/leaflet-src.esm.js'
|
||||
import * as Utils from '../utils.js'
|
||||
import { SCHEMA } from '../schema.js'
|
||||
|
||||
export function getClass(name) {
|
||||
switch (name) {
|
||||
case 'Circle':
|
||||
return Circle
|
||||
case 'Ball':
|
||||
return Ball
|
||||
case 'Drop':
|
||||
return Drop
|
||||
default:
|
||||
return DefaultIcon
|
||||
}
|
||||
}
|
||||
|
||||
export const RECENT = []
|
||||
|
||||
const BaseIcon = L.DivIcon.extend({
|
||||
initialize: function (options) {
|
||||
const default_options = {
|
||||
iconSize: null, // Made in css
|
||||
iconUrl: U.SCHEMA.iconUrl.default,
|
||||
iconUrl: SCHEMA.iconUrl.default,
|
||||
feature: null,
|
||||
}
|
||||
options = L.Util.extend({}, default_options, options)
|
||||
L.Icon.prototype.initialize.call(this, options)
|
||||
Icon.prototype.initialize.call(this, options)
|
||||
this.feature = this.options.feature
|
||||
if (this.feature?.isReadOnly()) {
|
||||
this.options.className += ' readonly'
|
||||
|
@ -17,10 +38,10 @@ U.Icon = L.DivIcon.extend({
|
|||
},
|
||||
|
||||
_setRecent: (url) => {
|
||||
if (U.Utils.hasVar(url)) return
|
||||
if (url === U.SCHEMA.iconUrl.default) return
|
||||
if (U.Icon.RECENT.indexOf(url) === -1) {
|
||||
U.Icon.RECENT.push(url)
|
||||
if (Utils.hasVar(url)) return
|
||||
if (url === SCHEMA.iconUrl.default) return
|
||||
if (RECENT.indexOf(url) === -1) {
|
||||
RECENT.push(url)
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -32,29 +53,26 @@ U.Icon = L.DivIcon.extend({
|
|||
} else {
|
||||
url = this.options[`${name}Url`]
|
||||
}
|
||||
return this.formatUrl(url, this.feature)
|
||||
return formatUrl(url, this.feature)
|
||||
},
|
||||
|
||||
_getColor: function () {
|
||||
let color
|
||||
if (this.feature) color = this.feature.getDynamicOption('color')
|
||||
else if (this.options.color) color = this.options.color
|
||||
else color = U.SCHEMA.color.default
|
||||
else color = SCHEMA.color.default
|
||||
return color
|
||||
},
|
||||
|
||||
_getOpacity: function () {
|
||||
if (this.feature) return this.feature.getOption('iconOpacity')
|
||||
return U.SCHEMA.iconOpacity.default
|
||||
return SCHEMA.iconOpacity.default
|
||||
},
|
||||
|
||||
formatUrl: (url, feature) =>
|
||||
U.Utils.greedyTemplate(url || '', feature ? feature.extendedProperties() : {}),
|
||||
|
||||
onAdd: () => {},
|
||||
})
|
||||
|
||||
U.Icon.Default = U.Icon.extend({
|
||||
const DefaultIcon = BaseIcon.extend({
|
||||
default_options: {
|
||||
iconAnchor: new L.Point(16, 40),
|
||||
popupAnchor: new L.Point(0, -40),
|
||||
|
@ -64,11 +82,11 @@ U.Icon.Default = U.Icon.extend({
|
|||
|
||||
initialize: function (options) {
|
||||
options = L.Util.extend({}, this.default_options, options)
|
||||
U.Icon.prototype.initialize.call(this, options)
|
||||
BaseIcon.prototype.initialize.call(this, options)
|
||||
},
|
||||
|
||||
_setIconStyles: function (img, name) {
|
||||
U.Icon.prototype._setIconStyles.call(this, img, name)
|
||||
BaseIcon.prototype._setIconStyles.call(this, img, name)
|
||||
const color = this._getColor()
|
||||
const opacity = this._getOpacity()
|
||||
this.elements.container.style.backgroundColor = color
|
||||
|
@ -80,29 +98,29 @@ U.Icon.Default = U.Icon.extend({
|
|||
onAdd: function () {
|
||||
const src = this._getIconUrl('icon')
|
||||
const bgcolor = this._getColor()
|
||||
U.Icon.setIconContrast(this.elements.icon, this.elements.container, src, bgcolor)
|
||||
setContrast(this.elements.icon, this.elements.container, src, bgcolor)
|
||||
},
|
||||
|
||||
createIcon: function () {
|
||||
this.elements = {}
|
||||
this.elements.main = L.DomUtil.create('div')
|
||||
this.elements.container = L.DomUtil.create(
|
||||
this.elements.main = DomUtil.create('div')
|
||||
this.elements.container = DomUtil.create(
|
||||
'div',
|
||||
'icon_container',
|
||||
this.elements.main
|
||||
)
|
||||
this.elements.main.dataset.feature = this.feature?.id
|
||||
this.elements.arrow = L.DomUtil.create('div', 'icon_arrow', this.elements.main)
|
||||
this.elements.arrow = DomUtil.create('div', 'icon_arrow', this.elements.main)
|
||||
const src = this._getIconUrl('icon')
|
||||
if (src) {
|
||||
this.elements.icon = U.Icon.makeIconElement(src, this.elements.container)
|
||||
this.elements.icon = makeElement(src, this.elements.container)
|
||||
}
|
||||
this._setIconStyles(this.elements.main, 'icon')
|
||||
return this.elements.main
|
||||
},
|
||||
})
|
||||
|
||||
U.Icon.Circle = U.Icon.extend({
|
||||
const Circle = BaseIcon.extend({
|
||||
initialize: function (options) {
|
||||
const default_options = {
|
||||
popupAnchor: new L.Point(0, -6),
|
||||
|
@ -110,18 +128,18 @@ U.Icon.Circle = U.Icon.extend({
|
|||
className: 'umap-circle-icon',
|
||||
}
|
||||
options = L.Util.extend({}, default_options, options)
|
||||
U.Icon.prototype.initialize.call(this, options)
|
||||
BaseIcon.prototype.initialize.call(this, options)
|
||||
},
|
||||
|
||||
_setIconStyles: function (img, name) {
|
||||
U.Icon.prototype._setIconStyles.call(this, img, name)
|
||||
BaseIcon.prototype._setIconStyles.call(this, img, name)
|
||||
this.elements.main.style.backgroundColor = this._getColor()
|
||||
this.elements.main.style.opacity = this._getOpacity()
|
||||
},
|
||||
|
||||
createIcon: function () {
|
||||
this.elements = {}
|
||||
this.elements.main = L.DomUtil.create('div')
|
||||
this.elements.main = DomUtil.create('div')
|
||||
this.elements.main.innerHTML = ' '
|
||||
this._setIconStyles(this.elements.main, 'icon')
|
||||
this.elements.main.dataset.feature = this.feature?.id
|
||||
|
@ -129,7 +147,7 @@ U.Icon.Circle = U.Icon.extend({
|
|||
},
|
||||
})
|
||||
|
||||
U.Icon.Drop = U.Icon.Default.extend({
|
||||
const Drop = DefaultIcon.extend({
|
||||
default_options: {
|
||||
iconAnchor: new L.Point(16, 42),
|
||||
popupAnchor: new L.Point(0, -42),
|
||||
|
@ -138,7 +156,7 @@ U.Icon.Drop = U.Icon.Default.extend({
|
|||
},
|
||||
})
|
||||
|
||||
U.Icon.Ball = U.Icon.Default.extend({
|
||||
const Ball = DefaultIcon.extend({
|
||||
default_options: {
|
||||
iconAnchor: new L.Point(8, 30),
|
||||
popupAnchor: new L.Point(0, -28),
|
||||
|
@ -148,20 +166,20 @@ U.Icon.Ball = U.Icon.Default.extend({
|
|||
|
||||
createIcon: function () {
|
||||
this.elements = {}
|
||||
this.elements.main = L.DomUtil.create('div')
|
||||
this.elements.container = L.DomUtil.create(
|
||||
this.elements.main = DomUtil.create('div')
|
||||
this.elements.container = DomUtil.create(
|
||||
'div',
|
||||
'icon_container',
|
||||
this.elements.main
|
||||
)
|
||||
this.elements.main.dataset.feature = this.feature?.id
|
||||
this.elements.arrow = L.DomUtil.create('div', 'icon_arrow', this.elements.main)
|
||||
this.elements.arrow = DomUtil.create('div', 'icon_arrow', this.elements.main)
|
||||
this._setIconStyles(this.elements.main, 'icon')
|
||||
return this.elements.main
|
||||
},
|
||||
|
||||
_setIconStyles: function (img, name) {
|
||||
U.Icon.prototype._setIconStyles.call(this, img, name)
|
||||
BaseIcon.prototype._setIconStyles.call(this, img, name)
|
||||
const color = this._getColor('color')
|
||||
let background
|
||||
if (L.Browser.ielt9) {
|
||||
|
@ -176,7 +194,7 @@ U.Icon.Ball = U.Icon.Default.extend({
|
|||
},
|
||||
})
|
||||
|
||||
U.Icon.Cluster = L.DivIcon.extend({
|
||||
export const Cluster = DivIcon.extend({
|
||||
options: {
|
||||
iconSize: [40, 40],
|
||||
},
|
||||
|
@ -187,9 +205,9 @@ U.Icon.Cluster = L.DivIcon.extend({
|
|||
},
|
||||
|
||||
createIcon: function () {
|
||||
const container = L.DomUtil.create('div', 'leaflet-marker-icon marker-cluster')
|
||||
const div = L.DomUtil.create('div', '', container)
|
||||
const span = L.DomUtil.create('span', '', div)
|
||||
const container = DomUtil.create('div', 'leaflet-marker-icon marker-cluster')
|
||||
const div = DomUtil.create('div', '', container)
|
||||
const span = DomUtil.create('span', '', div)
|
||||
const backgroundColor = this.datalayer.getColor()
|
||||
span.textContent = this.cluster.getChildCount()
|
||||
div.style.backgroundColor = backgroundColor
|
||||
|
@ -202,27 +220,28 @@ U.Icon.Cluster = L.DivIcon.extend({
|
|||
if (this.datalayer.options.cluster?.textColor) {
|
||||
color = this.datalayer.options.cluster.textColor
|
||||
}
|
||||
return color || L.DomUtil.TextColorFromBackgroundColor(el, backgroundColor)
|
||||
return color || DomUtil.TextColorFromBackgroundColor(el, backgroundColor)
|
||||
},
|
||||
})
|
||||
|
||||
U.Icon.isImg = (src) =>
|
||||
U.Utils.isPath(src) || U.Utils.isRemoteUrl(src) || U.Utils.isDataImage(src)
|
||||
export function isImg(src) {
|
||||
return Utils.isPath(src) || Utils.isRemoteUrl(src) || Utils.isDataImage(src)
|
||||
}
|
||||
|
||||
U.Icon.makeIconElement = (src, parent) => {
|
||||
export function makeElement(src, parent) {
|
||||
let icon
|
||||
if (U.Icon.isImg(src)) {
|
||||
icon = L.DomUtil.create('img')
|
||||
if (isImg(src)) {
|
||||
icon = DomUtil.create('img')
|
||||
icon.src = src
|
||||
} else {
|
||||
icon = L.DomUtil.create('span')
|
||||
icon = DomUtil.create('span')
|
||||
icon.textContent = src
|
||||
}
|
||||
parent.appendChild(icon)
|
||||
return icon
|
||||
}
|
||||
|
||||
U.Icon.setIconContrast = (icon, parent, src, bgcolor) => {
|
||||
export function setContrast(icon, parent, src, bgcolor) {
|
||||
/*
|
||||
* icon: the element we'll adapt the style, it can be an image or text
|
||||
* parent: the element we'll consider to decide whether to adapt the style,
|
||||
|
@ -233,14 +252,10 @@ U.Icon.setIconContrast = (icon, parent, src, bgcolor) => {
|
|||
*/
|
||||
if (!icon) return
|
||||
|
||||
if (L.DomUtil.contrastedColor(parent, bgcolor)) {
|
||||
if (DomUtil.contrastedColor(parent, bgcolor)) {
|
||||
// Decide whether to switch svg to white or not, but do it
|
||||
// only for internal SVG, as invert could do weird things
|
||||
if (
|
||||
U.Utils.isPath(src) &&
|
||||
src.endsWith('.svg') &&
|
||||
src !== U.SCHEMA.iconUrl.default
|
||||
) {
|
||||
if (Utils.isPath(src) && src.endsWith('.svg') && src !== SCHEMA.iconUrl.default) {
|
||||
// Must be called after icon container is added to the DOM
|
||||
// An image
|
||||
icon.style.filter = 'invert(1)'
|
||||
|
@ -250,3 +265,7 @@ U.Icon.setIconContrast = (icon, parent, src, bgcolor) => {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function formatUrl(url, feature) {
|
||||
return Utils.greedyTemplate(url || '', feature ? feature.extendedProperties() : {})
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
// WARNING must be loaded dynamically, or at least after leaflet.markercluster
|
||||
// Uses global L.MarkerCluster and L.MarkerClusterGroup, not exposed as ESM
|
||||
// Uses global U.Icon not yet a module
|
||||
import { translate } from '../../i18n.js'
|
||||
import { LayerMixin } from './base.js'
|
||||
import * as Utils from '../../utils.js'
|
||||
import { Evented } from '../../../../vendors/leaflet/leaflet-src.esm.js'
|
||||
import { Cluster as ClusterIcon } from '../icon.js'
|
||||
|
||||
const MarkerCluster = L.MarkerCluster.extend({
|
||||
// Custom class so we can call computeTextColor
|
||||
|
@ -34,7 +34,7 @@ export const Cluster = L.MarkerClusterGroup.extend({
|
|||
polygonOptions: {
|
||||
color: this.datalayer.getColor(),
|
||||
},
|
||||
iconCreateFunction: (cluster) => new U.Icon.Cluster(datalayer, cluster),
|
||||
iconCreateFunction: (cluster) => new ClusterIcon(datalayer, cluster),
|
||||
}
|
||||
if (this.datalayer.options.cluster?.radius) {
|
||||
options.maxClusterRadius = this.datalayer.options.cluster.radius
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { DomUtil, DomEvent } from '../../../vendors/leaflet/leaflet-src.esm.js'
|
||||
import { translate, getLocale } from '../i18n.js'
|
||||
import * as Utils from '../utils.js'
|
||||
import * as Icon from './icon.js'
|
||||
|
||||
export default function loadTemplate(name, feature, container) {
|
||||
let klass = PopupTemplate
|
||||
|
@ -160,9 +161,9 @@ class OSM extends TitleMixin(PopupTemplate) {
|
|||
const color = feature.getPreviewColor()
|
||||
title.style.backgroundColor = color
|
||||
const iconUrl = feature.getDynamicOption('iconUrl')
|
||||
const icon = U.Icon.makeIconElement(iconUrl, title)
|
||||
const icon = Icon.makeElement(iconUrl, title)
|
||||
DomUtil.addClass(icon, 'icon')
|
||||
U.Icon.setIconContrast(icon, title, iconUrl, color)
|
||||
Icon.setContrast(icon, title, iconUrl, color)
|
||||
if (DomUtil.contrastedColor(title, color)) title.style.color = 'white'
|
||||
DomUtil.add('span', '', title, this.getName(feature))
|
||||
const street = props['addr:street']
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
import { translate } from '../i18n.js'
|
||||
import { uMapAlert as Alert } from '../../components/alerts/alert.js'
|
||||
import * as Utils from '../utils.js'
|
||||
import * as Icon from './icon.js'
|
||||
|
||||
const FeatureMixin = {
|
||||
initialize: function (feature, latlngs) {
|
||||
|
@ -219,7 +220,7 @@ export const LeafletMarker = Marker.extend({
|
|||
},
|
||||
|
||||
getIcon: function () {
|
||||
const Class = U.Icon[this.getIconClass()] || U.Icon.Default
|
||||
const Class = Icon.getClass(this.getIconClass())
|
||||
return new Class({ feature: this.feature })
|
||||
},
|
||||
|
||||
|
|
|
@ -550,7 +550,7 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
|||
// Do not try to render URL with variables
|
||||
const box = L.DomUtil.create('div', 'umap-pictogram-choice', this.buttons)
|
||||
L.DomEvent.on(box, 'click', this.onDefine, this)
|
||||
const icon = U.Icon.makeIconElement(this.value(), box)
|
||||
const icon = U.Icon.makeElement(this.value(), box)
|
||||
}
|
||||
this.button = L.DomUtil.createButton(
|
||||
'button action-button',
|
||||
|
@ -571,7 +571,7 @@ L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
|
|||
if (search && U.Utils.normalize(title).indexOf(search) === -1) return
|
||||
const className = value === this.value() ? `${baseClass} selected` : baseClass
|
||||
const container = L.DomUtil.create('div', className, parent)
|
||||
U.Icon.makeIconElement(value, container)
|
||||
U.Icon.makeElement(value, container)
|
||||
container.title = title
|
||||
L.DomEvent.on(
|
||||
container,
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
defer></script>
|
||||
<script src="{% static 'umap/js/umap.core.js' %}" defer></script>
|
||||
<script src="{% static 'umap/js/umap.forms.js' %}" defer></script>
|
||||
<script src="{% static 'umap/js/umap.icon.js' %}" defer></script>
|
||||
<script src="{% static 'umap/js/umap.controls.js' %}" defer></script>
|
||||
<script src="{% static 'umap/js/umap.js' %}" defer></script>
|
||||
<script src="{% static 'umap/js/components/fragment.js' %}" defer></script>
|
||||
|
|
Loading…
Reference in a new issue