diff --git a/docs/references/fit-bounds.md b/docs/references/fit-bounds.md
index bdb6b44..1fdeb0f 100644
--- a/docs/references/fit-bounds.md
+++ b/docs/references/fit-bounds.md
@@ -4,7 +4,7 @@
## fitBounds
-> fitBounds(bounds, zoom = mapOptions.zoom)
+> fitBounds(bounds, zoom = mapOptions.zoom, padding = 50)
Set zoom and the display area limits of the map.
@@ -17,3 +17,15 @@ The display area limits of the map.
#### `zoom` - Number
The zoom level.
+
+#### `padding` - Number | Object
+
+The padding around the display area limits in pixel.
+If it's a number, all directions will have the same value.
+
+Object properties:
+
+- `top` - Number (optional, default `0`)
+- `right` - Number (optional, default `0`)
+- `bottom` - Number (optional, default `0`)
+- `left` - Number (optional, default `0`)
diff --git a/docs/references/index.md b/docs/references/index.md
index ff05cf7..74e3690 100644
--- a/docs/references/index.md
+++ b/docs/references/index.md
@@ -4,36 +4,37 @@
## Map Provider API
-- [Google Map](https://developers.google.com/maps/documentation/javascript/)
-- [Mappy (Leaflet)](http://leafletjs.com/reference-1.0.3.html)
-- [Leaflet](http://leafletjs.com/reference-1.5.1.html)
+- [Google Map](https://developers.google.com/maps/documentation/javascript/)
+- [Mappy (Leaflet)](http://leafletjs.com/reference-1.0.3.html)
+- [Leaflet](http://leafletjs.com/reference-1.5.1.html)
## Methods
-- [addCluster](add-cluster)
-- [addMarker](add-marker)
-- [addMarkers](add-markers)
-- [addUserMarker](add-user-marker)
-- [constructor](constructor)
-- [extendBounds](extend-bounds)
-- [fitBounds](fit-bounds)
-- [focusOnMarker](focus-on-marker)
-- [getGeolocation](get-geolocation)
-- [getMarkerIconByType](get-marker-icon-by-type)
-- [getMarkerIcons](get-marker-icons)
-- [getMarkerIconType](get-marker-icon-type)
-- [getMarker](get-marker)
-- [getMarkers](get-markers)
-- [getPoints](get-points)
-- [getBounds](get-bounds)
-- [initMap](init-map)
-- [listenZoomChange](listen-zoom-change)
-- [minifyMarkerIcons](minify-marker-icons)
-- [panTo](pan-to)
-- [removeMarker](remove-marker)
-- [setCenter](set-center)
-- [setIconOnMarker](set-icon-on-marker)
-- [setMapOptions](set-map-options)
-- [setMarkerIcons](set-marker-icons)
-- [setPoint](set-point)
-- [setZoom](set-zoom)
+- [addCluster](add-cluster)
+- [addMarker](add-marker)
+- [addMarkers](add-markers)
+- [addUserMarker](add-user-marker)
+- [constructor](constructor)
+- [extendBounds](extend-bounds)
+- [fitBounds](fit-bounds)
+- [focusOnMarker](focus-on-marker)
+- [getGeolocation](get-geolocation)
+- [getMarkerIconByType](get-marker-icon-by-type)
+- [getMarkerIcons](get-marker-icons)
+- [getMarkerIconType](get-marker-icon-type)
+- [getMarker](get-marker)
+- [getMarkers](get-markers)
+- [getPoints](get-points)
+- [getBounds](get-bounds)
+- [initMap](init-map)
+- [listenZoomChange](listen-zoom-change)
+- [minifyMarkerIcons](minify-marker-icons)
+- [panTo](pan-to)
+- [panBy](pan-by)
+- [removeMarker](remove-marker)
+- [setCenter](set-center)
+- [setIconOnMarker](set-icon-on-marker)
+- [setMapOptions](set-map-options)
+- [setMarkerIcons](set-marker-icons)
+- [setPoint](set-point)
+- [setZoom](set-zoom)
diff --git a/docs/references/pan-by.md b/docs/references/pan-by.md
new file mode 100644
index 0000000..6649351
--- /dev/null
+++ b/docs/references/pan-by.md
@@ -0,0 +1,19 @@
+# References
+
+[⇠ Go Back](../references/)
+
+## panBy
+
+> panBy(x, y)
+
+Changes the center of the map by the given distance in pixels.
+
+### Parameters
+
+#### `x` - Number
+
+The distance from west to east in pixels.
+
+#### `y` - Number
+
+The distance from north to south in pixels.
diff --git a/example/components/location.js b/example/components/location.js
index b3525ed..d9a5915 100644
--- a/example/components/location.js
+++ b/example/components/location.js
@@ -48,10 +48,10 @@ class LocationMapModule {
});
this.batMap.addMarkers();
- this.batMap.fitBounds(
- this.batMap.getBounds(),
- this.attr.options.locationZoom,
- );
+
+ const coords = this.attr.locations[0].localisation.coordinates;
+ this.map.setCenter(this.map.makeLatLng(coords.latitude, coords.longitude));
+ this.map.setZoom(this.attr.options.locationZoom);
}
}
diff --git a/example/components/results.js b/example/components/results.js
index bc7fb2e..1ad54c9 100644
--- a/example/components/results.js
+++ b/example/components/results.js
@@ -131,7 +131,14 @@ class ResultsMapModule {
this.batMap
.getGeolocation()
.then(position => {
- this.batMap.addUserMarker(position.coords, 'user');
+ this.batMap.addUserMarker(
+ this.map.makeLatLng(
+ position.coords.latitude,
+ position.coords.longitude,
+ ),
+ 'user',
+ );
+ this.batMap.panToAllMarkers();
})
.catch(error => {
console.error('geolocateOnMap(): ' + error.message);
@@ -167,6 +174,26 @@ class ResultsMapModule {
handleMouseEnterOnMarker(marker) {
return () => {
+ /**
+ * NOTE: Set all non active markers to default icon for Mappy and Leaflet
+ * prevent markers to not update correctly when showLabel is set to true
+ */
+ if (
+ this.attr.showLabel &&
+ (this.attr.provider === 'mappy' || this.attr.provider === 'leaflet')
+ ) {
+ this.getMarkers()
+ .filter(m => {
+ const type = this.getMarkerIconType(m);
+ return (
+ type !== 'active' && type !== 'default' && marker.id !== m.id
+ );
+ })
+ .forEach(m => {
+ this.setIconOnMarker(m, 'default');
+ });
+ }
+
if (
this.getMarkerIconType(marker) !== 'active' &&
this.getMarkerIconType(marker) !== 'hover'
diff --git a/src/AbstractMap.js b/src/AbstractMap.js
index a2df894..29c636d 100644
--- a/src/AbstractMap.js
+++ b/src/AbstractMap.js
@@ -33,6 +33,7 @@ export class AbstractMap {
this.icons = [];
this.bounds = null;
this.cluster = null;
+ this.focusInProgress = false;
this.defaultOptions = {
zoom: 12,
@@ -110,6 +111,10 @@ export class AbstractMap {
console.error(`${this.provider} has no 'setPoint' method implemented.`);
}
+ clearPoints() {
+ this.points.length = 0;
+ }
+
addMarkers() {
console.error(`${this.provider} has no 'addMarkers' method implemented.`);
}
@@ -128,6 +133,21 @@ export class AbstractMap {
console.error(`${this.provider} has no 'removeMarker' method implemented.`);
}
+ removeCluster() {
+ console.error(
+ `${this.provider} has no 'removeCluster' method implemented.`,
+ );
+ }
+
+ removeAllMarkers() {
+ if (this.cluster) {
+ this.removeCluster();
+ }
+ this.markers.forEach(marker => {
+ this.removeMarker(marker);
+ });
+ }
+
setMarkerIcons() {
console.error(
`${this.provider} has no 'setMarkerIcons' method implemented.`,
@@ -150,10 +170,20 @@ export class AbstractMap {
console.error(`${this.provider} has no 'addCluster' method implemented.`);
}
+ makeLatLng() {
+ console.error(`${this.provider} has no 'makeLatLng' method implemented.`);
+ }
+
setCenter() {
console.error(`${this.provider} has no 'setCenter' method implemented.`);
}
+ getCenterLatLng() {
+ console.error(
+ `${this.provider} has no 'getCenterLatLng' method implemented.`,
+ );
+ }
+
fitBounds() {
console.error(`${this.provider} has no 'fitBounds' method implemented.`);
}
@@ -166,10 +196,24 @@ export class AbstractMap {
console.error(`${this.provider} has no 'getBounds' method implemented.`);
}
+ getBoundsLatLng() {
+ console.error(
+ `${this.provider} has no 'getBoundsLatLng' method implemented.`,
+ );
+ }
+
panTo() {
console.error(`${this.provider} has no 'panTo' method implemented.`);
}
+ panBy() {
+ console.error(`${this.provider} has no 'panBy' method implemented.`);
+ }
+
+ getZoom() {
+ console.error(`${this.provider} has no 'getZoom' method implemented.`);
+ }
+
setZoom() {
console.error(`${this.provider} has no 'setZoom' method implemented.`);
}
@@ -180,6 +224,12 @@ export class AbstractMap {
);
}
+ listenBoundsChange() {
+ console.error(
+ `${this.provider} has no 'listenBoundsChange' method implemented.`,
+ );
+ }
+
minifyMarkerIcons() {
console.error(
`${this.provider} has no 'minifyMarkerIcons' method implemented.`,
diff --git a/src/providers/gmaps/index.js b/src/providers/gmaps/index.js
index 102abb3..ab1b401 100644
--- a/src/providers/gmaps/index.js
+++ b/src/providers/gmaps/index.js
@@ -42,6 +42,10 @@ export default class GoogleMaps extends AbstractMap {
'https://maps.googleapis.com/maps/api/js',
this.apiKey[1],
);
+
+ if (this.apiKey.length > 2) {
+ urlParams = urlParams + '&channel=' + this.apiKey[2];
+ }
} else {
urlParams = urlParams + '&key=' + this.apiKey;
}
@@ -79,6 +83,7 @@ export default class GoogleMaps extends AbstractMap {
initMap() {
this.bounds = new google.maps.LatLngBounds();
this.map = new google.maps.Map(this.domElement, this.mapOptions);
+ this.initialBoundsEvent = true;
}
setPoint(location, iconType, label = false) {
@@ -112,9 +117,11 @@ export default class GoogleMaps extends AbstractMap {
}
addMarker(point, eventCallback = {}) {
- const marker = new google.maps.Marker(point);
+ const marker = new google.maps.Marker({
+ map: this.map,
+ ...point,
+ });
this.markers.push(marker);
- marker.setMap(this.map);
this.setIconOnMarker(marker, point.iconType);
@@ -127,12 +134,16 @@ export default class GoogleMaps extends AbstractMap {
}
removeMarker(marker) {
- marker = this.getMarker(marker);
+ marker = marker ? marker : this.getMarker(marker);
marker.setMap(null);
this.markers = this.markers.filter(m => m.id !== marker.id);
}
+ removeCluster() {
+ this.cluster.clearMarkers();
+ }
+
setMarkerIcons() {
Object.keys(this.markersOptions).forEach(type => {
const options = this.markersOptions[type];
@@ -187,19 +198,37 @@ export default class GoogleMaps extends AbstractMap {
}
}
- focusOnMarker(marker) {
+ focusOnMarker(marker, offset = { x: 0, y: 0 }) {
+ this.focusInProgress = true;
+ let hasOffset = offset.x || offset.y;
marker = this.getMarker(marker);
+ const listener = this.map.addListener('idle', () => {
+ if (hasOffset) {
+ hasOffset = false;
+ this.map.panBy(offset.x, offset.y);
+ } else {
+ this.focusInProgress = false;
+ google.maps.event.removeListener(listener);
+ }
+ });
+
this.map.setZoom(this.mapOptions.locationZoom);
this.panTo(marker.position);
}
addUserMarker(position, iconType, id = 0) {
if (position) {
+ // Backward compatibility
+ const latLng =
+ position.latitude && position.longitude
+ ? this.makeLatLng(position.latitude, position.longitude)
+ : position;
+
const point = {
id: `${id}`,
map: this.map,
- position: new google.maps.LatLng(position.latitude, position.longitude),
+ position: latLng,
iconType,
};
@@ -226,10 +255,12 @@ export default class GoogleMaps extends AbstractMap {
width: icon.scaledSize.width,
height: icon.scaledSize.height,
anchorText: [
- icon.labelOrigin.y -
- icon.scaledSize.height / 2 +
- icon.labelOptions.size * 1.2,
- icon.labelOrigin.x - icon.scaledSize.width / 2,
+ Math.ceil(
+ icon.labelOrigin.y -
+ icon.scaledSize.height / 2 +
+ icon.labelOptions.size * 1.2,
+ ),
+ Math.ceil(icon.labelOrigin.x - icon.scaledSize.width / 2),
], // [yoffset, xoffset]
anchorIcon: [icon.anchor.y, icon.anchor.x], // [yoffset, xoffset]
textSize: icon.labelOptions.size,
@@ -245,56 +276,112 @@ export default class GoogleMaps extends AbstractMap {
);
}
+ getZoom() {
+ return this.map.getZoom();
+ }
+
setZoom(zoom) {
this.map.setZoom(zoom);
}
+ makeLatLng(latitude, longitude) {
+ return new google.maps.LatLng(latitude, longitude);
+ }
+
setCenter(position) {
this.map.setCenter(position);
}
+ getCenterLatLng() {
+ const center = this.map.getCenter();
+ return {
+ lat: center.lat(),
+ lng: center.lng(),
+ };
+ }
+
getBounds() {
return this.bounds;
}
+ getBoundsLatLng() {
+ const bounds = this.map.getBounds();
+ const northEast = bounds.getNorthEast();
+ const southWest = bounds.getSouthWest();
+ return [southWest.lat(), southWest.lng(), northEast.lat(), northEast.lng()];
+ }
+
extendBounds(position) {
return this.bounds.extend(position);
}
- fitBounds(bounds, zoom = this.mapOptions.zoom) {
- if (this.markers.length > 1) {
- this.map.fitBounds(bounds);
- } else {
- this.setCenter(this.markers[0].position);
- this.setZoom(zoom);
- }
+ fitBounds(bounds, _zoom, padding = 50) {
+ this.map.fitBounds(bounds, padding);
}
panTo(position) {
this.map.panTo(position);
}
+ panBy(x, y) {
+ this.map.panBy(x, y);
+ }
+
listenZoomChange(callback) {
this.map.addListener('zoom_changed', () => {
return callback(this.map.getZoom());
});
}
+ listenBoundsChange(callback, ignoreFocusOnMarker = true) {
+ this.map.addListener('bounds_changed', () => {
+ if (ignoreFocusOnMarker && this.focusInProgress) {
+ return;
+ }
+ if (this.initialBoundsEvent) {
+ this.initialBoundsEvent = false;
+ return;
+ }
+ return callback(this.getCenterLatLng());
+ });
+ }
+
minifyMarkerIcons(zoom, breakZoom = 8, minifier = 0.8) {
if (zoom < breakZoom + 1 && !this.isMinifiedMarkerIcons) {
[].forEach.call(Object.keys(this.icons), key => {
const size = this.icons[key].scaledSize;
- this.icons[key].scaledSize.width = size.width * minifier;
- this.icons[key].scaledSize.height = size.height * minifier;
+ const width = size.width * minifier;
+ const height = size.height * minifier;
+
+ this.icons[key].scaledSize = new google.maps.Size(width, height);
+ this.icons[key].anchor = new google.maps.Point(width / 2, height);
});
+ this.refreshAllMarkers();
+
this.isMinifiedMarkerIcons = true;
} else if (zoom > breakZoom && this.isMinifiedMarkerIcons) {
[].forEach.call(Object.keys(this.icons), key => {
const size = this.icons[key].scaledSize;
- this.icons[key].scaledSize.width = size.width / minifier;
- this.icons[key].scaledSize.height = size.height / minifier;
+ const width = size.width / minifier;
+ const height = size.height / minifier;
+
+ this.icons[key].scaledSize = new google.maps.Size(width, height);
+ this.icons[key].anchor = new google.maps.Point(width / 2, height);
});
+ this.refreshAllMarkers();
+
this.isMinifiedMarkerIcons = false;
}
}
+
+ refreshAllMarkers() {
+ this.getMarkers().forEach(marker => {
+ const iconName = this.getMarkerIconType(marker);
+ marker.setIcon(this.icons[iconName]);
+ });
+
+ if (this.userMarker) {
+ this.userMarker.setIcon(this.icons.user);
+ }
+ }
}
diff --git a/src/providers/leaflet/index.js b/src/providers/leaflet/index.js
index a155a82..1cfe58b 100644
--- a/src/providers/leaflet/index.js
+++ b/src/providers/leaflet/index.js
@@ -128,8 +128,7 @@ export default class Leaflet extends AbstractMap {
const marker = L.marker(point.position, point);
marker.id = point.id;
marker.location = point.location;
-
- this.setIconOnMarker(marker, point.iconType);
+ marker.options.alt = 'marker ' + point.location.name;
if (this.showCluster && this.icons.cluster) {
this.cluster.addLayer(marker);
@@ -145,6 +144,8 @@ export default class Leaflet extends AbstractMap {
this.extendBounds(marker.getLatLng());
this.markers.push(marker);
+
+ this.setIconOnMarker(marker, point.iconType);
}
removeMarker(marker) {
@@ -154,6 +155,10 @@ export default class Leaflet extends AbstractMap {
this.markers = this.markers.filter(m => m.id !== marker.id);
}
+ removeCluster() {
+ this.cluster.remove();
+ }
+
setMarkerIcons() {
Object.keys(this.markersOptions).forEach(type => {
const options = this.markersOptions[type];
@@ -207,7 +212,7 @@ export default class Leaflet extends AbstractMap {
className: icon.options.className,
iconSize: icon.options.iconSize,
iconAnchor: icon.options.iconAnchor,
- html: `
${span.outerHTML}`,
+ html: `
${span.outerHTML}`,
}),
);
} else {
@@ -216,17 +221,34 @@ export default class Leaflet extends AbstractMap {
}
}
- focusOnMarker(marker) {
+ focusOnMarker(marker, offset = { x: 0, y: 0 }) {
+ this.focusInProgress = true;
+ let hasOffset = offset.x || offset.y;
marker = this.getMarker(marker);
+ const onMoveEnd = () => {
+ if (hasOffset) {
+ hasOffset = false;
+ this.map.panBy(new L.Point(offset.x, offset.y));
+ } else {
+ this.focusInProgress = false;
+ this.map.off('moveend', onMoveEnd, this);
+ }
+ };
+ this.map.on('moveend', onMoveEnd, this);
+
this.panTo(marker.getLatLng());
}
addUserMarker(position, iconType, id = 0) {
if (position) {
- this.userMarker = new L.marker(
- L.latLng(position.latitude, position.longitude),
- );
+ // Backward compatibility
+ const latLng =
+ position.latitude && position.longitude
+ ? this.makeLatLng(position.latitude, position.longitude)
+ : position;
+
+ this.userMarker = new L.marker(latLng);
this.userMarker.id = id;
this.userMarker.addTo(this.map);
@@ -274,74 +296,120 @@ export default class Leaflet extends AbstractMap {
this.map.addLayer(this.cluster);
}
+ getZoom() {
+ return this.map.getZoom();
+ }
+
setZoom(zoom) {
this.map.setZoom(zoom);
}
+ makeLatLng(latitude, longitude) {
+ return L.latLng(latitude, longitude);
+ }
+
setCenter(position, zoom = this.mapOptions.zoom) {
this.map.setView(position, zoom);
}
+ getCenterLatLng() {
+ return this.map.getCenter();
+ }
+
getBounds() {
return this.bounds;
}
+ getBoundsLatLng() {
+ const bounds = this.map.getBounds();
+ const northEast = bounds.getNorthEast();
+ const southWest = bounds.getSouthWest();
+ return [southWest.lat, southWest.lng, northEast.lat, northEast.lng];
+ }
+
extendBounds(position) {
return this.bounds.extend(position);
}
- fitBounds(bounds, zoom = this.mapOptions.zoom) {
- if (this.markers.length > 1) {
- this.map.fitBounds(bounds, {
- padding: L.point(50, 50),
- maxZoom: zoom,
- });
+ fitBounds(bounds, zoom = this.mapOptions.zoom, padding = 50) {
+ const options = {
+ maxZoom: zoom,
+ };
+
+ if (!isNaN(padding)) {
+ options['padding'] = L.point(padding, padding);
} else {
- this.setCenter(this.markers[0].getLatLng(), zoom);
+ options['paddingTopLeft'] = L.point(padding.left || 0, padding.top || 0);
+ options['paddingBottomRight'] = L.point(
+ padding.right || 0,
+ padding.bottom || 0,
+ );
}
+
+ this.map.fitBounds(bounds, options);
}
panTo(position, zoom = this.mapOptions.locationZoom) {
this.map.flyTo(position, zoom);
}
+ panBy(x, y) {
+ this.map.panBy(L.point(x, y));
+ }
+
listenZoomChange(callback) {
this.map.on('zoomend', () => {
return callback(this.map.getZoom());
});
}
+ listenBoundsChange(callback, ignoreFocusOnMarker = true) {
+ this.map.on('move', () => {
+ if (ignoreFocusOnMarker && this.focusInProgress) {
+ return;
+ }
+ return callback(this.getCenterLatLng());
+ });
+ }
+
minifyMarkerIcons(zoom, breakZoom = 8, minifier = 0.8) {
if (zoom < breakZoom + 1 && !this.isMinifiedMarkerIcons) {
[].forEach.call(Object.keys(this.icons), key => {
const size = this.icons[key].options.iconSize;
- this.icons[key].options.iconSize = [
- size[0] * minifier,
- size[1] * minifier,
- ];
+ const width = size[0] * minifier;
+ const height = size[1] * minifier;
+
+ this.icons[key].options.iconSize = [width, height];
+ this.icons[key].options.iconAnchor = [width / 2, height];
});
+
+ this.refreshAllMarkers();
+
this.isMinifiedMarkerIcons = true;
- this.updateAllMarkerIconsOnMap();
} else if (zoom > breakZoom && this.isMinifiedMarkerIcons) {
[].forEach.call(Object.keys(this.icons), key => {
const size = this.icons[key].options.iconSize;
- this.icons[key].options.iconSize = [
- size[0] / minifier,
- size[1] / minifier,
- ];
+ const width = size[0] / minifier;
+ const height = size[1] / minifier;
+
+ this.icons[key].options.iconSize = [width, height];
+ this.icons[key].options.iconAnchor = [width / 2, height];
});
+
+ this.refreshAllMarkers();
+
this.isMinifiedMarkerIcons = false;
- this.updateAllMarkerIconsOnMap();
}
}
- updateAllMarkerIconsOnMap() {
- [].forEach.call(this.markers, marker => {
- this.setIconOnMarker(marker, marker.iconType, false);
+ refreshAllMarkers() {
+ this.getMarkers().forEach(marker => {
+ const iconName = this.getMarkerIconType(marker);
+ marker.setIcon(this.icons[iconName]);
});
if (this.userMarker) {
- this.setIconOnMarker(this.userMarker, this.userMarker.iconType, false);
+ this.userMarker.setIcon(this.icons.user);
}
}
}
diff --git a/src/providers/mappy-widget/index.js b/src/providers/mappy-widget/index.js
index 5f35589..7c1ff49 100644
--- a/src/providers/mappy-widget/index.js
+++ b/src/providers/mappy-widget/index.js
@@ -143,6 +143,7 @@ export default class MappyWidget extends AbstractMap {
const marker = L.marker(point.position, point);
marker.id = point.id;
marker.location = point.location;
+ marker.options.alt = 'marker ' + point.location.name;
this.setIconOnMarker(marker, point.iconType);
@@ -225,7 +226,7 @@ export default class MappyWidget extends AbstractMap {
className: icon.options.className,
iconSize: icon.options.iconSize,
iconAnchor: icon.options.iconAnchor,
- html: `
${span.outerHTML}`,
+ html: `
${span.outerHTML}`,
}),
);
} else {
diff --git a/src/providers/mappy/index.js b/src/providers/mappy/index.js
index 7bbb7e9..5a9235f 100644
--- a/src/providers/mappy/index.js
+++ b/src/providers/mappy/index.js
@@ -9,6 +9,8 @@ import objectAssign from 'object-assign';
import { AbstractMap } from '../../AbstractMap';
import { domUtils, loaderUtils } from '../../utils';
+let L;
+
export default class Mappy extends AbstractMap {
constructor(...args) {
super(...args);
@@ -65,8 +67,8 @@ export default class Mappy extends AbstractMap {
}
domUtils.addResources(document.head, resources, () => {
- this.L = window.L;
- this.L.Mappy.setImgPath(
+ L = window.L;
+ L.Mappy.setImgPath(
'//d11lbkprc85eyb.cloudfront.net/Mappy/7.5.0/images/',
);
callback();
@@ -107,13 +109,13 @@ export default class Mappy extends AbstractMap {
}
initMap() {
- this.bounds = new this.L.latLngBounds([]);
- this.map = new this.L.Mappy.Map(this.domElement, this.mapOptions);
+ this.bounds = new L.latLngBounds([]);
+ this.map = new L.Mappy.Map(this.domElement, this.mapOptions);
}
setPoint(location, iconType, label = false) {
const point = {
- position: this.L.latLng(
+ position: L.latLng(
location.localisation.coordinates.latitude,
location.localisation.coordinates.longitude,
),
@@ -140,11 +142,10 @@ export default class Mappy extends AbstractMap {
}
addMarker(point, eventCallback = {}) {
- const marker = this.L.marker(point.position, point);
+ const marker = L.marker(point.position, point);
marker.id = point.id;
marker.location = point.location;
-
- this.setIconOnMarker(marker, point.iconType);
+ marker.options.alt = 'marker ' + point.location.name;
if (this.showCluster && this.icons.cluster) {
this.cluster.addLayer(marker);
@@ -160,6 +161,8 @@ export default class Mappy extends AbstractMap {
this.extendBounds(marker.getLatLng());
this.markers.push(marker);
+
+ this.setIconOnMarker(marker, point.iconType);
}
removeMarker(marker) {
@@ -169,13 +172,17 @@ export default class Mappy extends AbstractMap {
this.markers = this.markers.filter(m => m.id !== marker.id);
}
+ removeCluster() {
+ this.cluster.remove();
+ }
+
setMarkerIcons() {
Object.keys(this.markersOptions).forEach(type => {
const options = this.markersOptions[type];
const iconAnchor = options.anchor || [options.width / 2, options.height];
const iconLabelOptions = options.label || {};
- this.icons[type] = new this.L.Icon({
+ this.icons[type] = new L.Icon({
className: `batmap-marker-${type}`,
iconUrl: options.url,
iconSize: [options.width, options.height],
@@ -218,11 +225,11 @@ export default class Mappy extends AbstractMap {
span.style.fontSize = `${labelOptions.size}px`;
marker.setIcon(
- new this.L.DivIcon({
+ new L.DivIcon({
className: icon.options.className,
iconSize: icon.options.iconSize,
iconAnchor: icon.options.iconAnchor,
- html: `
${span.outerHTML}`,
+ html: `
${span.outerHTML}`,
}),
);
} else {
@@ -231,17 +238,34 @@ export default class Mappy extends AbstractMap {
}
}
- focusOnMarker(marker) {
+ focusOnMarker(marker, offset = { x: 0, y: 0 }) {
+ this.focusInProgress = true;
+ let hasOffset = offset.x || offset.y;
marker = this.getMarker(marker);
+ const onMoveEnd = () => {
+ if (hasOffset) {
+ hasOffset = false;
+ this.map.panBy(offset);
+ } else {
+ this.focusInProgress = false;
+ this.map.off('moveend', onMoveEnd, this);
+ }
+ };
+ this.map.on('moveend', onMoveEnd, this);
+
this.panTo(marker.getLatLng());
}
addUserMarker(position, iconType, id = 0) {
if (position) {
- this.userMarker = new this.L.marker(
- this.L.latLng(position.latitude, position.longitude),
- );
+ // Backward compatibility
+ const latLng =
+ position.latitude && position.longitude
+ ? this.makeLatLng(position.latitude, position.longitude)
+ : position;
+
+ this.userMarker = new L.marker(latLng);
this.userMarker.id = id;
this.userMarker.addTo(this.map);
@@ -253,7 +277,7 @@ export default class Mappy extends AbstractMap {
addCluster() {
const icon = this.icons.cluster;
- this.cluster = this.L.markerClusterGroup(
+ this.cluster = L.markerClusterGroup(
objectAssign(
{
showCoverageOnHover: false,
@@ -273,7 +297,7 @@ export default class Mappy extends AbstractMap {
span.style.fontWeight = `${labelOptions.weight}`;
span.style.fontSize = `${labelOptions.size}px`;
- return this.L.divIcon({
+ return L.divIcon({
className: icon.options.className,
html:
`
` +
@@ -289,74 +313,120 @@ export default class Mappy extends AbstractMap {
this.map.addLayer(this.cluster);
}
+ getZoom() {
+ return this.map.getZoom();
+ }
+
setZoom(zoom) {
this.map.setZoom(zoom);
}
+ makeLatLng(latitude, longitude) {
+ return L.latLng(latitude, longitude);
+ }
+
setCenter(position, zoom = this.mapOptions.zoom) {
this.map.setView(position, zoom);
}
+ getCenterLatLng() {
+ return this.map.getCenter();
+ }
+
getBounds() {
return this.bounds;
}
+ getBoundsLatLng() {
+ const bounds = this.map.getBounds();
+ const northEast = bounds.getNorthEast();
+ const southWest = bounds.getSouthWest();
+ return [southWest.lat, southWest.lng, northEast.lat, northEast.lng];
+ }
+
extendBounds(position) {
return this.bounds.extend(position);
}
- fitBounds(bounds, zoom = this.mapOptions.zoom) {
- if (this.markers.length > 1) {
- this.map.fitBounds(bounds, {
- padding: this.L.point(50, 50),
- maxZoom: zoom,
- });
+ fitBounds(bounds, zoom = this.mapOptions.zoom, padding = 50) {
+ const options = {
+ maxZoom: zoom,
+ };
+
+ if (!isNaN(padding)) {
+ options['padding'] = L.point(padding, padding);
} else {
- this.setCenter(this.markers[0].getLatLng(), zoom);
+ options['paddingTopLeft'] = L.point(padding.left || 0, padding.top || 0);
+ options['paddingBottomRight'] = L.point(
+ padding.right || 0,
+ padding.bottom || 0,
+ );
}
+
+ this.map.fitBounds(bounds, options);
}
panTo(position, zoom = this.mapOptions.locationZoom) {
this.map.setView(position, zoom);
}
+ panBy(x, y) {
+ this.map.panBy(L.point(x, y));
+ }
+
listenZoomChange(callback) {
this.map.on('zoomend', () => {
return callback(this.map.getZoom());
});
}
+ listenBoundsChange(callback, ignoreFocusOnMarker = true) {
+ this.map.on('move', () => {
+ if (ignoreFocusOnMarker && this.focusInProgress) {
+ return;
+ }
+ return callback(this.getCenterLatLng());
+ });
+ }
+
minifyMarkerIcons(zoom, breakZoom = 8, minifier = 0.8) {
if (zoom < breakZoom + 1 && !this.isMinifiedMarkerIcons) {
[].forEach.call(Object.keys(this.icons), key => {
const size = this.icons[key].options.iconSize;
- this.icons[key].options.iconSize = [
- size[0] * minifier,
- size[1] * minifier,
- ];
+ const width = size[0] * minifier;
+ const height = size[1] * minifier;
+
+ this.icons[key].options.iconSize = [width, height];
+ this.icons[key].options.iconAnchor = [width / 2, height];
});
+
+ this.refreshAllMarkers();
+
this.isMinifiedMarkerIcons = true;
- this.updateAllMarkerIconsOnMap();
} else if (zoom > breakZoom && this.isMinifiedMarkerIcons) {
[].forEach.call(Object.keys(this.icons), key => {
const size = this.icons[key].options.iconSize;
- this.icons[key].options.iconSize = [
- size[0] / minifier,
- size[1] / minifier,
- ];
+ const width = size[0] / minifier;
+ const height = size[1] / minifier;
+
+ this.icons[key].options.iconSize = [width, height];
+ this.icons[key].options.iconAnchor = [width / 2, height];
});
+
+ this.refreshAllMarkers();
+
this.isMinifiedMarkerIcons = false;
- this.updateAllMarkerIconsOnMap();
}
}
- updateAllMarkerIconsOnMap() {
- [].forEach.call(this.markers, marker => {
- this.setIconOnMarker(marker, marker.iconType, false);
+ refreshAllMarkers() {
+ this.getMarkers().forEach(marker => {
+ const iconName = this.getMarkerIconType(marker);
+ marker.setIcon(this.icons[iconName]);
});
if (this.userMarker) {
- this.setIconOnMarker(this.userMarker, this.userMarker.iconType, false);
+ this.userMarker.setIcon(this.icons.user);
}
}
}