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

View File

@ -14,7 +14,8 @@
* 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 {
minZoom?: number;
@ -22,8 +23,11 @@ export interface LiveAtlasPolylineOptions extends PolylineOptions {
}
export default class LiveAtlasPolyline extends Polyline {
constructor(latlngs: LatLngExpression[] | LatLngExpression[][], options?: LiveAtlasPolylineOptions) {
super(latlngs, options);
Util.setOptions(this, options);
declare options: LiveAtlasPolylineOptions;
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 {
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) {
this.options = {
mapToWorld: options.mapToWorld || [0, 0, 0, 0, 0, 0, 0, 0],
worldToMap: options.worldToMap || [0, 0, 0, 0, 0, 0, 0, 0],
nativeZoomLevels: options.nativeZoomLevels || 1
}
this.mapToWorld = options.mapToWorld || [0, 0, 0, 0, 0, 0, 0, 0];
this.worldToMap = options.worldToMap || [0, 0, 0, 0, 0, 0, 0, 0];
this.nativeZoomLevels = options.nativeZoomLevels || 1;
}
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,
lng = wtp[0] * location.x + wtp[1] * location.y + wtp[2] * location.z;
return new LatLng(
-((128 - lat) / (1 << this.options.nativeZoomLevels)),
lng / (1 << this.options.nativeZoomLevels));
-((128 - lat) / (1 << this.nativeZoomLevels)),
lng / (1 << this.nativeZoomLevels));
}
latLngToLocation(latLng: LatLng, y: number): Coordinate {
const ptw = this.options.mapToWorld,
lat = latLng.lng * (1 << this.options.nativeZoomLevels),
lon = 128 + latLng.lat * (1 << this.options.nativeZoomLevels),
const ptw = this.mapToWorld,
lat = latLng.lng * (1 << this.nativeZoomLevels),
lon = 128 + latLng.lat * (1 << this.nativeZoomLevels),
x = ptw[0] * lat + ptw[1] * lon + ptw[2] * 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],
z = area.z || [0, 0];
return {
return Object.seal({
style: {
color: area.color || '#ff0000',
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,
maxZoom: typeof area.maxzoom !== 'undefined' && area.maxzoom > -1 ? area.maxzoom : undefined,
popupContent: area.desc || undefined,
};
});
}
private static buildLines(data: any): Map<string, LiveAtlasLine> {
@ -347,7 +347,7 @@ export default class DynmapMapProvider extends MapProvider {
}
private static buildLine(line: any): LiveAtlasLine {
return {
return Object.seal({
style: {
color: line.color || '#ff0000',
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,
maxZoom: typeof line.maxzoom !== 'undefined' && line.maxzoom > -1 ? line.maxzoom : undefined,
popupContent: line.desc || undefined,
};
});
}
private static buildCircles(data: any): Map<string, LiveAtlasCircle> {
@ -377,7 +377,7 @@ export default class DynmapMapProvider extends MapProvider {
}
private static buildCircle(circle: any): LiveAtlasCircle {
return {
return Object.seal({
location: {
x: circle.x || 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,
maxZoom: typeof circle.maxzoom !== 'undefined' && circle.maxzoom > -1 ? circle.maxzoom : undefined,
popupContent: circle.desc || undefined,
};
});
}
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 => {
const outline = !options.style.fillOpacity || (options.style.fillOpacity <= 0),
points = options.points.map(projectPointsMapCallback, converter) as LatLngExpression[] | LatLngExpression[][],
area = outline ? new LiveAtlasPolyline(points, {
...options.style,
minZoom: options.minZoom,
maxZoom: options.maxZoom,
}) : new LiveAtlasPolygon(points, {
...options.style,
minZoom: options.minZoom,
maxZoom: options.maxZoom,
});
area = outline ? new LiveAtlasPolyline(points, options) : new LiveAtlasPolygon(points, options);
if (options.label) {
area.bindPopup(() => createPopup(options));

View File

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

View File

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