Spaces:
Sleeping
Sleeping
File size: 4,279 Bytes
b593f0b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | // @flow
import DOM from '../../util/dom';
import {extend, bindAll} from '../../util/util';
import type Map from '../map';
type Unit = 'imperial' | 'metric' | 'nautical';
type Options = {
maxWidth?: number,
unit?: Unit;
};
const defaultOptions: Options = {
maxWidth: 100,
unit: 'metric'
};
/**
* A `ScaleControl` control displays the ratio of a distance on the map to the corresponding distance on the ground.
*
* @implements {IControl}
* @param {Object} [options]
* @param {number} [options.maxWidth='100'] The maximum length of the scale control in pixels.
* @param {string} [options.unit='metric'] Unit of the distance (`'imperial'`, `'metric'` or `'nautical'`).
* @example
* var scale = new mapboxgl.ScaleControl({
* maxWidth: 80,
* unit: 'imperial'
* });
* map.addControl(scale);
*
* scale.setUnit('metric');
*/
class ScaleControl {
_map: Map;
_container: HTMLElement;
options: Options;
constructor(options: Options) {
this.options = extend({}, defaultOptions, options);
bindAll([
'_onMove',
'setUnit'
], this);
}
getDefaultPosition() {
return 'bottom-left';
}
_onMove() {
updateScale(this._map, this._container, this.options);
}
onAdd(map: Map) {
this._map = map;
this._container = DOM.create('div', 'mapboxgl-ctrl mapboxgl-ctrl-scale', map.getContainer());
this._map.on('move', this._onMove);
this._onMove();
return this._container;
}
onRemove() {
DOM.remove(this._container);
this._map.off('move', this._onMove);
this._map = (undefined: any);
}
/**
* Set the scale's unit of the distance
*
* @param unit Unit of the distance (`'imperial'`, `'metric'` or `'nautical'`).
*/
setUnit(unit: Unit) {
this.options.unit = unit;
updateScale(this._map, this._container, this.options);
}
}
export default ScaleControl;
function updateScale(map, container, options) {
// A horizontal scale is imagined to be present at center of the map
// container with maximum length (Default) as 100px.
// Using spherical law of cosines approximation, the real distance is
// found between the two coordinates.
const maxWidth = options && options.maxWidth || 100;
const y = map._container.clientHeight / 2;
const left = map.unproject([0, y]);
const right = map.unproject([maxWidth, y]);
const maxMeters = left.distanceTo(right);
// The real distance corresponding to 100px scale length is rounded off to
// near pretty number and the scale length for the same is found out.
// Default unit of the scale is based on User's locale.
if (options && options.unit === 'imperial') {
const maxFeet = 3.2808 * maxMeters;
if (maxFeet > 5280) {
const maxMiles = maxFeet / 5280;
setScale(container, maxWidth, maxMiles, map._getUIString('ScaleControl.Miles'));
} else {
setScale(container, maxWidth, maxFeet, map._getUIString('ScaleControl.Feet'));
}
} else if (options && options.unit === 'nautical') {
const maxNauticals = maxMeters / 1852;
setScale(container, maxWidth, maxNauticals, map._getUIString('ScaleControl.NauticalMiles'));
} else if (maxMeters >= 1000) {
setScale(container, maxWidth, maxMeters / 1000, map._getUIString('ScaleControl.Kilometers'));
} else {
setScale(container, maxWidth, maxMeters, map._getUIString('ScaleControl.Meters'));
}
}
function setScale(container, maxWidth, maxDistance, unit) {
const distance = getRoundNum(maxDistance);
const ratio = distance / maxDistance;
container.style.width = `${maxWidth * ratio}px`;
container.innerHTML = `${distance} ${unit}`;
}
function getDecimalRoundNum(d) {
const multiplier = Math.pow(10, Math.ceil(-Math.log(d) / Math.LN10));
return Math.round(d * multiplier) / multiplier;
}
function getRoundNum(num) {
const pow10 = Math.pow(10, (`${Math.floor(num)}`).length - 1);
let d = num / pow10;
d = d >= 10 ? 10 :
d >= 5 ? 5 :
d >= 3 ? 3 :
d >= 2 ? 2 :
d >= 1 ? 1 : getDecimalRoundNum(d);
return pow10 * d;
}
|