Path performance improvements

- Avoid intermediate objects when creating leaflet objects to reduce allocations
- Make individual path objects non-reactive
- Avoid projecting path points twice during updates
This commit is contained in:
James Lyne 2021-07-28 02:14:20 +01:00
parent 9517de0760
commit 2a216dd4e8
7 changed files with 40 additions and 57 deletions

View File

@ -14,7 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
import {LatLngExpression, Polygon, PolylineOptions, Util} from "leaflet"; import {LatLngExpression, Polygon, PolylineOptions} from "leaflet";
import {LiveAtlasPath} from "@/index";
export interface LiveAtlasPolygonOptions extends PolylineOptions { export interface LiveAtlasPolygonOptions extends PolylineOptions {
minZoom?: number; minZoom?: number;
@ -22,8 +23,9 @@ export interface LiveAtlasPolygonOptions extends PolylineOptions {
} }
export default class LiveAtlasPolygon extends Polygon { export default class LiveAtlasPolygon extends Polygon {
constructor(latlngs: LatLngExpression[] | LatLngExpression[][] | LatLngExpression[][][], options?: LiveAtlasPolygonOptions) { declare options: LiveAtlasPolygonOptions;
super(latlngs, options);
Util.setOptions(this, options); constructor(latlngs: LatLngExpression[] | LatLngExpression[][] | LatLngExpression[][][], options: LiveAtlasPath) {
super(latlngs, options.style);
} }
} }

View File

@ -14,7 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
import {LatLngExpression, Polyline, PolylineOptions, Util} from "leaflet"; import {LatLngExpression, Polyline, PolylineOptions} from "leaflet";
import {LiveAtlasPath} from "@/index";
export interface LiveAtlasPolylineOptions extends PolylineOptions { export interface LiveAtlasPolylineOptions extends PolylineOptions {
minZoom?: number; minZoom?: number;
@ -22,8 +23,11 @@ export interface LiveAtlasPolylineOptions extends PolylineOptions {
} }
export default class LiveAtlasPolyline extends Polyline { export default class LiveAtlasPolyline extends Polyline {
constructor(latlngs: LatLngExpression[] | LatLngExpression[][], options?: LiveAtlasPolylineOptions) { declare options: LiveAtlasPolylineOptions;
super(latlngs, options);
Util.setOptions(this, options); constructor(latlngs: LatLngExpression[] | LatLngExpression[][], option: LiveAtlasPath) {
super(latlngs, option.style);
this.options.minZoom = option.minZoom;
this.options.maxZoom = option.maxZoom;
} }
} }

View File

@ -27,30 +27,30 @@ export interface LiveAtlasProjectionOptions {
} }
export class LiveAtlasProjection { export class LiveAtlasProjection {
private readonly options: LiveAtlasProjectionOptions private readonly mapToWorld: [number, number, number, number, number, number, number, number, number];
private readonly worldToMap: [number, number, number, number, number, number, number, number, number];
private readonly nativeZoomLevels: number;
constructor(options: LiveAtlasProjectionOptions) { constructor(options: LiveAtlasProjectionOptions) {
this.options = { this.mapToWorld = options.mapToWorld || [0, 0, 0, 0, 0, 0, 0, 0];
mapToWorld: options.mapToWorld || [0, 0, 0, 0, 0, 0, 0, 0], this.worldToMap = options.worldToMap || [0, 0, 0, 0, 0, 0, 0, 0];
worldToMap: options.worldToMap || [0, 0, 0, 0, 0, 0, 0, 0], this.nativeZoomLevels = options.nativeZoomLevels || 1;
nativeZoomLevels: options.nativeZoomLevels || 1
}
} }
locationToLatLng(location: Coordinate): LatLng { locationToLatLng(location: Coordinate): LatLng {
const wtp = this.options.worldToMap, const wtp = this.worldToMap,
lat = wtp[3] * location.x + wtp[4] * location.y + wtp[5] * location.z, lat = wtp[3] * location.x + wtp[4] * location.y + wtp[5] * location.z,
lng = wtp[0] * location.x + wtp[1] * location.y + wtp[2] * location.z; lng = wtp[0] * location.x + wtp[1] * location.y + wtp[2] * location.z;
return new LatLng( return new LatLng(
-((128 - lat) / (1 << this.options.nativeZoomLevels)), -((128 - lat) / (1 << this.nativeZoomLevels)),
lng / (1 << this.options.nativeZoomLevels)); lng / (1 << this.nativeZoomLevels));
} }
latLngToLocation(latLng: LatLng, y: number): Coordinate { latLngToLocation(latLng: LatLng, y: number): Coordinate {
const ptw = this.options.mapToWorld, const ptw = this.mapToWorld,
lat = latLng.lng * (1 << this.options.nativeZoomLevels), lat = latLng.lng * (1 << this.nativeZoomLevels),
lon = 128 + latLng.lat * (1 << this.options.nativeZoomLevels), lon = 128 + latLng.lat * (1 << this.nativeZoomLevels),
x = ptw[0] * lat + ptw[1] * lon + ptw[2] * y, x = ptw[0] * lat + ptw[1] * lon + ptw[2] * y,
z = ptw[6] * lat + ptw[7] * lon + ptw[8] * y; z = ptw[6] * lat + ptw[7] * lon + ptw[8] * y;

View File

@ -314,7 +314,7 @@ export default class DynmapMapProvider extends MapProvider {
y: [number, number] = [area.ybottom || 0, area.ytop || 0], y: [number, number] = [area.ybottom || 0, area.ytop || 0],
z = area.z || [0, 0]; z = area.z || [0, 0];
return { return Object.seal({
style: { style: {
color: area.color || '#ff0000', color: area.color || '#ff0000',
opacity: area.opacity || 1, opacity: area.opacity || 1,
@ -329,7 +329,7 @@ export default class DynmapMapProvider extends MapProvider {
minZoom: typeof area.minzoom !== 'undefined' && area.minzoom > -1 ? area.minzoom : undefined, minZoom: typeof area.minzoom !== 'undefined' && area.minzoom > -1 ? area.minzoom : undefined,
maxZoom: typeof area.maxzoom !== 'undefined' && area.maxzoom > -1 ? area.maxzoom : undefined, maxZoom: typeof area.maxzoom !== 'undefined' && area.maxzoom > -1 ? area.maxzoom : undefined,
popupContent: area.desc || undefined, popupContent: area.desc || undefined,
}; });
} }
private static buildLines(data: any): Map<string, LiveAtlasLine> { private static buildLines(data: any): Map<string, LiveAtlasLine> {
@ -347,7 +347,7 @@ export default class DynmapMapProvider extends MapProvider {
} }
private static buildLine(line: any): LiveAtlasLine { private static buildLine(line: any): LiveAtlasLine {
return { return Object.seal({
style: { style: {
color: line.color || '#ff0000', color: line.color || '#ff0000',
opacity: line.opacity || 1, opacity: line.opacity || 1,
@ -359,7 +359,7 @@ export default class DynmapMapProvider extends MapProvider {
minZoom: typeof line.minzoom !== 'undefined' && line.minzoom > -1 ? line.minzoom : undefined, minZoom: typeof line.minzoom !== 'undefined' && line.minzoom > -1 ? line.minzoom : undefined,
maxZoom: typeof line.maxzoom !== 'undefined' && line.maxzoom > -1 ? line.maxzoom : undefined, maxZoom: typeof line.maxzoom !== 'undefined' && line.maxzoom > -1 ? line.maxzoom : undefined,
popupContent: line.desc || undefined, popupContent: line.desc || undefined,
}; });
} }
private static buildCircles(data: any): Map<string, LiveAtlasCircle> { private static buildCircles(data: any): Map<string, LiveAtlasCircle> {
@ -377,7 +377,7 @@ export default class DynmapMapProvider extends MapProvider {
} }
private static buildCircle(circle: any): LiveAtlasCircle { private static buildCircle(circle: any): LiveAtlasCircle {
return { return Object.seal({
location: { location: {
x: circle.x || 0, x: circle.x || 0,
y: circle.y || 0, y: circle.y || 0,
@ -397,7 +397,7 @@ export default class DynmapMapProvider extends MapProvider {
minZoom: typeof circle.minzoom !== 'undefined' && circle.minzoom > -1 ? circle.minzoom : undefined, minZoom: typeof circle.minzoom !== 'undefined' && circle.minzoom > -1 ? circle.minzoom : undefined,
maxZoom: typeof circle.maxzoom !== 'undefined' && circle.maxzoom > -1 ? circle.maxzoom : undefined, maxZoom: typeof circle.maxzoom !== 'undefined' && circle.maxzoom > -1 ? circle.maxzoom : undefined,
popupContent: circle.desc || undefined, popupContent: circle.desc || undefined,
}; });
} }
private buildUpdates(data: Array<any>) { private buildUpdates(data: Array<any>) {

View File

@ -25,15 +25,7 @@ import {Coordinate, LiveAtlasArea} from "@/index";
export const createArea = (options: LiveAtlasArea, converter: Function): LiveAtlasPolyline | LiveAtlasPolygon => { export const createArea = (options: LiveAtlasArea, converter: Function): LiveAtlasPolyline | LiveAtlasPolygon => {
const outline = !options.style.fillOpacity || (options.style.fillOpacity <= 0), const outline = !options.style.fillOpacity || (options.style.fillOpacity <= 0),
points = options.points.map(projectPointsMapCallback, converter) as LatLngExpression[] | LatLngExpression[][], points = options.points.map(projectPointsMapCallback, converter) as LatLngExpression[] | LatLngExpression[][],
area = outline ? new LiveAtlasPolyline(points, { area = outline ? new LiveAtlasPolyline(points, options) : new LiveAtlasPolygon(points, options);
...options.style,
minZoom: options.minZoom,
maxZoom: options.maxZoom,
}) : new LiveAtlasPolygon(points, {
...options.style,
minZoom: options.minZoom,
maxZoom: options.maxZoom,
});
if (options.label) { if (options.label) {
area.bindPopup(() => createPopup(options)); area.bindPopup(() => createPopup(options));

View File

@ -25,15 +25,7 @@ import {LiveAtlasCircle} from "@/index";
export const createCircle = (options: LiveAtlasCircle, converter: Function): LiveAtlasPolyline | LiveAtlasPolygon => { export const createCircle = (options: LiveAtlasCircle, converter: Function): LiveAtlasPolyline | LiveAtlasPolygon => {
const outline = !options.style.fillOpacity || (options.style.fillOpacity <= 0), const outline = !options.style.fillOpacity || (options.style.fillOpacity <= 0),
points = getCirclePoints(options, converter, outline), points = getCirclePoints(options, converter, outline),
circle = outline ? new LiveAtlasPolyline(points, { circle = outline ? new LiveAtlasPolyline(points, options) : new LiveAtlasPolygon(points, options);
...options.style,
minZoom: options.minZoom,
maxZoom: options.maxZoom,
}) : new LiveAtlasPolygon(points, {
...options.style,
minZoom: options.minZoom,
maxZoom: options.maxZoom,
});
if(options.label) { if(options.label) {
circle.bindPopup(() => createPopup(options)); circle.bindPopup(() => createPopup(options));
@ -43,18 +35,17 @@ export const createCircle = (options: LiveAtlasCircle, converter: Function): Liv
}; };
export const updateCircle = (circle: LiveAtlasPolyline | LiveAtlasPolygon | undefined, options: LiveAtlasCircle, converter: Function): LiveAtlasPolyline | LiveAtlasPolygon => { export const updateCircle = (circle: LiveAtlasPolyline | LiveAtlasPolygon | undefined, options: LiveAtlasCircle, converter: Function): LiveAtlasPolyline | LiveAtlasPolygon => {
const outline = (options.style && options.style.fillOpacity && (options.style.fillOpacity <= 0)) as boolean,
points = getCirclePoints(options, converter, outline);
if (!circle) { if (!circle) {
return createCircle(options, converter); return createCircle(options, converter);
} }
const outline = (options.style && options.style.fillOpacity && (options.style.fillOpacity <= 0)) as boolean;
circle.closePopup(); circle.closePopup();
circle.unbindPopup(); circle.unbindPopup();
circle.bindPopup(() => createPopup(options)); circle.bindPopup(() => createPopup(options));
circle.setStyle(options.style); circle.setStyle(options.style);
circle.setLatLngs(points); circle.setLatLngs(getCirclePoints(options, converter, outline));
circle.redraw(); circle.redraw();
return circle; return circle;

View File

@ -22,12 +22,8 @@ import {Coordinate, LiveAtlasLine} from "@/index";
import {LatLngExpression} from "leaflet"; import {LatLngExpression} from "leaflet";
export const createLine = (options: LiveAtlasLine, converter: Function): LiveAtlasPolyline => { export const createLine = (options: LiveAtlasLine, converter: Function): LiveAtlasPolyline => {
const points = options.points.map(projectPointsMapCallback, converter) as LatLngExpression[], const points = options.points.map(projectPointsMapCallback, converter),
line = new LiveAtlasPolyline(points, { line = new LiveAtlasPolyline(points, options);
...options.style,
minZoom: options.minZoom,
maxZoom: options.maxZoom,
});
if(options.label) { if(options.label) {
line.bindPopup(() => createPopup(options)); line.bindPopup(() => createPopup(options));
@ -37,8 +33,6 @@ export const createLine = (options: LiveAtlasLine, converter: Function): LiveAtl
}; };
export const updateLine = (line: LiveAtlasPolyline | undefined, options: LiveAtlasLine, converter: Function): LiveAtlasPolyline => { export const updateLine = (line: LiveAtlasPolyline | undefined, options: LiveAtlasLine, converter: Function): LiveAtlasPolyline => {
const points = options.points.map(projectPointsMapCallback, converter);
if (!line) { if (!line) {
return createLine(options, converter); return createLine(options, converter);
} }
@ -47,7 +41,7 @@ export const updateLine = (line: LiveAtlasPolyline | undefined, options: LiveAtl
line.unbindPopup(); line.unbindPopup();
line.bindPopup(() => createPopup(options)); line.bindPopup(() => createPopup(options));
line.setStyle(options.style); line.setStyle(options.style);
line.setLatLngs(points); line.setLatLngs(options.points.map(projectPointsMapCallback, converter));
line.redraw(); line.redraw();
return line; return line;