import mapboxgl from 'mapbox-gl';
import distance from '@turf/distance';
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function iconRuler() {
return (new DOMParser().parseFromString("<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"22\" height=\"12\" viewBox=\"0 0 22 12\" fill=\"#505050\">\n <path fill-rule=\"evenodd\" fill=\"none\" d=\"M-1-6h24v24H-1z\"/>\n <path d=\"M20 0H2C.9 0 0 .9 0 2v8c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V2c0-1.1-.9-2-2-2zm0 10H2V2h2v4h2V2h2v4h2V2h2v4h2V2h2v4h2V2h2v8z\"/>\n</svg>", 'image/svg+xml')).firstChild;
}
var LAYER_LINE = 'controls-layer-line';
var LAYER_SYMBOL = 'controls-layer-symbol';
var SOURCE_LINE = 'controls-source-line';
var SOURCE_SYMBOL = 'controls-source-symbol';
var MAIN_COLOR = '#263238';
var HALO_COLOR = '#fff';
function geoLineString() {
var coordinates = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
return {
type: 'Feature',
properties: {},
geometry: {
type: 'LineString',
coordinates: coordinates
}
};
}
function geoPoint() {
var coordinates = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var labels = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
return {
type: 'FeatureCollection',
features: coordinates.map(function (c, i) {
return {
type: 'Feature',
properties: {
text: labels[i]
},
geometry: {
type: 'Point',
coordinates: c
}
};
})
};
}
function defaultLabelFormat(number) {
if (number < 1) {
return "".concat((number * 1000).toFixed(), " m");
}
return "".concat(number.toFixed(2), " km");
}
/**
* Fires map `ruler.on` and `ruler.off`events at the beginning and at the end of measuring.
* @param {Object} options
* @param {String} [options.units='kilometers'] - Any units [@turf/distance](https://github.com/Turfjs/turf/tree/master/packages/turf-distance) supports
* @param {Function} [options.labelFormat] - Accepts number and returns label.
* Can be used to convert value to any measuring units
* @param {Array} [options.font=['Roboto Medium']] - Array of fonts.
* @param {String} [options.mainColor='#263238'] - Color of ruler lines.
* @param {String} [options.secondaryColor='#fff'] - Color of halo and inner marker background.
* @param {String} [options.fontSize='12'] - Label font size
* @param {String} [options.fontHalo='1'] - Label font halo
*/
var RulerControl = /*#__PURE__*/function () {
function RulerControl() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_classCallCheck(this, RulerControl);
this.isMeasuring = false;
this.markers = [];
this.coordinates = [];
this.labels = [];
this.units = options.units || 'kilometers';
this.font = options.font || ['Roboto Medium'];
this.fontSize = options.fontSize || 12;
this.fontHalo = options.fontHalo || 1;
this.labelFormat = options.labelFormat || defaultLabelFormat;
this.mainColor = options.mainColor || MAIN_COLOR;
this.secondaryColor = options.secondaryColor || HALO_COLOR;
this.mapClickListener = this.mapClickListener.bind(this);
this.styleLoadListener = this.styleLoadListener.bind(this);
}
_createClass(RulerControl, [{
key: "insertControls",
value: function insertControls() {
this.container = document.createElement('div');
this.container.classList.add('mapboxgl-ctrl');
this.container.classList.add('mapboxgl-ctrl-group');
this.container.classList.add('mapboxgl-ctrl-ruler');
this.button = document.createElement('button');
this.button.setAttribute('type', 'button');
this.button.appendChild(iconRuler());
this.container.appendChild(this.button);
}
}, {
key: "draw",
value: function draw() {
this.map.addSource(SOURCE_LINE, {
type: 'geojson',
data: geoLineString(this.coordinates)
});
this.map.addSource(SOURCE_SYMBOL, {
type: 'geojson',
data: geoPoint(this.coordinates, this.labels)
});
this.map.addLayer({
id: LAYER_LINE,
type: 'line',
source: SOURCE_LINE,
paint: {
'line-color': this.mainColor,
'line-width': 2
}
});
this.map.addLayer({
id: LAYER_SYMBOL,
type: 'symbol',
source: SOURCE_SYMBOL,
layout: {
'text-field': '{text}',
'text-font': this.font,
'text-anchor': 'top',
'text-size': this.fontSize,
'text-offset': [0, 0.8]
},
paint: {
'text-color': this.mainColor,
'text-halo-color': this.secondaryColor,
'text-halo-width': this.fontHalo
}
});
}
}, {
key: "measuringOn",
value: function measuringOn() {
this.isMeasuring = true;
this.markers = [];
this.coordinates = [];
this.labels = [];
this.map.getCanvas().style.cursor = 'crosshair';
this.button.classList.add('-active');
this.draw();
this.map.on('click', this.mapClickListener);
this.map.on('style.load', this.styleLoadListener);
this.map.fire('ruler.on');
}
}, {
key: "measuringOff",
value: function measuringOff() {
this.isMeasuring = false;
this.map.getCanvas().style.cursor = '';
this.button.classList.remove('-active'); // remove layers, sources and event listeners
this.map.removeLayer(LAYER_LINE);
this.map.removeLayer(LAYER_SYMBOL);
this.map.removeSource(SOURCE_LINE);
this.map.removeSource(SOURCE_SYMBOL);
this.markers.forEach(function (m) {
return m.remove();
});
this.map.off('click', this.mapClickListener);
this.map.off('style.load', this.styleLoadListener);
this.map.fire('ruler.off');
}
}, {
key: "mapClickListener",
value: function mapClickListener(event) {
var _this = this;
var markerNode = document.createElement('div');
markerNode.style.width = '12px';
markerNode.style.height = '12px';
markerNode.style.borderRadius = '50%';
markerNode.style.background = this.secondaryColor;
markerNode.style.boxSizing = 'border-box';
markerNode.style.border = "2px solid ".concat(this.mainColor);
var marker = new mapboxgl.Marker({
element: markerNode,
draggable: true
}).setLngLat(event.lngLat).addTo(this.map);
this.coordinates.push([event.lngLat.lng, event.lngLat.lat]);
this.labels = this.coordinatesToLabels();
this.map.getSource(SOURCE_LINE).setData(geoLineString(this.coordinates));
this.map.getSource(SOURCE_SYMBOL).setData(geoPoint(this.coordinates, this.labels));
this.markers.push(marker);
marker.on('drag', function () {
var index = _this.markers.indexOf(marker);
var lngLat = marker.getLngLat();
_this.coordinates[index] = [lngLat.lng, lngLat.lat];
_this.labels = _this.coordinatesToLabels();
_this.map.getSource(SOURCE_LINE).setData(geoLineString(_this.coordinates));
_this.map.getSource(SOURCE_SYMBOL).setData(geoPoint(_this.coordinates, _this.labels));
});
}
}, {
key: "coordinatesToLabels",
value: function coordinatesToLabels() {
var coordinates = this.coordinates,
units = this.units,
labelFormat = this.labelFormat;
var sum = 0;
return coordinates.map(function (coordinate, index) {
if (index === 0) return labelFormat(0);
sum += distance(coordinates[index - 1], coordinates[index], {
units: units
});
return labelFormat(sum);
});
}
}, {
key: "styleLoadListener",
value: function styleLoadListener() {
this.draw();
}
}, {
key: "onAdd",
value: function onAdd(map) {
var _this2 = this;
this.map = map;
this.insertControls();
this.button.addEventListener('click', function () {
if (_this2.isMeasuring) {
_this2.measuringOff();
} else {
_this2.measuringOn();
}
});
return this.container;
}
}, {
key: "onRemove",
value: function onRemove() {
if (this.isMeasuring) {
this.measuringOff();
}
this.map.off('click', this.mapClickListener);
this.container.parentNode.removeChild(this.container);
this.map = undefined;
}
}]);
return RulerControl;
}();
export { RulerControl };