Skip to content

Commit

Permalink
Merge pull request #369 from MTES-MCT/leaflet-icon-fix
Browse files Browse the repository at this point in the history
Ajoute un correctif pour le problème récurrent d'icones leaflet
  • Loading branch information
thibault authored Jul 25, 2024
2 parents a97320a + e2676ee commit 1a9cf39
Show file tree
Hide file tree
Showing 16 changed files with 203 additions and 24 deletions.
Binary file added envergo/static/images/marker-icon-2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added envergo/static/images/marker-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added envergo/static/images/marker-shadow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 0 additions & 3 deletions envergo/static/js/libs/2150_map.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,6 @@
* Create the main marker object that is manipulated by the widget.
*/
Map.prototype.initializeMarker = function (map) {
// Bypass an issue with leaflet detecting a bad icon url, caused by
// assets versioning
L.Icon.Default.prototype.options.imagePath = '/static/leaflet/images/';

const options = {
draggable: true,
Expand Down
160 changes: 160 additions & 0 deletions envergo/static/js/libs/leaflet-icon-fix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// https://github.com/ghybs/leaflet-defaulticon-compatibility
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('leaflet')) :
typeof define === 'function' && define.amd ? define(['leaflet'], factory) :
(factory(global.L));
}(this, (function (L) { 'use strict';

L.Icon.Default.mergeOptions({
// Erase default options, so that they can be overridden by _initializeOptions if not supplied.
iconUrl: null,
iconRetinaUrl: null,
shadowUrl: null,
iconSize: null,
iconAnchor: null,
popupAnchor: null,
tooltipAnchor: null,
shadowSize: null,

// @option classNamePrefix: String = 'leaflet-default-icon-'
// Prefix for the classes defined in CSS that contain the Icon options.
// See the leaflet-defaulticon-compatibility.css file as a starter.
// Expected suffixes are "icon", "shadow", "popup" and "tooltip".
classNamePrefix: 'leaflet-default-icon-',
});


L.Icon.Default.include({

_needsInit: true,

// Override to make sure options are retrieved from CSS.
_getIconUrl: function (name) {
// @option imagePath: String
// `Icon.Default` will try to auto-detect the location of
// the blue icon images. If you are placing these images in a
// non-standard way, set this option to point to the right
// path, before any marker is added to a map.
// Caution: do not use this option with inline base64 image(s).
var imagePath = this.options.imagePath || L.Icon.Default.imagePath || '';
// Deprecated (IconDefault.imagePath), backwards-compatibility only

if (this._needsInit) {
// Modifying imagePath option after _getIconUrl has been called
// once in this instance of IconDefault will no longer have any
// effect.
this._initializeOptions(imagePath);
}

return imagePath + L.Icon.prototype._getIconUrl.call(this, name);
},

// Initialize all necessary options for this instance.
_initializeOptions: function (imagePath) {
this._setOptions('icon', _detectIconOptions, imagePath);
this._setOptions('shadow', _detectIconOptions, imagePath);
this._setOptions('popup', _detectDivOverlayOptions);
this._setOptions('tooltip', _detectDivOverlayOptions);
this._needsInit = false;
},

// Retrieve values from CSS and assign to this instance options.
_setOptions: function (name, detectorFn, imagePath) {
var options = this.options,
prefix = options.classNamePrefix,
optionValues = detectorFn(prefix + name, imagePath);

for (var optionName in optionValues) {
options[name + optionName] = options[name + optionName] || optionValues[optionName];
}
}

});


// Retrieve icon option values from CSS (icon or shadow).
function _detectIconOptions(className, imagePath) {
var el = L.DomUtil.create('div', className, document.body),
urlsContainer = _getBkgImageOrCursor(el),
urls = _extractUrls(urlsContainer, imagePath),
iconX = _getStyleInt(el, 'width'),
iconY = _getStyleInt(el, 'height'),
anchorNX = _getStyleInt(el, 'margin-left'),
anchorNY = _getStyleInt(el, 'margin-top');

el.parentNode.removeChild(el);

return {
Url: urls[0],
RetinaUrl: urls[1],
Size: [iconX, iconY],
Anchor: [-anchorNX, -anchorNY]
};
}

// Retrieve anchor option values from CSS (popup or tooltip).
function _detectDivOverlayOptions(className) {
var el = L.DomUtil.create('div', className, document.body),
anchorX = _getStyleInt(el, 'margin-left'),
anchorY = _getStyleInt(el, 'margin-top');

el.parentNode.removeChild(el);

return {
Anchor: [anchorX, anchorY]
};
}

// Read the CSS url (could be path or inline base64), may be multiple.
// First: normal icon
// Second: Retina icon
function _extractUrls(urlsContainer, imagePath) {
var re = /url\(['"]?([^"']*?)['"]?\)/gi, // Match anything between url( and ), possibly with single or double quotes.
urls = [],
m = re.exec(urlsContainer);

while (m) {
// Keep the entire URL from CSS rule, so that each image can have its own full URL.
// Except in the case imagePath is provided: remove the path part (i.e. keep only the file name).
urls.push(imagePath ? _stripPath(m[1]) : m[1]);
m = re.exec(urlsContainer);
}

return urls;
}

// Remove anything before the last slash (/) occurrence (inclusive).
// Caution: will give unexpected result if url is inline base64 data
// => do not specify imagePath in that case!
function _stripPath(url) {
return url.substr(url.lastIndexOf('/') + 1);
}

function _getStyleInt(el, style) {
return parseInt(_getStyle(el, style), 10);
}

// Factorize style reading fallback for IE8.
function _getStyle(el, style) {
return L.DomUtil.getStyle(el, style) || L.DomUtil.getStyle(el, _kebabToCamelCase(style));
}

// When Firefox high contrast (colours override) option is enabled,
// "background-image" is overridden by the browser as "none".
// In that case, fallback to "cursor". But keep "background-image"
// as primary source because IE expects cursor URL as relative to HTML page
// instead of relative to CSS file.
function _getBkgImageOrCursor(el) {
var bkgImage = _getStyle(el, 'background-image');

return bkgImage && bkgImage !== 'none' ? bkgImage : _getStyle(el, 'cursor');
}

// Convert kebab-case CSS property name to camelCase for IE currentStyle.
function _kebabToCamelCase(prop) {
return prop.replace(/-(\w)/g, function (str, w) {
return w.toUpperCase();
});
}

})));
3 changes: 0 additions & 3 deletions envergo/static/js/libs/moulinette_map.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,6 @@
* Create the main marker object that is manipulated by the widget.
*/
MoulinetteMap.prototype.initializeMarker = function (map) {
// Bypass an issue with leaflet detecting a bad icon url, caused by
// assets versioning
L.Icon.Default.prototype.options.imagePath = '/static/leaflet/images/';

const options = {
draggable: !this.options.isStatic,
Expand Down
8 changes: 2 additions & 6 deletions envergo/static/js/libs/moulinette_result_maps.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@
layers: [planLayer],
};
if (typeof mapData["fixed"] === 'object') {
settings = {...settings, ...mapData["fixed"]}
settings = { ...settings, ...mapData["fixed"] }
}
else{
else {
settings["zoomControl"] = !mapData["fixed"];
settings["dragging"] = !mapData["fixed"];
settings["doubleClickZoom"] = !mapData["fixed"];
Expand Down Expand Up @@ -111,10 +111,6 @@
};
legend.addTo(map);

// Bypass an issue with leaflet detecting a bad icon url, caused by
// assets versioning
L.Icon.Default.prototype.options.imagePath = '/static/leaflet/images/';

// Upon page printing, the map container width is reduced, so we need to
// make sure the map displays correctly with the new size.
window.matchMedia('print').addEventListener("change", function (query) {
Expand Down
34 changes: 34 additions & 0 deletions envergo/static/sass/project.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1713,3 +1713,37 @@ main.demonstrateur_2150 {
.fr-hint-text a.fr-link:has(+span.fr-tooltip) {
font-size: inherit;
}

// Fix issues with the leaflet icon detection
// This is code copied from the https://github.com/ghybs/leaflet-defaulticon-compatibility plugin
.leaflet-default-icon-icon {
background-image: url(/static/images/marker-icon.png), url(/static/images/marker-icon-2x.png);
/* normal[, Retina] */
cursor: url(/static/images/marker-icon.png), url(/static/images/marker-icon-2x.png), auto;
/* normal[, Retina], auto for compliance with cursor syntax */
width: 25px;
height: 41px;
margin: -41px -12px;
/* margin top and left to reversely position iconAnchor */
}

.leaflet-default-icon-shadow {
background-image: url(/static/images/marker-shadow.png);
/* normal[, Retina] */
cursor: url(/static/images/marker-shadow.png), auto;
/* normal[, Retina], auto */
width: 41px;
height: 41px;
margin: -41px -12px;
/* margin top and left to reversely position shadowAnchor */
}

.leaflet-default-icon-popup {
margin: -34px 1px;
/* margin top and left to position popupAnchor */
}

.leaflet-default-icon-tooltip {
margin: -28px 16px;
/* margin top and left to position tooltipAnchor, even if direction 'bottom' or 'right' */
}
1 change: 1 addition & 0 deletions envergo/templates/evaluations/detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ <h2>Partager cet avis réglementaire ?</h2>
</script>
<script defer src="{% static 'leaflet/leaflet.js' %}"></script>
<script defer src="{% static 'leaflet/draw/leaflet.draw.js' %}"></script>
<script defer src="{% static 'js/libs/leaflet-icon-fix.js' %}"></script>
<script defer src="{% static 'js/libs/moulinette_map.js' %}"></script>
<script defer src="{% static 'js/libs/map_widget_events.js' %}"></script>
<script defer src="{% static 'js/libs/moulinette_result_maps.js' %}"></script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

{% load utils %}

{% load evaluations leaflet_tags static %}
{% load evaluations static %}

{% block top-bar %}{% endblock %}

Expand Down Expand Up @@ -58,13 +58,11 @@ <h2 class="fr-stepper__title">
{% endblock %}

{% block extra_css %}
{% leaflet_css %}
<link rel="stylesheet"
href="{% static 'accessible-autocomplete/dist/accessible-autocomplete.min.css' %}" />
{% endblock %}

{% block extra_js %}
{% leaflet_js %}
<script>ADDRESS_AUTOCOMPLETE_FIELD_NAME = 'address';</script>
<script defer
src="{% static 'accessible-autocomplete/dist/accessible-autocomplete.min.js' %}"></script>
Expand Down
4 changes: 1 addition & 3 deletions envergo/templates/evaluations/request.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{% extends 'base.html' %}

{% load evaluations leaflet_tags static %}
{% load evaluations static %}

{% block title %}Demandez une avis réglementaire{% endblock %}

Expand Down Expand Up @@ -102,13 +102,11 @@ <h1>Demandez un avis réglementaire pour un projet</h1>
{% endblock %}

{% block extra_css %}
{% leaflet_css %}
<link rel="stylesheet"
href="{% static 'accessible-autocomplete/dist/accessible-autocomplete.min.css' %}" />
{% endblock %}

{% block extra_js %}
{% leaflet_js %}
<script defer
src="{% static 'accessible-autocomplete/dist/accessible-autocomplete.min.js' %}"></script>
<script defer src="{% static 'js/libs/address_autocomplete.js' %}"></script>
Expand Down
1 change: 1 addition & 0 deletions envergo/templates/geodata/2150_debug.html
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ <h2 class="fr-h4">Pour améliorer ce démonstrateur</h2>
{% block extra_js %}
<script defer src="{% static 'leaflet/leaflet.js' %}"></script>
<script defer src="{% static 'leaflet/draw/leaflet.draw.js' %}"></script>
<script defer src="{% static 'js/libs/leaflet-icon-fix.js' %}"></script>
<script defer src="{% static 'js/libs/2150_map.js' %}"></script>
<script defer src="{% static 'js/libs/share_url_modal.js' %}"></script>

Expand Down
1 change: 1 addition & 0 deletions envergo/templates/geodata/admin/map_preview.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ <h1 class="fr-h6">Carte {{ map }}</h1>

{% block extra_js %}
<script defer src="{% static 'leaflet/dist/leaflet.js' %}"></script>
<script defer src="{% static 'js/libs/leaflet-icon-fix.js' %}"></script>
<script>
window.addEventListener('load', function() {

Expand Down
1 change: 1 addition & 0 deletions envergo/templates/moulinette/_form_scripts.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

<script defer src="{% static 'leaflet/dist/leaflet.js' %}"></script>
<script defer src="{% static 'leaflet/draw/leaflet.draw.js' %}"></script>
<script defer src="{% static 'js/libs/leaflet-icon-fix.js' %}"></script>
<script defer
src="{% static 'accessible-autocomplete/dist/accessible-autocomplete.min.js' %}"></script>
<script defer src="{% static 'js/libs/address_autocomplete.js' %}"></script>
Expand Down
1 change: 1 addition & 0 deletions envergo/templates/moulinette/result.html
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ <h2>

<script defer src="{% static 'leaflet/dist/leaflet.js' %}"></script>
<script defer src="{% static 'leaflet/draw/leaflet.draw.js' %}"></script>
<script defer src="{% static 'js/libs/leaflet-icon-fix.js' %}"></script>
<script defer src="{% static 'js/libs/moulinette_result_maps.js' %}"></script>
<script defer src="{% static 'js/libs/moulinette_analytics.js' %}"></script>
<script defer
Expand Down
6 changes: 0 additions & 6 deletions envergo/templates/moulinette/result_debug.html
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,6 @@ <h2>Catalogue de données</h2>

{% block extra_js %}
{{ block.super }}
<script>
window.addEventListener('load', function() {
L.Icon.Default.prototype.options.imagePath = '/static/leaflet/images/';
});
</script>

{% regroup grouped_perimeters by activation_map as map_list %}
{% for map in map_list %}
<script>
Expand Down

0 comments on commit 1a9cf39

Please sign in to comment.