Browse Source

UI: Maps - performance improvements and minor fixes.

pull/12866/head
Igor Kulikov 2 years ago
parent
commit
c78509c7c4
  1. 73
      ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/trips-data-layer.ts
  2. 46
      ui-ngx/src/app/modules/home/components/widget/lib/maps/map.ts
  3. 6
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/data-layer-pattern-settings.component.ts
  4. 9
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-dialog.component.html
  5. 1
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-dialog.component.ts

73
ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/trips-data-layer.ts

@ -44,6 +44,11 @@ import { MarkerDataProcessor } from '@home/components/widget/lib/maps/data-layer
type TripRouteData = {[time: number]: FormattedData<TbMapDatasource>};
interface PointItem {
point: L.CircleMarker;
tooltip?: L.Popup;
}
class TbTripDataItem extends TbDataLayerItem<TripsDataLayerSettings, TbTripsDataLayer, L.FeatureGroup> {
private tripRouteData: TripRouteData;
@ -54,7 +59,8 @@ class TbTripDataItem extends TbDataLayerItem<TripsDataLayerSettings, TbTripsData
private polyline: L.Polyline;
private polylineDecorator: L.PolylineDecorator;
private points: L.FeatureGroup;
private pointsContainer: L.FeatureGroup;
private points = new Map<string, PointItem>();
private currentTime: number;
private currentPositionData: FormattedData<TbMapDatasource>;
@ -94,7 +100,7 @@ class TbTripDataItem extends TbDataLayerItem<TripsDataLayerSettings, TbTripsData
public updateAppearance() {
this.updatePathAppearance();
const dsData = this.dataLayer.getMap().getData();
if (this.settings.tooltip.show) {
if (this.settings.showMarker && this.settings.tooltip?.show) {
updateTooltip(this.dataLayer.getMap(), this.markerTooltip,
this.settings.tooltip, this.dataLayer.dataLayerTooltipProcessor, this.pointData, dsData);
}
@ -120,6 +126,12 @@ class TbTripDataItem extends TbDataLayerItem<TripsDataLayerSettings, TbTripsData
}
public remove() {
if (this.marker) {
this.marker.off();
}
this.points.forEach(pointItem => {
pointItem.point.off();
});
this.dataLayer.getDataLayerContainer().removeLayer(this.layer);
this.layer.off();
}
@ -216,34 +228,61 @@ class TbTripDataItem extends TbDataLayerItem<TripsDataLayerSettings, TbTripsData
private updatePoints() {
if (this.settings.showPoints) {
if (!this.points) {
this.points = L.featureGroup();
this.points.addTo(this.layer);
if (!this.pointsContainer) {
this.pointsContainer = L.featureGroup();
this.pointsContainer.addTo(this.layer);
}
this.points.clearLayers();
const formattedRouteData = _.values(this.tripRouteData);
const dsData = this.dataLayer.getMap().getData();
const pointsList = formattedRouteData.filter(data => !!this.dataLayer.dataProcessor.extractLocationData(data));
for (const pData of pointsList) {
let pointData = pData;
const pointsData = formattedRouteData.map(data => ({
location: this.dataLayer.dataProcessor.extractLocation(data, dsData),
data
})).filter(pData => !!pData.location);
const toDelete = new Set(Array.from(this.points.keys()));
for (const pData of pointsData) {
let pointData = pData.data;
if (this.latestData) {
pointData = {...pointData, ...this.latestData};
}
const pointLocation = pData.location;
const pointColor = this.dataLayer.pointColorProcessor.processColor(pointData, dsData);
const point = L.circleMarker(this.dataLayer.dataProcessor.extractLocation(pointData, dsData), {
const pointStyle = {
stroke: false,
fillOpacity: 1,
fillColor: pointColor,
radius: this.settings.pointSize
});
if (this.settings.pointTooltip?.show) {
const pointTooltip = createTooltip(this.dataLayer.getMap(),
point, this.settings.pointTooltip, pointData, () => true);
updateTooltip(this.dataLayer.getMap(), pointTooltip,
this.settings.pointTooltip, this.dataLayer.pointTooltipProcessor, pointData, dsData);
};
const pointKey = `${pointLocation.lat}_${pointLocation.lng}`;
let pointItem = this.points.get(pointKey);
if (pointItem) {
pointItem.point.setStyle(pointStyle);
if (this.settings.pointTooltip?.show) {
updateTooltip(this.dataLayer.getMap(), pointItem.tooltip,
this.settings.pointTooltip, this.dataLayer.pointTooltipProcessor, pointData, dsData);
}
} else {
pointItem = {
point: L.circleMarker(pointLocation, pointStyle)
};
pointItem.point.addTo(this.pointsContainer);
if (this.settings.pointTooltip?.show) {
pointItem.tooltip = createTooltip(this.dataLayer.getMap(),
pointItem.point, this.settings.pointTooltip, pointData, () => true);
updateTooltip(this.dataLayer.getMap(), pointItem.tooltip,
this.settings.pointTooltip, this.dataLayer.pointTooltipProcessor, pointData, dsData);
}
this.points.set(pointKey, pointItem);
}
this.points.addLayer(point);
toDelete.delete(pointKey);
}
toDelete.forEach(pointKey => {
const pointItem = this.points.get(pointKey);
if (pointItem) {
this.pointsContainer.removeLayer(pointItem.point);
pointItem.point.off();
this.points.delete(pointKey);
}
});
}
}

46
ui-ngx/src/app/modules/home/components/widget/lib/maps/map.ts

@ -175,6 +175,25 @@ export abstract class TbMap<S extends BaseMapSettings> {
this.map.zoomControl.setPosition(this.settings.controlsPosition);
}
this.dragMode = !this.settings.dragModeButton;
const tripsWithMarkers = this.settings.trips?.length ? this.settings.trips.filter(trip => trip.showMarker) : [];
const showTimeline = this.settings.tripTimeline?.showTimelineControl && tripsWithMarkers.length;
if (showTimeline) {
this.timeline = true;
this.timeStep = this.settings.tripTimeline.timeStep;
this.timeLineComponentRef = this.ctx.widgetContentContainer.createComponent(MapTimelinePanelComponent);
this.timeLineComponent = this.timeLineComponentRef.instance;
this.timeLineComponent.settings = this.settings.tripTimeline;
this.timeLineComponent.timeChanged.subscribe((time) => {
this.currentTime = time;
this.updateTripsTime();
});
const parentElement = this.timeLineComponentRef.instance.element.nativeElement;
const content = parentElement.firstChild;
parentElement.removeChild(content);
parentElement.style.display = 'none';
this.containerElement.append(content);
}
const setup = [this.doSetupControls()];
if (this.timeline && this.settings.tripTimeline.snapToRealLocation) {
setup.push(parseTbFunction<MapBooleanFunction>(this.getCtx().http, this.settings.tripTimeline.locationSnapFilter, ['data', 'dsData']).pipe(
@ -269,7 +288,7 @@ export abstract class TbMap<S extends BaseMapSettings> {
buttonTitle: this.ctx.translate.instant('widgets.maps.data-layer.groups'),
}).addTo(this.map);
this.map.on('layergroupchange', () => {
this.updateBounds();
this.updateBounds(true);
});
}
const setup = this.dataLayers.map(dl => dl.setup());
@ -322,6 +341,7 @@ export abstract class TbMap<S extends BaseMapSettings> {
const tripDataLayersSubscriptionOptions: WidgetSubscriptionOptions = {
datasources: tripDatasources,
hasDataPageLink: true,
ignoreDataUpdateOnIntervalTick: true,
useDashboardTimewindow: isDefined(this.ctx.widgetConfig.useDashboardTimewindow)
? this.ctx.widgetConfig.useDashboardTimewindow : true,
type: widgetType.timeseries,
@ -364,26 +384,6 @@ export abstract class TbMap<S extends BaseMapSettings> {
private setupEditMode() {
const tripsWithMarkers = this.tripDataLayers.filter(dl => dl.showMarker());
const showTimeline = this.settings.tripTimeline?.showTimelineControl && tripsWithMarkers.length;
if (showTimeline) {
this.timeline = true;
this.timeStep = this.settings.tripTimeline.timeStep;
this.timeLineComponentRef = this.ctx.widgetContentContainer.createComponent(MapTimelinePanelComponent);
this.timeLineComponent = this.timeLineComponentRef.instance;
this.timeLineComponent.settings = this.settings.tripTimeline;
this.timeLineComponent.timeChanged.subscribe((time) => {
this.currentTime = time;
this.updateTripsTime();
});
const parentElement = this.timeLineComponentRef.instance.element.nativeElement;
const content = parentElement.firstChild;
parentElement.removeChild(content);
parentElement.style.display = 'none';
this.containerElement.append(content);
}
this.editToolbar = L.TB.bottomToolbar({
mapElement: $(this.mapElement),
closeTitle: this.ctx.translate.instant('action.cancel'),
@ -919,7 +919,7 @@ export abstract class TbMap<S extends BaseMapSettings> {
this.currentPopover?.updatePosition();
}
private updateBounds() {
private updateBounds(force = false) {
const enabledDataLayers = this.dataLayers.filter(dl => dl.isEnabled());
const dataLayersBounds = enabledDataLayers.map(dl => dl.getBounds()).filter(b => b.isValid());
let bounds: L.LatLngBounds;
@ -927,7 +927,7 @@ export abstract class TbMap<S extends BaseMapSettings> {
bounds = new L.LatLngBounds(null, null);
dataLayersBounds.forEach(b => bounds.extend(b));
const mapBounds = this.map.getBounds();
if (bounds.isValid() && (!this.bounds || !this.bounds.isValid() || !this.bounds.equals(bounds) && this.settings.fitMapBounds && !mapBounds.contains(bounds))) {
if (bounds.isValid() && (!this.bounds || !this.bounds.isValid() || (!this.bounds.equals(bounds) || force) && this.settings.fitMapBounds && !mapBounds.contains(bounds))) {
this.bounds = bounds;
if (!this.ignoreUpdateBounds && !this.isPlacingItem) {
this.fitBounds(bounds);

6
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/data-layer-pattern-settings.component.ts

@ -81,6 +81,10 @@ export class DataLayerPatternSettingsComponent implements OnInit, ControlValueAc
@coerceBoolean()
hasTooltipOffset = false;
@Input()
@coerceBoolean()
expand = true;
@Input()
context: MapSettingsContext;
@ -149,7 +153,7 @@ export class DataLayerPatternSettingsComponent implements OnInit, ControlValueAc
value, {emitEvent: false}
);
this.updateValidators();
this.settingsExpanded = this.patternSettingsFormGroup.get('show').value;
this.settingsExpanded = this.patternSettingsFormGroup.get('show').value && this.expand;
this.patternSettingsFormGroup.get('show').valueChanges.pipe(
takeUntilDestroyed(this.destroyRef)
).subscribe((show) => {

9
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-dialog.component.html

@ -238,7 +238,7 @@
</div>
</div>
@if (dataLayerType === 'trips') {
<ng-container *ngTemplateOutlet="dataLayerLabelAndTooltip"></ng-container>
<ng-container *ngTemplateOutlet="dataLayerLabelAndTooltip; context: {expand: false}"></ng-container>
<ng-container *ngTemplateOutlet="behavior; context: {stroked: true}"></ng-container>
}
</ng-template>
@ -360,6 +360,7 @@
patternType="tooltip"
patternTitle="{{ 'widgets.maps.data-layer.points.point-tooltip' | translate }}"
[context]="context"
[expand]="false"
helpId="widget/lib/map/path_point_tooltip_fn"
formControlName="pointTooltip">
</tb-data-layer-pattern-settings>
@ -384,7 +385,7 @@
</div>
</ng-container>
@if (dataLayerType !== 'trips') {
<ng-container *ngTemplateOutlet="dataLayerLabelAndTooltip"></ng-container>
<ng-container *ngTemplateOutlet="dataLayerLabelAndTooltip; context: {expand: true}"></ng-container>
}
</div>
@if (dataLayerType !== 'trips') {
@ -436,18 +437,20 @@
</div>
</form>
<ng-template #dataLayerLabelAndTooltip>
<ng-template #dataLayerLabelAndTooltip let-expand='expand'>
<ng-container [formGroup]="dataLayerFormGroup">
<tb-data-layer-pattern-settings
patternType="label"
[context]="context"
[helpId]="labelHelpId"
[expand]="expand"
formControlName="label">
</tb-data-layer-pattern-settings>
<tb-data-layer-pattern-settings
patternType="tooltip"
[context]="context"
[helpId]="tooltipHelpId"
[expand]="expand"
[hasTooltipOffset]="['trips', 'markers'].includes(dataLayerType)"
formControlName="tooltip">
</tb-data-layer-pattern-settings>

1
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-dialog.component.ts

@ -428,6 +428,7 @@ export class MapDataLayerDialogComponent extends DialogComponent<MapDataLayerDia
(updatedDataKey) => {
if (updatedDataKey) {
this.dataLayerFormGroup.get(keyType).patchValue(updatedDataKey);
this.dataLayerFormGroup.markAsDirty();
}
}
);

Loading…
Cancel
Save