@globalfishingwatch/layer-composer
Advanced tools
Comparing version 0.3.5 to 0.4.0
@@ -11,4 +11,2 @@ "use strict"; | ||
exports.HEATMAP_COLOR_RAMPS = generators_1.HEATMAP_COLOR_RAMPS; | ||
exports.getVesselEventsGeojson = generators_1.getVesselEventsGeojson; | ||
exports.simplifyTrack = generators_1.simplifyTrack; | ||
var sort_1 = require("./sort"); | ||
@@ -15,0 +13,0 @@ exports.sort = sort_1.default; |
@@ -19,6 +19,3 @@ "use strict"; | ||
var track_1 = __importStar(require("./track/track")); | ||
var simplify_track_1 = require("./track/simplify-track"); | ||
exports.simplifyTrack = simplify_track_1.simplifyTrack; | ||
var vessel_events_1 = __importStar(require("./vessel-events/vessel-events")); | ||
exports.getVesselEventsGeojson = vessel_events_1.getVesselEventsGeojson; | ||
var TYPES = { BASEMAP: basemap_1.BASEMAP_TYPE, CARTO_POLYGONS: carto_polygons_1.CARTO_POLYGONS_TYPE, BACKGROUND: background_1.BACKGROUND_TYPE, GL: gl_1.GL_TYPE, HEATMAP: heatmap_1.HEATMAP_TYPE, TRACK: track_1.TRACK_TYPE, VESSEL_EVENTS: vessel_events_1.VESSEL_EVENTS_TYPE }; | ||
@@ -25,0 +22,0 @@ exports.TYPES = TYPES; |
"use strict"; | ||
var __assign = (this && this.__assign) || function () { | ||
__assign = Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var POS_MAX_Δ = 0.005; // 500m at equator - https://www.usna.edu/Users/oceano/pguth/md_help/html/approx_equivalents.htm | ||
var DEFAULT_POS_MAX_Δ = 0.005; // 500m at equator - https://www.usna.edu/Users/oceano/pguth/md_help/html/approx_equivalents.htm | ||
var COORD_PROPS_MAX_ΔS = { | ||
times: 600000, | ||
speeds: 1, | ||
courses: 20, | ||
// times: 600000, //10mn | ||
// times: 36000000, //10hr | ||
// speeds: 1, | ||
// courses: 20, | ||
}; | ||
@@ -40,3 +30,4 @@ var POS_ROUND = 4; | ||
}; | ||
exports.simplifyTrack = function (track) { | ||
exports.simplifyTrack = function (track, posMaxΔ) { | ||
if (posMaxΔ === void 0) { posMaxΔ = DEFAULT_POS_MAX_Δ; } | ||
var simplifiedTrack = { | ||
@@ -55,3 +46,3 @@ type: 'FeatureCollection', | ||
var simplifiedCoordProps = {}; | ||
var coordPropsKeys = Object.keys(coordProps).filter(function (key) { return COORD_PROPS_MAX_ΔS[key] !== undefined; }); | ||
var coordPropsKeys = Object.keys(coordProps); | ||
coordPropsKeys.forEach(function (key) { return (simplifiedCoordProps[key] = []); }); | ||
@@ -62,7 +53,3 @@ var lastPos; | ||
var pos = line.coordinates[i]; | ||
simplifiedGeometry.coordinates.push( | ||
// roundPos( | ||
pos | ||
// ) | ||
); | ||
simplifiedGeometry.coordinates.push(pos); | ||
lastPos = pos; | ||
@@ -72,5 +59,2 @@ coordPropsKeys.forEach(function (key) { | ||
var coordPropValue = round(coordProp, COORD_PROPS_ROUND[key]); | ||
// if (key === 'times') { | ||
// coordPropValue = compressTimestamp(coordPropValue) | ||
// } | ||
simplifiedCoordProps[key].push(coordPropValue); | ||
@@ -81,3 +65,3 @@ lastCoordinateProperties[key] = coordProp; | ||
line.coordinates.forEach(function (pos, i) { | ||
if (i === 0) { | ||
if (i === 0 || i === line.coordinates.length - 1) { | ||
addFrame(i); | ||
@@ -87,7 +71,10 @@ return; | ||
var posΔ = cheapDistance(pos, lastPos); | ||
var isPosInfMaxΔ = posΔ < POS_MAX_Δ; | ||
var isPosInfMaxΔ = posΔ < posMaxΔ; | ||
// check that every coordProp Δ is less than max Δ | ||
var isCoordPropsInfMaxΔ = coordPropsKeys.every(function (key) { | ||
var maxΔ = COORD_PROPS_MAX_ΔS[key]; | ||
if (maxΔ === undefined) { | ||
return true; | ||
} | ||
var Δ = Math.abs(coordProps[key][i] - lastCoordinateProperties[key]); | ||
var maxΔ = COORD_PROPS_MAX_ΔS[key]; | ||
return Δ < maxΔ; | ||
@@ -105,3 +92,5 @@ }); | ||
geometry: simplifiedGeometry, | ||
properties: __assign({ coordinateProperties: simplifiedCoordProps }, feature.properties), | ||
properties: { | ||
coordinateProperties: simplifiedCoordProps, | ||
}, | ||
}; | ||
@@ -108,0 +97,0 @@ simplifiedTrack.features.push(simplifiedFeature); |
@@ -6,4 +6,36 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var d3_scale_1 = require("d3-scale"); | ||
// TODO custom "augmented" GeoJSON type? | ||
// see https://github.com/yagajs/generic-geojson/blob/master/index.d.ts | ||
var filterGeoJSONByTimerange_1 = __importDefault(require("./filterGeoJSONByTimerange")); | ||
var simplify_track_1 = require("./simplify-track"); | ||
var utils_1 = require("../../utils"); | ||
exports.TRACK_TYPE = 'TRACK'; | ||
var mapZoomToMinPosΔ = function (zoomLoadLevel) { | ||
// first normalize and invert z level | ||
var normalizedZoom = d3_scale_1.scaleLinear() | ||
.clamp(true) | ||
.range([1, 0]) | ||
.domain([3, 12])(zoomLoadLevel); | ||
var MIN_POS_Δ_LOW_ZOOM = 0.1; | ||
var MIN_POS_Δ_HIGH_ZOOM = 0.0005; | ||
var DETAIL_INCREASE_RATE = 1.5; // Higher = min delta lower at intermediate zoom levels = more detail at intermediate zoom levels | ||
var minPosΔ = d3_scale_1.scalePow() | ||
.clamp(true) | ||
.exponent(DETAIL_INCREASE_RATE) | ||
.range([MIN_POS_Δ_HIGH_ZOOM, MIN_POS_Δ_LOW_ZOOM]) | ||
.domain([0, 1])(normalizedZoom); | ||
return minPosΔ; | ||
}; | ||
var simplifyTrackWithZoomLevel = function (data, zoomLoadLevel) { | ||
var s = mapZoomToMinPosΔ(zoomLoadLevel); | ||
var simplifiedData = simplify_track_1.simplifyTrack(data, s); | ||
return simplifiedData; | ||
}; | ||
var filterByTimerange = function (data, start, end) { | ||
var startMs = new Date(start).getTime(); | ||
var endMs = new Date(end).getTime(); | ||
var filteredData = filterGeoJSONByTimerange_1.default(data, startMs, endMs); | ||
return filteredData; | ||
}; | ||
var TrackGenerator = /** @class */ (function () { | ||
@@ -21,15 +53,10 @@ function TrackGenerator() { | ||
type: 'geojson', | ||
data: defaultGeoJSON, | ||
data: config.data || defaultGeoJSON, | ||
}; | ||
if (!config.data) { | ||
return [source]; | ||
if (config.zoomLoadLevel && config.simplify) { | ||
source.data = utils_1.memoizeCache[config.id].simplifyTrackWithZoomLevel(source.data, config.zoomLoadLevel); | ||
} | ||
if (!config.start || !config.end) { | ||
source.data = config.data; | ||
return [source]; | ||
if (config.start && config.end) { | ||
source.data = utils_1.memoizeCache[config.id].filterByTimerange(source.data, config.start, config.end); | ||
} | ||
var startMs = new Date(config.start).getTime(); | ||
var endMs = new Date(config.end).getTime(); | ||
var filteredData = filterGeoJSONByTimerange_1.default(config.data, startMs, endMs); | ||
source.data = filteredData; | ||
return [source]; | ||
@@ -48,2 +75,3 @@ }; | ||
this.getStyle = function (config) { | ||
utils_1.memoizeByLayerId(config.id, simplifyTrackWithZoomLevel, filterByTimerange); | ||
return { | ||
@@ -50,0 +78,0 @@ id: config.id, |
@@ -22,3 +22,11 @@ "use strict"; | ||
var basemap_layers_1 = require("../basemap/basemap-layers"); | ||
var utils_1 = require("../../utils"); | ||
exports.VESSEL_EVENTS_TYPE = 'VESSEL_EVENTS'; | ||
var EVENTS_COLORS = { | ||
encounter: '#FAE9A0', | ||
partially: '#F59E84', | ||
unmatched: '#CE2C54', | ||
loitering: '#cfa9f9', | ||
port: '#99EEFF', | ||
}; | ||
var VesselsEventsGenerator = /** @class */ (function () { | ||
@@ -58,3 +66,4 @@ function VesselsEventsGenerator() { | ||
} | ||
var newData = __assign({}, data); | ||
var geojson = utils_1.memoizeCache[config.id].getVesselEventsGeojson(data); | ||
var newData = __assign({}, geojson); | ||
if (config.currentEvent) { | ||
@@ -110,2 +119,3 @@ newData = _this._setActiveEvent(newData, config.currentEvent); | ||
this.getStyle = function (config) { | ||
utils_1.memoizeByLayerId(config.id, exports.getVesselEventsGeojson); | ||
return { | ||
@@ -121,9 +131,2 @@ id: config.id, | ||
exports.default = VesselsEventsGenerator; | ||
var EVENTS_COLORS = { | ||
encounter: '#FAE9A0', | ||
partially: '#F59E84', | ||
unmatched: '#CE2C54', | ||
loitering: '#cfa9f9', | ||
port: '#99EEFF', | ||
}; | ||
var getEncounterAuthColor = function (authorizationStatus) { | ||
@@ -130,0 +133,0 @@ switch (authorizationStatus) { |
@@ -65,2 +65,10 @@ "use strict"; | ||
}; | ||
// Compute helpers based on global config | ||
this._getGlobalConfig = function (config) { | ||
var newConfig = __assign({}, config); | ||
if (newConfig.zoom) { | ||
newConfig.zoomLoadLevel = Math.floor(newConfig.zoom); | ||
} | ||
return newConfig; | ||
}; | ||
// Uses generators to return the layer with sources and layers | ||
@@ -71,3 +79,3 @@ this._getGeneratorStyles = function (config, globalConfig) { | ||
} | ||
var finalConfig = __assign(__assign({}, globalConfig), config); | ||
var finalConfig = __assign(__assign({}, _this._getGlobalConfig(globalConfig)), config); | ||
var generator = _this.generators[finalConfig.type]; | ||
@@ -74,0 +82,0 @@ var generatorStyles = _this._applyGenericStyle(finalConfig, generator.getStyle(finalConfig)); |
@@ -24,3 +24,7 @@ "use strict"; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var memoize_one_1 = __importDefault(require("memoize-one")); | ||
exports.flatObjectArrays = function (object) { | ||
@@ -47,2 +51,18 @@ if (object === void 0) { object = {}; } | ||
}; | ||
exports.memoizeCache = {}; | ||
exports.memoizeByLayerId = function (id) { | ||
var functions = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
functions[_i - 1] = arguments[_i]; | ||
} | ||
if (exports.memoizeCache[id] === undefined) { | ||
exports.memoizeCache[id] = {}; | ||
} | ||
functions.forEach(function (fun) { | ||
if (!exports.memoizeCache[id][fun.name]) { | ||
exports.memoizeCache[id][fun.name] = memoize_one_1.default(fun); | ||
} | ||
}); | ||
return exports.memoizeCache[id]; | ||
}; | ||
//# sourceMappingURL=utils.js.map |
export { LayerComposerStyles, LayerComposerOptions, GeneratorStyles, Generator, GeneratorConfig, } from './layer-composer/types'; | ||
export { default, DEFAULT_CONFIG } from './layer-composer'; | ||
export { default as defaultGenerators, TYPES, HEATMAP_GEOM_TYPES, HEATMAP_COLOR_RAMPS, getVesselEventsGeojson, simplifyTrack, } from './layer-composer/generators'; | ||
export { default as defaultGenerators, TYPES, HEATMAP_GEOM_TYPES, HEATMAP_COLOR_RAMPS, } from './layer-composer/generators'; | ||
export { default as sort, convertLegacyGroups } from './sort'; |
@@ -7,4 +7,3 @@ import BackgroundGenerator, { BACKGROUND_TYPE as BACKGROUND } from './background/background'; | ||
import TrackGenerator, { TRACK_TYPE as TRACK } from './track/track'; | ||
import { simplifyTrack } from './track/simplify-track'; | ||
import VesselEventsGenerator, { VESSEL_EVENTS_TYPE as VESSEL_EVENTS, getVesselEventsGeojson } from './vessel-events/vessel-events'; | ||
import VesselEventsGenerator, { VESSEL_EVENTS_TYPE as VESSEL_EVENTS } from './vessel-events/vessel-events'; | ||
declare const TYPES: { | ||
@@ -21,4 +20,2 @@ BASEMAP: string; | ||
export { HEATMAP_GEOM_TYPES, HEATMAP_COLOR_RAMPS }; | ||
export { getVesselEventsGeojson }; | ||
export { simplifyTrack }; | ||
declare const _default: { | ||
@@ -25,0 +22,0 @@ [BACKGROUND]: BackgroundGenerator; |
@@ -1,2 +0,2 @@ | ||
import { FeatureCollection } from 'geojson'; | ||
export declare const simplifyTrack: (track: FeatureCollection<import("geojson").Geometry, import("geojson").GeoJsonProperties>) => FeatureCollection<import("geojson").Geometry, import("geojson").GeoJsonProperties>; | ||
import { FeatureCollection, LineString } from 'geojson'; | ||
export declare const simplifyTrack: (track: FeatureCollection<LineString, import("geojson").GeoJsonProperties>, posMaxΔ?: number) => FeatureCollection<LineString, import("geojson").GeoJsonProperties>; |
@@ -0,6 +1,7 @@ | ||
import { FeatureCollection } from 'geojson'; | ||
import { GeneratorConfig } from 'layer-composer/types'; | ||
import { FeatureCollection } from 'geojson'; | ||
export declare const TRACK_TYPE = "TRACK"; | ||
export interface TrackGeneratorConfig extends GeneratorConfig { | ||
data: FeatureCollection; | ||
simplify?: boolean; | ||
color?: string; | ||
@@ -7,0 +8,0 @@ } |
@@ -11,4 +11,19 @@ /// <reference types="mapbox-gl" /> | ||
} | ||
declare type AuthorizationOptions = 'authorized' | 'partially' | 'unmatched'; | ||
declare type RawEvent = { | ||
id: string; | ||
type: string; | ||
position: { | ||
lng?: number; | ||
lon?: number; | ||
lat: number; | ||
}; | ||
start: number; | ||
encounter?: { | ||
authorized: boolean; | ||
authorizationStatus: AuthorizationOptions; | ||
}; | ||
}; | ||
export interface VesselEventsGeneratorConfig extends GeneratorConfig { | ||
data: FeatureCollection; | ||
data: RawEvent[]; | ||
currentEvent?: CurrentEvent; | ||
@@ -60,17 +75,2 @@ } | ||
export default VesselsEventsGenerator; | ||
declare type AuthorizationOptions = 'authorized' | 'partially' | 'unmatched'; | ||
declare type RawEvent = { | ||
id: string; | ||
type: string; | ||
position: { | ||
lng?: number; | ||
lon?: number; | ||
lat: number; | ||
}; | ||
start: number; | ||
encounter?: { | ||
authorized: boolean; | ||
authorizationStatus: AuthorizationOptions; | ||
}; | ||
}; | ||
export declare const getVesselEventsGeojson: (trackEvents: RawEvent[] | null) => FeatureCollection<import("geojson").Geometry, import("geojson").GeoJsonProperties>; |
@@ -26,2 +26,8 @@ /// <reference types="mapbox-gl" /> | ||
_applyGenericStyle: (generatorConfig: GeneratorConfig, generatorStyles: GeneratorStyles) => GeneratorStyles; | ||
_getGlobalConfig: (config: GlobalGeneratorConfig) => { | ||
start?: string | undefined; | ||
end?: string | undefined; | ||
zoom?: number | undefined; | ||
zoomLoadLevel?: number | undefined; | ||
}; | ||
_getGeneratorStyles: (config: GeneratorConfig, globalConfig: GlobalGeneratorConfig) => GeneratorStyles; | ||
@@ -28,0 +34,0 @@ _getStyleJson(sources?: {}, layers?: {}): { |
@@ -28,3 +28,9 @@ import { Layer, AnySourceImpl } from 'mapbox-gl'; | ||
} | ||
export interface GeneratorConfig { | ||
export interface GlobalGeneratorConfig { | ||
start?: string; | ||
end?: string; | ||
zoom?: number; | ||
zoomLoadLevel?: number; | ||
} | ||
export interface GeneratorConfig extends GlobalGeneratorConfig { | ||
id: string; | ||
@@ -34,8 +40,2 @@ type: 'BACKGROUND' | 'BASEMAP' | 'CARTO_POLYGONS' | 'GL_STYLES' | 'HEATMAP' | 'TRACK' | 'VESSEL_EVENTS' | string; | ||
opacity?: number; | ||
start?: string; | ||
end?: string; | ||
} | ||
export interface GlobalGeneratorConfig { | ||
start?: string; | ||
end?: string; | ||
} |
@@ -0,1 +1,2 @@ | ||
import { Dictionary } from 'layer-composer/types'; | ||
export declare const flatObjectArrays: (object?: any) => { | ||
@@ -5,1 +6,3 @@ [key: string]: any; | ||
export declare const flatObjectToArray: (object?: {}) => unknown[]; | ||
export declare const memoizeCache: Dictionary<Dictionary<(...args: any[]) => any>>; | ||
export declare const memoizeByLayerId: (id: string, ...functions: ((...args: any[]) => any)[]) => Dictionary<(...args: any[]) => any>; |
{ | ||
"name": "@globalfishingwatch/layer-composer", | ||
"version": "0.3.5", | ||
"version": "0.4.0", | ||
"description": "Tools to convert layer configuration to data structures needed in Mapbox GL GFW interactive maps ", | ||
@@ -49,3 +49,5 @@ "keywords": [ | ||
"@mapbox/vector-tile": "^1.3.1", | ||
"@types/d3": "^5.7.2", | ||
"@types/geojson": "^7946.0.7", | ||
"d3-scale": "2.2.2", | ||
"geojson-vt": "^3.2.1", | ||
@@ -52,0 +54,0 @@ "lodash": "^4.17.15", |
@@ -16,6 +16,4 @@ export { | ||
HEATMAP_COLOR_RAMPS, | ||
getVesselEventsGeojson, | ||
simplifyTrack, | ||
} from './layer-composer/generators' | ||
export { default as sort, convertLegacyGroups } from './sort' |
@@ -14,6 +14,4 @@ import BackgroundGenerator, { BACKGROUND_TYPE as BACKGROUND } from './background/background' | ||
import TrackGenerator, { TRACK_TYPE as TRACK } from './track/track' | ||
import { simplifyTrack } from './track/simplify-track' | ||
import VesselEventsGenerator, { | ||
VESSEL_EVENTS_TYPE as VESSEL_EVENTS, | ||
getVesselEventsGeojson, | ||
} from './vessel-events/vessel-events' | ||
@@ -26,5 +24,2 @@ | ||
export { getVesselEventsGeojson } | ||
export { simplifyTrack } | ||
export default { | ||
@@ -31,0 +26,0 @@ [BACKGROUND]: new BackgroundGenerator(), |
import { FeatureCollection, Feature, LineString, Position } from 'geojson' | ||
import { Dictionary } from '../../types' | ||
const POS_MAX_Δ = 0.005 // 500m at equator - https://www.usna.edu/Users/oceano/pguth/md_help/html/approx_equivalents.htm | ||
const DEFAULT_POS_MAX_Δ = 0.005 // 500m at equator - https://www.usna.edu/Users/oceano/pguth/md_help/html/approx_equivalents.htm | ||
const COORD_PROPS_MAX_ΔS: Dictionary<number> = { | ||
times: 600000, //10mn | ||
speeds: 1, | ||
courses: 20, | ||
// times: 600000, //10mn | ||
// times: 36000000, //10hr | ||
// speeds: 1, | ||
// courses: 20, | ||
} | ||
@@ -36,4 +37,7 @@ | ||
export const simplifyTrack = (track: FeatureCollection) => { | ||
const simplifiedTrack: FeatureCollection = { | ||
export const simplifyTrack = ( | ||
track: FeatureCollection<LineString>, | ||
posMaxΔ = DEFAULT_POS_MAX_Δ | ||
) => { | ||
const simplifiedTrack: FeatureCollection<LineString> = { | ||
type: 'FeatureCollection', | ||
@@ -52,5 +56,3 @@ features: [], | ||
const simplifiedCoordProps: Dictionary<number[]> = {} | ||
const coordPropsKeys = Object.keys(coordProps).filter( | ||
(key) => COORD_PROPS_MAX_ΔS[key] !== undefined | ||
) | ||
const coordPropsKeys = Object.keys(coordProps) | ||
coordPropsKeys.forEach((key) => (simplifiedCoordProps[key] = [])) | ||
@@ -63,7 +65,3 @@ | ||
const pos = line.coordinates[i] | ||
simplifiedGeometry.coordinates.push( | ||
// roundPos( | ||
pos | ||
// ) | ||
) | ||
simplifiedGeometry.coordinates.push(pos) | ||
lastPos = pos | ||
@@ -73,6 +71,2 @@ coordPropsKeys.forEach((key) => { | ||
const coordPropValue = round(coordProp, COORD_PROPS_ROUND[key]) | ||
// if (key === 'times') { | ||
// coordPropValue = compressTimestamp(coordPropValue) | ||
// } | ||
simplifiedCoordProps[key].push(coordPropValue) | ||
@@ -84,3 +78,3 @@ lastCoordinateProperties[key] = coordProp | ||
line.coordinates.forEach((pos, i) => { | ||
if (i === 0) { | ||
if (i === 0 || i === line.coordinates.length - 1) { | ||
addFrame(i) | ||
@@ -91,8 +85,11 @@ return | ||
const posΔ: number = cheapDistance(pos, lastPos) | ||
const isPosInfMaxΔ = posΔ < POS_MAX_Δ | ||
const isPosInfMaxΔ = posΔ < posMaxΔ | ||
// check that every coordProp Δ is less than max Δ | ||
const isCoordPropsInfMaxΔ = coordPropsKeys.every((key) => { | ||
const maxΔ = COORD_PROPS_MAX_ΔS[key] | ||
if (maxΔ === undefined) { | ||
return true | ||
} | ||
const Δ = Math.abs(coordProps[key][i] - lastCoordinateProperties[key]) | ||
const maxΔ = COORD_PROPS_MAX_ΔS[key] | ||
return Δ < maxΔ | ||
@@ -109,3 +106,3 @@ }) | ||
}) | ||
const simplifiedFeature: Feature = { | ||
const simplifiedFeature: Feature<LineString> = { | ||
type: 'Feature', | ||
@@ -115,3 +112,2 @@ geometry: simplifiedGeometry, | ||
coordinateProperties: simplifiedCoordProps, | ||
...feature.properties, | ||
}, | ||
@@ -118,0 +114,0 @@ } |
@@ -0,14 +1,55 @@ | ||
import { scaleLinear, scalePow } from 'd3-scale' | ||
import { FeatureCollection, LineString } from 'geojson' | ||
import { GeneratorConfig } from 'layer-composer/types' | ||
// TODO custom "augemented" GeoJSON type | ||
// TODO custom "augmented" GeoJSON type? | ||
// see https://github.com/yagajs/generic-geojson/blob/master/index.d.ts | ||
import { FeatureCollection } from 'geojson' | ||
import filterGeoJSONByTimerange from './filterGeoJSONByTimerange' | ||
import { simplifyTrack } from './simplify-track' | ||
import { memoizeByLayerId, memoizeCache } from '../../utils' | ||
export const TRACK_TYPE = 'TRACK' | ||
const mapZoomToMinPosΔ = (zoomLoadLevel: number) => { | ||
// first normalize and invert z level | ||
const normalizedZoom = scaleLinear() | ||
.clamp(true) | ||
.range([1, 0]) | ||
.domain([3, 12])(zoomLoadLevel) | ||
const MIN_POS_Δ_LOW_ZOOM = 0.1 | ||
const MIN_POS_Δ_HIGH_ZOOM = 0.0005 | ||
const DETAIL_INCREASE_RATE = 1.5 // Higher = min delta lower at intermediate zoom levels = more detail at intermediate zoom levels | ||
const minPosΔ = scalePow() | ||
.clamp(true) | ||
.exponent(DETAIL_INCREASE_RATE) | ||
.range([MIN_POS_Δ_HIGH_ZOOM, MIN_POS_Δ_LOW_ZOOM]) | ||
.domain([0, 1])(normalizedZoom) | ||
return minPosΔ | ||
} | ||
export interface TrackGeneratorConfig extends GeneratorConfig { | ||
data: FeatureCollection | ||
simplify?: boolean | ||
color?: string | ||
} | ||
const simplifyTrackWithZoomLevel = ( | ||
data: FeatureCollection, | ||
zoomLoadLevel: number | ||
): FeatureCollection => { | ||
const s = mapZoomToMinPosΔ(zoomLoadLevel) | ||
const simplifiedData = simplifyTrack(data as FeatureCollection<LineString>, s) | ||
return simplifiedData | ||
} | ||
const filterByTimerange = (data: FeatureCollection, start: string, end: string) => { | ||
const startMs = new Date(start).getTime() | ||
const endMs = new Date(end).getTime() | ||
const filteredData = filterGeoJSONByTimerange(data, startMs, endMs) | ||
return filteredData | ||
} | ||
class TrackGenerator { | ||
@@ -25,18 +66,16 @@ type = TRACK_TYPE | ||
type: 'geojson', | ||
data: defaultGeoJSON, | ||
data: config.data || defaultGeoJSON, | ||
} | ||
if (!config.data) { | ||
return [source] | ||
if (config.zoomLoadLevel && config.simplify) { | ||
source.data = memoizeCache[config.id].simplifyTrackWithZoomLevel( | ||
source.data, | ||
config.zoomLoadLevel | ||
) | ||
} | ||
if (!config.start || !config.end) { | ||
source.data = config.data as FeatureCollection | ||
return [source] | ||
if (config.start && config.end) { | ||
source.data = memoizeCache[config.id].filterByTimerange(source.data, config.start, config.end) | ||
} | ||
const startMs = new Date(config.start).getTime() | ||
const endMs = new Date(config.end).getTime() | ||
const filteredData = filterGeoJSONByTimerange(config.data, startMs, endMs) | ||
source.data = filteredData | ||
return [source] | ||
@@ -57,2 +96,3 @@ } | ||
getStyle = (config: TrackGeneratorConfig) => { | ||
memoizeByLayerId(config.id, simplifyTrackWithZoomLevel, filterByTimerange) | ||
return { | ||
@@ -59,0 +99,0 @@ id: config.id, |
@@ -6,2 +6,3 @@ import { GeneratorConfig } from 'layer-composer/types' | ||
import { DEFAULT_LANDMASS_COLOR } from '../basemap/basemap-layers' | ||
import { memoizeByLayerId, memoizeCache } from '../../utils' | ||
@@ -17,4 +18,29 @@ export const VESSEL_EVENTS_TYPE = 'VESSEL_EVENTS' | ||
type AuthorizationOptions = 'authorized' | 'partially' | 'unmatched' | ||
type RawEvent = { | ||
id: string | ||
type: string | ||
position: { | ||
lng?: number | ||
lon?: number | ||
lat: number | ||
} | ||
start: number | ||
encounter?: { | ||
authorized: boolean | ||
authorizationStatus: AuthorizationOptions | ||
} | ||
} | ||
const EVENTS_COLORS: Dictionary<string> = { | ||
encounter: '#FAE9A0', | ||
partially: '#F59E84', | ||
unmatched: '#CE2C54', | ||
loitering: '#cfa9f9', | ||
port: '#99EEFF', | ||
} | ||
export interface VesselEventsGeneratorConfig extends GeneratorConfig { | ||
data: FeatureCollection | ||
data: RawEvent[] | ||
currentEvent?: CurrentEvent | ||
@@ -56,3 +82,5 @@ } | ||
let newData: FeatureCollection = { ...data } | ||
const geojson = memoizeCache[config.id].getVesselEventsGeojson(data) | ||
let newData: FeatureCollection = { ...geojson } | ||
if (config.currentEvent) { | ||
@@ -115,2 +143,3 @@ newData = this._setActiveEvent(newData, config.currentEvent) | ||
getStyle = (config: VesselEventsGeneratorConfig) => { | ||
memoizeByLayerId(config.id, getVesselEventsGeojson) | ||
return { | ||
@@ -126,27 +155,2 @@ id: config.id, | ||
type AuthorizationOptions = 'authorized' | 'partially' | 'unmatched' | ||
type RawEvent = { | ||
id: string | ||
type: string | ||
position: { | ||
lng?: number | ||
lon?: number | ||
lat: number | ||
} | ||
start: number | ||
encounter?: { | ||
authorized: boolean | ||
authorizationStatus: AuthorizationOptions | ||
} | ||
} | ||
const EVENTS_COLORS: Dictionary<string> = { | ||
encounter: '#FAE9A0', | ||
partially: '#F59E84', | ||
unmatched: '#CE2C54', | ||
loitering: '#cfa9f9', | ||
port: '#99EEFF', | ||
} | ||
const getEncounterAuthColor = (authorizationStatus: AuthorizationOptions) => { | ||
@@ -153,0 +157,0 @@ switch (authorizationStatus) { |
@@ -72,2 +72,11 @@ import Generators from './generators' | ||
// Compute helpers based on global config | ||
_getGlobalConfig = (config: GlobalGeneratorConfig) => { | ||
const newConfig = { ...config } | ||
if (newConfig.zoom) { | ||
newConfig.zoomLoadLevel = Math.floor(newConfig.zoom) | ||
} | ||
return newConfig | ||
} | ||
// Uses generators to return the layer with sources and layers | ||
@@ -82,3 +91,3 @@ _getGeneratorStyles = ( | ||
const finalConfig = { | ||
...globalConfig, | ||
...this._getGlobalConfig(globalConfig), | ||
...config, | ||
@@ -85,0 +94,0 @@ } |
@@ -35,3 +35,10 @@ import { Layer, AnySourceImpl } from 'mapbox-gl' | ||
export interface GeneratorConfig { | ||
export interface GlobalGeneratorConfig { | ||
start?: string | ||
end?: string | ||
zoom?: number | ||
zoomLoadLevel?: number | ||
} | ||
export interface GeneratorConfig extends GlobalGeneratorConfig { | ||
id: string | ||
@@ -49,9 +56,2 @@ type: | ||
opacity?: number | ||
start?: string | ||
end?: string | ||
} | ||
export interface GlobalGeneratorConfig { | ||
start?: string | ||
end?: string | ||
} |
@@ -0,1 +1,4 @@ | ||
import memoizeOne from 'memoize-one' | ||
import { Dictionary } from 'layer-composer/types' | ||
export const flatObjectArrays = (object = {} as any) => { | ||
@@ -21,1 +24,14 @@ let objectParsed: { [key: string]: any } = {} | ||
Object.values(object).flatMap((layerGroup) => layerGroup) | ||
export const memoizeCache: Dictionary<Dictionary<(...args: any[]) => any>> = {} | ||
export const memoizeByLayerId = (id: string, ...functions: ((...args: any[]) => any)[]) => { | ||
if (memoizeCache[id] === undefined) { | ||
memoizeCache[id] = {} | ||
} | ||
functions.forEach((fun) => { | ||
if (!memoizeCache[id][fun.name]) { | ||
memoizeCache[id][fun.name] = memoizeOne(fun) | ||
} | ||
}) | ||
return memoizeCache[id] | ||
} |
declare module 'vt-pbf' | ||
declare module 'geojson-vt' | ||
declare module 'geojson-validation' | ||
declare module 'd3-scale' |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
2195241
145
16755
11
+ Added@types/d3@^5.7.2
+ Addedd3-scale@2.2.2
+ Added@types/d3@5.16.7(transitive)
+ Added@types/d3-array@1.2.12(transitive)
+ Added@types/d3-axis@1.0.19(transitive)
+ Added@types/d3-brush@1.1.8(transitive)
+ Added@types/d3-chord@1.0.14(transitive)
+ Added@types/d3-collection@1.0.13(transitive)
+ Added@types/d3-color@1.4.5(transitive)
+ Added@types/d3-contour@1.3.6(transitive)
+ Added@types/d3-dispatch@1.0.12(transitive)
+ Added@types/d3-drag@1.2.8(transitive)
+ Added@types/d3-dsv@1.2.8(transitive)
+ Added@types/d3-ease@1.0.13(transitive)
+ Added@types/d3-fetch@1.2.5(transitive)
+ Added@types/d3-force@1.2.7(transitive)
+ Added@types/d3-format@1.4.5(transitive)
+ Added@types/d3-geo@1.12.7(transitive)
+ Added@types/d3-hierarchy@1.1.11(transitive)
+ Added@types/d3-interpolate@1.4.5(transitive)
+ Added@types/d3-path@1.0.11(transitive)
+ Added@types/d3-polygon@1.0.10(transitive)
+ Added@types/d3-quadtree@1.0.13(transitive)
+ Added@types/d3-random@1.1.5(transitive)
+ Added@types/d3-scale@2.2.10(transitive)
+ Added@types/d3-scale-chromatic@1.5.4(transitive)
+ Added@types/d3-selection@1.4.7(transitive)
+ Added@types/d3-shape@1.3.12(transitive)
+ Added@types/d3-time@1.1.4(transitive)
+ Added@types/d3-time-format@2.3.4(transitive)
+ Added@types/d3-timer@1.0.12(transitive)
+ Added@types/d3-transition@1.3.6(transitive)
+ Added@types/d3-voronoi@1.1.12(transitive)
+ Added@types/d3-zoom@1.8.7(transitive)
+ Addedd3-array@1.2.4(transitive)
+ Addedd3-collection@1.0.7(transitive)
+ Addedd3-color@1.4.1(transitive)
+ Addedd3-format@1.4.5(transitive)
+ Addedd3-interpolate@1.4.0(transitive)
+ Addedd3-scale@2.2.2(transitive)
+ Addedd3-time@1.1.0(transitive)
+ Addedd3-time-format@2.3.0(transitive)