Bryan Housel
2018-03-22 16:51:53 -04:00
parent c08d79e488
commit 1dbf273878
12 changed files with 206 additions and 264 deletions

View File

@@ -5,8 +5,7 @@
"es6": true
},
"extends": [
"eslint:recommended",
"plugin:flowtype/recommended"
"eslint:recommended"
],
"globals": {
"d3": false
@@ -16,9 +15,6 @@
"ecmaVersion": 6,
"sourceType": "module"
},
"plugins": [
"flowtype"
],
"rules": {
"dot-notation": "error",
"eqeqeq": ["error", "smart"],
@@ -72,10 +68,5 @@
"space-unary-ops": "error",
"wrap-regex": "off",
"quotes": ["error", "single"]
},
"settings": {
"flowtype": {
"onlyFilesWithFlowAnnotation": true
}
}
}
}

View File

@@ -6,8 +6,6 @@ const nodeResolve = require('rollup-plugin-node-resolve');
const commonjs = require('rollup-plugin-commonjs');
const json = require('rollup-plugin-json');
const colors = require('colors/safe');
const flowRemoveTypes = require('flow-remove-types');
module.exports = function buildSrc() {
var cache;
@@ -28,7 +26,6 @@ module.exports = function buildSrc() {
.rollup({
input: './modules/id.js',
plugins: [
flow(),
nodeResolve({
module: true,
main: true,
@@ -67,15 +64,3 @@ function unlink(f) {
fs.unlinkSync(f);
} catch (e) { /* noop */ }
}
// Using this instead of rollup-plugin-flow due to
// https://github.com/leebyron/rollup-plugin-flow/issues/5
function flow() {
return {
name: 'flow-remove-types',
transform: (code) => ({
code: flowRemoveTypes(code).toString(),
map: null
})
};
}

View File

@@ -1,6 +1,3 @@
// @flow
import type { Vec2, Mat2 } from '.';
import _extend from 'lodash-es/extend';
import {
@@ -9,7 +6,7 @@ import {
} from './index';
export function geoExtent(min?: Vec2 | Mat2, max?: Vec2) {
export function geoExtent(min, max) {
if (!(this instanceof geoExtent)) {
return new geoExtent(min, max);
} else if (min instanceof geoExtent) {
@@ -39,8 +36,8 @@ _extend(geoExtent.prototype, {
extend: function(obj) {
if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
return geoExtent(
[(Math.min(obj[0][0], this[0][0]): number), (Math.min(obj[0][1], this[0][1]): number)],
[(Math.max(obj[1][0], this[1][0]): number), (Math.max(obj[1][1], this[1][1]): number)]
[Math.min(obj[0][0], this[0][0]), Math.min(obj[0][1], this[0][1])],
[Math.max(obj[1][0], this[1][0]), Math.max(obj[1][1], this[1][1])]
);
},
@@ -59,8 +56,7 @@ _extend(geoExtent.prototype, {
center: function() {
return [(this[0][0] + this[1][0]) / 2,
(this[0][1] + this[1][1]) / 2];
return [(this[0][0] + this[1][0]) / 2, (this[0][1] + this[1][1]) / 2];
},
@@ -106,8 +102,8 @@ _extend(geoExtent.prototype, {
intersection: function(obj) {
if (!this.intersects(obj)) return new geoExtent();
return new geoExtent(
[(Math.max(obj[0][0], this[0][0]): number), (Math.max(obj[0][1], this[0][1]): number)],
[(Math.min(obj[1][0], this[1][0]): number), (Math.min(obj[1][1], this[1][1]): number)]
[Math.max(obj[0][0], this[0][0]), Math.max(obj[0][1], this[0][1])],
[Math.min(obj[1][0], this[1][0]), Math.min(obj[1][1], this[1][1])]
);
},
@@ -125,9 +121,9 @@ _extend(geoExtent.prototype, {
},
padByMeters: function(meters: number) {
var dLat: number = geoMetersToLat(meters);
var dLon: number = geoMetersToLon(meters, this.center()[1]);
padByMeters: function(meters) {
var dLat = geoMetersToLat(meters);
var dLon = geoMetersToLon(meters, this.center()[1]);
return geoExtent(
[this[0][0] - dLon, this[0][1] - dLat],
[this[1][0] + dLon, this[1][1] + dLat]

View File

@@ -1,35 +1,32 @@
// @flow
import type { Vec2 } from '.';
// constants
var TAU = 2 * Math.PI;
var EQUATORIAL_RADIUS = 6356752.314245179;
var POLAR_RADIUS = 6378137.0;
export function geoLatToMeters(dLat: number): number {
export function geoLatToMeters(dLat) {
return dLat * (TAU * POLAR_RADIUS / 360);
}
export function geoLonToMeters(dLon: number, atLat: number): number {
export function geoLonToMeters(dLon, atLat) {
return Math.abs(atLat) >= 90 ? 0 :
dLon * (TAU * EQUATORIAL_RADIUS / 360) * Math.abs(Math.cos(atLat * (Math.PI / 180)));
}
export function geoMetersToLat(m: number): number {
export function geoMetersToLat(m) {
return m / (TAU * POLAR_RADIUS / 360);
}
export function geoMetersToLon(m: number, atLat: number): number {
export function geoMetersToLon(m, atLat) {
return Math.abs(atLat) >= 90 ? 0 :
m / (TAU * EQUATORIAL_RADIUS / 360) / Math.abs(Math.cos(atLat * (Math.PI / 180)));
}
export function geoMetersToOffset(meters: Vec2, tileSize?: number): Vec2 {
export function geoMetersToOffset(meters, tileSize) {
tileSize = tileSize || 256;
return [
meters[0] * tileSize / (TAU * EQUATORIAL_RADIUS),
@@ -38,7 +35,7 @@ export function geoMetersToOffset(meters: Vec2, tileSize?: number): Vec2 {
}
export function geoOffsetToMeters(offset: Vec2, tileSize?: number): Vec2 {
export function geoOffsetToMeters(offset, tileSize) {
tileSize = tileSize || 256;
return [
offset[0] * TAU * EQUATORIAL_RADIUS / tileSize,
@@ -48,23 +45,23 @@ export function geoOffsetToMeters(offset: Vec2, tileSize?: number): Vec2 {
// Equirectangular approximation of spherical distances on Earth
export function geoSphericalDistance(a: Vec2, b: Vec2): number {
var x: number = geoLonToMeters(a[0] - b[0], (a[1] + b[1]) / 2);
var y: number = geoLatToMeters(a[1] - b[1]);
export function geoSphericalDistance(a, b) {
var x = geoLonToMeters(a[0] - b[0], (a[1] + b[1]) / 2);
var y = geoLatToMeters(a[1] - b[1]);
return Math.sqrt((x * x) + (y * y));
}
// scale to zoom
export function geoScaleToZoom(k: number, tileSize?: number): number {
export function geoScaleToZoom(k, tileSize) {
tileSize = tileSize || 256;
var log2ts: number = Math.log(tileSize) * Math.LOG2E;
var log2ts = Math.log(tileSize) * Math.LOG2E;
return Math.log(k * TAU) / Math.LN2 - log2ts;
}
// zoom to scale
export function geoZoomToScale(z: number, tileSize?: number): number {
export function geoZoomToScale(z, tileSize) {
tileSize = tileSize || 256;
return tileSize * Math.pow(2, z) / TAU;
}

View File

@@ -1,8 +1,3 @@
// @flow
import type { Vec2 } from '.';
type Node = { id: string, loc: Vec2 };
type Edge = { index: number, distance: number, loc: ?Vec2 };
import _every from 'lodash-es/every';
import _some from 'lodash-es/some';
@@ -19,18 +14,18 @@ import {
// Return the counterclockwise angle in the range (-pi, pi)
// between the positive X axis and the line intersecting a and b.
export function geoAngle(a: Node, b: Node, projection: (Vec2) => Vec2): number {
export function geoAngle(a, b, projection) {
return geoVecAngle(projection(a.loc), projection(b.loc));
}
export function geoEdgeEqual(a: Vec2, b: Vec2): boolean {
export function geoEdgeEqual(a, b) {
return (a[0] === b[0] && a[1] === b[1]) ||
(a[0] === b[1] && a[1] === b[0]);
}
// Rotate all points counterclockwise around a pivot point by given angle
export function geoRotate(points: Array<Vec2>, angle: number, around: Vec2): Array<Vec2> {
return points.map(function(point: Vec2) {
export function geoRotate(points, angle, around) {
return points.map(function(point) {
var radial = geoVecSubtract(point, around);
return [
radial[0] * Math.cos(angle) - radial[1] * Math.sin(angle) + around[0],
@@ -44,7 +39,7 @@ export function geoRotate(points: Array<Vec2>, angle: number, around: Vec2): Arr
// projection onto that edge, if such a projection exists, or the distance to
// the closest vertex on that edge. Returns an object with the `index` of the
// chosen edge, the chosen `loc` on that edge, and the `distance` to to it.
export function geoChooseEdge(nodes: Array<Node>, point: Vec2, projection: (loc: Vec2) => Vec2, activeID?: string): ?Edge {
export function geoChooseEdge(nodes, point, projection, activeID) {
var dist = geoVecLength;
var points = nodes.map(function(n) { return projection(n.loc); });
var ids = nodes.map(function(n) { return n.id; });
@@ -89,7 +84,7 @@ export function geoChooseEdge(nodes: Array<Node>, point: Vec2, projection: (loc:
// This is used to test e.g. multipolygon rings that cross
// `activeNodes` is the ring containing the activeID being dragged.
// `inactiveNodes` is the other ring to test against
export function geoHasLineIntersections(activeNodes: Array<Node>, inactiveNodes: Array<Node>, activeID?: string): boolean {
export function geoHasLineIntersections(activeNodes, inactiveNodes, activeID) {
var actives = [];
var inactives = [];
var j, k, n1, n2, segment;
@@ -130,7 +125,7 @@ export function geoHasLineIntersections(activeNodes: Array<Node>, inactiveNodes:
// Test active (dragged or drawing) segments against inactive segments
// This is used to test whether a way intersects with itself.
export function geoHasSelfIntersections(nodes: Array<Node>, activeID?: string): boolean {
export function geoHasSelfIntersections(nodes, activeID) {
var actives = [];
var inactives = [];
var j, k;
@@ -180,7 +175,7 @@ export function geoHasSelfIntersections(nodes: Array<Node>, activeID?: string):
// From https://github.com/pgkelley4/line-segments-intersect
// This uses the vector cross product approach described below:
// http://stackoverflow.com/a/565282/786339
export function geoLineIntersection(a: Array<Vec2>, b: Array<Vec2>): ?Vec2 {
export function geoLineIntersection(a, b) {
var p = [a[0][0], a[0][1]];
var p2 = [a[1][0], a[1][1]];
var q = [b[0][0], b[0][1]];
@@ -203,7 +198,7 @@ export function geoLineIntersection(a: Array<Vec2>, b: Array<Vec2>): ?Vec2 {
}
export function geoPathIntersections(path1: Array<Vec2>, path2: Array<Vec2>): Array<Vec2> {
export function geoPathIntersections(path1, path2) {
var intersections = [];
for (var i = 0; i < path1.length - 1; i++) {
for (var j = 0; j < path2.length - 1; j++) {
@@ -218,7 +213,7 @@ export function geoPathIntersections(path1: Array<Vec2>, path2: Array<Vec2>): Ar
return intersections;
}
export function geoPathHasIntersections(path1: Array<Vec2>, path2: Array<Vec2>): boolean {
export function geoPathHasIntersections(path1, path2) {
for (var i = 0; i < path1.length - 1; i++) {
for (var j = 0; j < path2.length - 1; j++) {
var a = [ path1[i], path1[i+1] ];
@@ -242,7 +237,7 @@ export function geoPathHasIntersections(path1: Array<Vec2>, path2: Array<Vec2>):
// ray-casting algorithm based on
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
//
export function geoPointInPolygon(point: Vec2, polygon: Array<Vec2>): boolean {
export function geoPointInPolygon(point, polygon) {
var x = point[0];
var y = point[1];
var inside = false;
@@ -262,14 +257,14 @@ export function geoPointInPolygon(point: Vec2, polygon: Array<Vec2>): boolean {
}
export function geoPolygonContainsPolygon(outer: Array<Vec2>, inner: Array<Vec2>): boolean {
export function geoPolygonContainsPolygon(outer, inner) {
return _every(inner, function(point) {
return geoPointInPolygon(point, outer);
});
}
export function geoPolygonIntersectsPolygon(outer: Array<Vec2>, inner: Array<Vec2>, checkSegments: boolean): boolean {
export function geoPolygonIntersectsPolygon(outer, inner, checkSegments) {
function testPoints(outer, inner) {
return _some(inner, function(point) {
return geoPointInPolygon(point, outer);
@@ -280,7 +275,7 @@ export function geoPolygonIntersectsPolygon(outer: Array<Vec2>, inner: Array<Vec
}
export function geoPathLength(path: Array<Vec2>): number {
export function geoPathLength(path) {
var length = 0;
for (var i = 0; i < path.length - 1; i++) {
length += geoVecLength(path[i], path[i + 1]);
@@ -291,7 +286,7 @@ export function geoPathLength(path: Array<Vec2>): number {
// If the given point is at the edge of the padded viewport,
// return a vector that will nudge the viewport in that direction
export function geoViewportEdge(point: Vec2, dimensions: Vec2): ?Vec2 {
export function geoViewportEdge(point, dimensions) {
var pad = [80, 20, 50, 20]; // top, right, bottom, left
var x = 0;
var y = 0;

View File

@@ -1,8 +1,3 @@
// @flow
export type Vec2 = [number, number];
export type Mat2 = [Vec2, Vec2];
export type Transform = { x: number, y: number, k: number };
export { geoExtent } from './extent.js';
export { geoLatToMeters } from './geo.js';
@@ -42,4 +37,3 @@ export { geoVecInterp } from './vector.js';
export { geoVecLength } from './vector.js';
export { geoVecSubtract } from './vector.js';
export { geoVecScale } from './vector.js';

View File

@@ -1,6 +1,3 @@
// @flow
import type { Mat2, Vec2, Transform } from '.';
import {
geoMercatorRaw as d3_geoMercatorRaw,
geoTransform as d3_geoTransform
@@ -19,32 +16,32 @@ import {
*/
export function geoRawMercator() {
var project = d3_geoMercatorRaw;
var k: number = 512 / Math.PI; // scale
var x: number = 0;
var y: number = 0; // translate
var clipExtent: Mat2 = [[0, 0], [0, 0]];
var k = 512 / Math.PI; // scale
var x = 0;
var y = 0; // translate
var clipExtent = [[0, 0], [0, 0]];
function projection(point: Vec2) {
function projection(point) {
point = project(point[0] * Math.PI / 180, point[1] * Math.PI / 180);
return [point[0] * k + x, y - point[1] * k];
}
projection.invert = function(point: Vec2) {
projection.invert = function(point) {
point = project.invert((point[0] - x) / k, (y - point[1]) / k);
return point && [point[0] * 180 / Math.PI, point[1] * 180 / Math.PI];
};
projection.scale = function(_: number) {
projection.scale = function(_) {
if (!arguments.length) return k;
k = +_;
return projection;
};
projection.translate = function(_: Vec2) {
projection.translate = function(_) {
if (!arguments.length) return [x, y];
x = +_[0];
y = +_[1];
@@ -52,14 +49,14 @@ export function geoRawMercator() {
};
projection.clipExtent = function(_: Mat2) {
projection.clipExtent = function(_) {
if (!arguments.length) return clipExtent;
clipExtent = _;
return projection;
};
projection.transform = function(obj: Transform) {
projection.transform = function(obj) {
if (!arguments.length) return d3_zoomIdentity.translate(x, y).scale(k);
x = +obj.x;
y = +obj.y;
@@ -69,8 +66,8 @@ export function geoRawMercator() {
projection.stream = d3_geoTransform({
point: function(x: number, y: number) {
var vec: Vec2 = projection([x, y]);
point: function(x, y) {
var vec = projection([x, y]);
this.stream.point(vec[0], vec[1]);
}
}).stream;

View File

@@ -1,8 +1,5 @@
// @flow
import type { Vec2 } from '.';
// vector equals
export function geoVecEqual(a: Vec2, b: Vec2, epsilon?: number): boolean {
export function geoVecEqual(a, b, epsilon) {
if (epsilon) {
return (Math.abs(a[0] - b[0]) <= epsilon) && (Math.abs(a[1] - b[1]) <= epsilon);
} else {
@@ -11,27 +8,27 @@ export function geoVecEqual(a: Vec2, b: Vec2, epsilon?: number): boolean {
}
// vector addition
export function geoVecAdd(a: Vec2, b: Vec2): Vec2 {
export function geoVecAdd(a, b) {
return [ a[0] + b[0], a[1] + b[1] ];
}
// vector subtraction
export function geoVecSubtract(a: Vec2, b: Vec2): Vec2 {
export function geoVecSubtract(a, b) {
return [ a[0] - b[0], a[1] - b[1] ];
}
// vector scaling
export function geoVecScale(a: Vec2, mag: number): Vec2 {
export function geoVecScale(a, mag) {
return [ a[0] * mag, a[1] * mag ];
}
// vector rounding (was: geoRoundCoordinates)
export function geoVecFloor(a: Vec2): Vec2 {
export function geoVecFloor(a) {
return [ Math.floor(a[0]), Math.floor(a[1]) ];
}
// linear interpolation
export function geoVecInterp(a: Vec2, b: Vec2, t: number): Vec2 {
export function geoVecInterp(a, b, t) {
return [
a[0] + (b[0] - a[0]) * t,
a[1] + (b[1] - a[1]) * t
@@ -39,20 +36,20 @@ export function geoVecInterp(a: Vec2, b: Vec2, t: number): Vec2 {
}
// http://jsperf.com/id-dist-optimization
export function geoVecLength(a: Vec2, b: Vec2): number {
var x: number = a[0] - b[0];
var y: number = a[1] - b[1];
export function geoVecLength(a, b) {
var x = a[0] - b[0];
var y = a[1] - b[1];
return Math.sqrt((x * x) + (y * y));
}
// Return the counterclockwise angle in the range (-pi, pi)
// between the positive X axis and the line intersecting a and b.
export function geoVecAngle(a: Vec2, b: Vec2): number {
export function geoVecAngle(a, b) {
return Math.atan2(b[1] - a[1], b[0] - a[0]);
}
// dot product
export function geoVecDot(a: Vec2, b: Vec2, origin?: Vec2): number {
export function geoVecDot(a, b, origin) {
origin = origin || [0, 0];
return (a[0] - origin[0]) * (b[0] - origin[0]) +
(a[1] - origin[1]) * (b[1] - origin[1]);
@@ -61,7 +58,7 @@ export function geoVecDot(a: Vec2, b: Vec2, origin?: Vec2): number {
// 2D cross product of OA and OB vectors, returns magnitude of Z vector
// Returns a positive value, if OAB makes a counter-clockwise turn,
// negative for clockwise turn, and zero if the points are collinear.
export function geoVecCross(a: Vec2, b: Vec2, origin?: Vec2): number {
export function geoVecCross(a, b, origin) {
origin = origin || [0, 0];
return (a[0] - origin[0]) * (b[1] - origin[1]) -
(a[1] - origin[1]) * (b[0] - origin[0]);

View File

@@ -1,10 +1,9 @@
// @flow
var translations = Object.create(null);
export var currentLocale = 'en';
export var textDirection = 'ltr';
export function setLocale(_: any): void {
export function setLocale(_) {
if (translations[_] !== undefined) {
currentLocale = _;
} else if (translations[_.split('-')[0]]) {
@@ -12,34 +11,40 @@ export function setLocale(_: any): void {
}
}
export function addTranslation(id: string, value: string): void {
export function addTranslation(id, value) {
translations[id] = value;
}
/**
* Given a string identifier, try to find that string in the current
* language, and return it.
* language, and return it. This function will be called recursively
* with locale `en` if a string can not be found in the requested language.
*
* @param {string} s string identifier
* @param {string} s string identifier
* @param {object?} o object of token replacements and default string
* @param {string?} loc locale to use
* @returns {string?} locale string
*/
export function t(s: string, o: any, loc?: string): string {
export function t(s, o, loc) {
loc = loc || currentLocale;
var path = s
.split('.')
.map(function (s) {
return s.replace('<TX_DOT>', '.');
})
.map(function (s) { return s.replace('<TX_DOT>', '.'); })
.reverse();
var rep = translations[loc];
while (rep !== undefined && path.length) rep = rep[path.pop()];
while (rep !== undefined && path.length) {
rep = rep[path.pop()];
}
if (rep !== undefined) {
if (o)
for (var k in o) rep = rep.replace('{' + k + '}', o[k]);
if (o) {
for (var k in o) {
rep = rep.replace('{' + k + '}', o[k]);
}
}
return rep;
}
@@ -60,9 +65,9 @@ export function t(s: string, o: any, loc?: string): string {
/**
* Given string 'ltr' or 'rtl', save that setting
*
* @param {string} s ltr or rtl
* @param {string} dir ltr or rtl
*/
export function setTextDirection(dir: string): void {
export function setTextDirection(dir) {
textDirection = dir;
}
}

View File

@@ -1,19 +1,11 @@
// @flow
// A per-domain session mutex backed by a cookie and dead man's
// switch. If the session crashes, the mutex will auto-release
// after 5 seconds.
// This is a type alias (https://flow.org/en/docs/types/aliases/) which allows flow to understand the object returned by utilSessionMutex in other files.
type utilSessionMutexType = {
lock: () => boolean,
unlock: () => void,
locked: () => boolean
};
// This accepts a string and returns an object that complies with utilSessionMutexType
export function utilSessionMutex(name: string): utilSessionMutexType {
export function utilSessionMutex(name) {
var mutex = {};
var intervalID: ?IntervalID; // This indicates a Maybe type - intervalId can be null so we need to use "?IntervalID", not "IntervalID"
var intervalID;
function renew() {
var expires = new Date();
@@ -21,7 +13,7 @@ export function utilSessionMutex(name: string): utilSessionMutexType {
document.cookie = name + '=1; expires=' + expires.toUTCString();
}
mutex.lock = function (): boolean {
mutex.lock = function () {
if (intervalID) return true;
var cookie = document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + name + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1');
if (cookie) return false;
@@ -30,14 +22,14 @@ export function utilSessionMutex(name: string): utilSessionMutexType {
return true;
};
mutex.unlock = function (): void {
mutex.unlock = function () {
if (!intervalID) return;
document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
clearInterval(intervalID);
intervalID = null;
};
mutex.locked = function (): boolean {
mutex.locked = function () {
return !!intervalID;
};

View File

@@ -1,4 +1,3 @@
// @flow
import { t } from './locale';
import { utilDetect } from './detect';
@@ -11,31 +10,31 @@ var locale = utilDetect().locale;
* @param {Number} m area in meters
* @param {Boolean} isImperial true for U.S. customary units; false for metric
*/
export function displayLength(m: number, isImperial: boolean): string {
var d = m * (isImperial ? 3.28084 : 1),
unit;
export function displayLength(m, isImperial) {
var d = m * (isImperial ? 3.28084 : 1);
var unit;
if (isImperial) {
if (d >= 5280) {
d /= 5280;
unit = 'miles';
} else {
unit = 'feet';
}
} else {
if (d >= 1000) {
d /= 1000;
unit = 'kilometers';
} else {
unit = 'meters';
}
}
if (isImperial) {
if (d >= 5280) {
d /= 5280;
unit = 'miles';
} else {
unit = 'feet';
}
} else {
if (d >= 1000) {
d /= 1000;
unit = 'kilometers';
} else {
unit = 'meters';
}
}
return t('units.' + unit, {
quantity: d.toLocaleString(locale, {
maximumSignificantDigits: 4
})
});
return t('units.' + unit, {
quantity: d.toLocaleString(locale, {
maximumSignificantDigits: 4
})
});
}
/**
@@ -44,105 +43,105 @@ export function displayLength(m: number, isImperial: boolean): string {
* @param {Number} m2 area in square meters
* @param {Boolean} isImperial true for U.S. customary units; false for metric
*/
export function displayArea(m2: number, isImperial: boolean): string {
var d = m2 * (isImperial ? 10.7639111056 : 1),
d1, d2, area;
var unit1: string = '';
var unit2: string = '';
export function displayArea(m2, isImperial) {
var d = m2 * (isImperial ? 10.7639111056 : 1);
var d1, d2, area;
var unit1 = '';
var unit2 = '';
if (isImperial) {
if (d >= 6969600) { // > 0.25mi² show mi²
d1 = d / 27878400;
unit1 = 'square_miles';
} else {
d1 = d;
unit1 = 'square_feet';
}
if (isImperial) {
if (d >= 6969600) { // > 0.25mi² show mi²
d1 = d / 27878400;
unit1 = 'square_miles';
} else {
d1 = d;
unit1 = 'square_feet';
}
if (d > 4356 && d < 43560000) { // 0.1 - 1000 acres
d2 = d / 43560;
unit2 = 'acres';
}
if (d > 4356 && d < 43560000) { // 0.1 - 1000 acres
d2 = d / 43560;
unit2 = 'acres';
}
} else {
if (d >= 250000) { // > 0.25km² show km²
d1 = d / 1000000;
unit1 = 'square_kilometers';
} else {
d1 = d;
unit1 = 'square_meters';
}
} else {
if (d >= 250000) { // > 0.25km² show km²
d1 = d / 1000000;
unit1 = 'square_kilometers';
} else {
d1 = d;
unit1 = 'square_meters';
}
if (d > 1000 && d < 10000000) { // 0.1 - 1000 hectares
d2 = d / 10000;
unit2 = 'hectares';
}
}
if (d > 1000 && d < 10000000) { // 0.1 - 1000 hectares
d2 = d / 10000;
unit2 = 'hectares';
}
}
area = t('units.' + unit1, {
quantity: d1.toLocaleString(locale, {
maximumSignificantDigits: 4
})
});
area = t('units.' + unit1, {
quantity: d1.toLocaleString(locale, {
maximumSignificantDigits: 4
})
});
if (d2) {
return t('units.area_pair', {
area1: area,
area2: t('units.' + unit2, {
quantity: d2.toLocaleString(locale, {
maximumSignificantDigits: 2
})
})
});
} else {
return area;
}
if (d2) {
return t('units.area_pair', {
area1: area,
area2: t('units.' + unit2, {
quantity: d2.toLocaleString(locale, {
maximumSignificantDigits: 2
})
})
});
} else {
return area;
}
}
function wrap(x: number, min: number, max: number): number {
var d = max - min;
return ((x - min) % d + d) % d + min;
function wrap(x, min, max) {
var d = max - min;
return ((x - min) % d + d) % d + min;
}
function clamp(x: number, min: number, max: number): number {
return Math.max(min, Math.min(x, max));
function clamp(x, min, max) {
return Math.max(min, Math.min(x, max));
}
function displayCoordinate(deg: number, pos: any, neg: any): string {
var min = (Math.abs(deg) - Math.floor(Math.abs(deg))) * 60,
sec = (min - Math.floor(min)) * 60,
displayDegrees = t('units.arcdegrees', {
quantity: Math.floor(Math.abs(deg)).toLocaleString(locale)
}),
displayCoordinate;
function displayCoordinate(deg, pos, neg) {
var min = (Math.abs(deg) - Math.floor(Math.abs(deg))) * 60;
var sec = (min - Math.floor(min)) * 60;
var displayDegrees = t('units.arcdegrees', {
quantity: Math.floor(Math.abs(deg)).toLocaleString(locale)
});
var displayCoordinate;
if (Math.floor(sec) > 0) {
displayCoordinate = displayDegrees +
t('units.arcminutes', {
quantity: Math.floor(min).toLocaleString(locale)
}) +
t('units.arcseconds', {
quantity: Math.round(sec).toLocaleString(locale)
});
} else if (Math.floor(min) > 0) {
displayCoordinate = displayDegrees +
t('units.arcminutes', {
quantity: Math.round(min).toLocaleString(locale)
});
} else {
displayCoordinate = t('units.arcdegrees', {
quantity: Math.round(Math.abs(deg)).toLocaleString(locale)
});
}
if (Math.floor(sec) > 0) {
displayCoordinate = displayDegrees +
t('units.arcminutes', {
quantity: Math.floor(min).toLocaleString(locale)
}) +
t('units.arcseconds', {
quantity: Math.round(sec).toLocaleString(locale)
});
} else if (Math.floor(min) > 0) {
displayCoordinate = displayDegrees +
t('units.arcminutes', {
quantity: Math.round(min).toLocaleString(locale)
});
} else {
displayCoordinate = t('units.arcdegrees', {
quantity: Math.round(Math.abs(deg)).toLocaleString(locale)
});
}
if (deg === 0) {
return displayCoordinate;
} else {
return t('units.coordinate', {
coordinate: displayCoordinate,
direction: t('units.' + (deg > 0 ? pos : neg))
});
}
if (deg === 0) {
return displayCoordinate;
} else {
return t('units.coordinate', {
coordinate: displayCoordinate,
direction: t('units.' + (deg > 0 ? pos : neg))
});
}
}
/**
@@ -150,11 +149,11 @@ function displayCoordinate(deg: number, pos: any, neg: any): string {
*
* @param {Array<Number>} coord longitude and latitude
*/
export function dmsCoordinatePair(coord: number[]): string {
return t('units.coordinate_pair', {
latitude: displayCoordinate(clamp(coord[1], -90, 90), 'north', 'south'),
longitude: displayCoordinate(wrap(coord[0], -180, 180), 'east', 'west')
});
export function dmsCoordinatePair(coord) {
return t('units.coordinate_pair', {
latitude: displayCoordinate(clamp(coord[1], -90, 90), 'north', 'south'),
longitude: displayCoordinate(wrap(coord[0], -180, 180), 'east', 'west')
});
}
/**
@@ -163,9 +162,9 @@ export function dmsCoordinatePair(coord: number[]): string {
*
* @param {Array<Number>} coord longitude and latitude
*/
export function decimalCoordinatePair(coord: number[]): string {
return t('units.coordinate_pair', {
latitude: clamp(coord[1], -90, 90).toFixed(OSM_PRECISION),
longitude: wrap(coord[0], -180, 180).toFixed(OSM_PRECISION)
});
export function decimalCoordinatePair(coord) {
return t('units.coordinate_pair', {
latitude: clamp(coord[1], -90, 90).toFixed(OSM_PRECISION),
longitude: wrap(coord[0], -180, 180).toFixed(OSM_PRECISION)
});
}

View File

@@ -10,7 +10,7 @@
],
"license": "ISC",
"scripts": {
"all": "npm-run-all -s clean flow build dist",
"all": "npm-run-all -s clean build dist",
"build": "node development_server.js",
"clean": "shx rm -f dist/*.js dist/*.map dist/*.css dist/img/*.svg",
"dist": "npm-run-all -p dist:**",
@@ -18,8 +18,6 @@
"dist:min": "uglifyjs dist/iD.js -c warnings=false -m -o dist/iD.min.js",
"dist:svg:maki": "svg-sprite --symbol --symbol-dest . --symbol-sprite dist/img/maki-sprite.svg node_modules/@mapbox/maki/icons/*.svg",
"dist:svg:id": "node svg/spriteify.js --svg svg/iD-sprite.src.svg --json svg/iD-sprite.json > dist/img/iD-sprite.svg",
"flow": "flow",
"flow:coverage": "flow-coverage-report --config .flowcoverageconfig",
"imagery": "node data/update_imagery",
"lint": "eslint *.js js/id test/spec modules",
"start": "node development_server.js develop",
@@ -49,10 +47,6 @@
"ecstatic": "^3.0.0",
"editor-layer-index": "osmlab/editor-layer-index.git#gh-pages",
"eslint": "^4.3.0",
"eslint-plugin-flowtype": "^2.46.1",
"flow-bin": "^0.68.0",
"flow-coverage-report": "^0.5.0",
"flow-remove-types": "^1.2.3",
"gaze": "^1.1.1",
"glob": "^7.1.0",
"happen": "^0.3.1",