Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sourcedata switch layer #153

Merged
merged 8 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions erdblick_app/app/highlight.pipe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export class HighlightSearch implements PipeTransform {
return value;
}

let re = new RegExp(String(args).replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi');
const re = new RegExp(String(args).replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi');
return String(value).replace(re, '<mark>$&</mark>');
}
}
}
6 changes: 2 additions & 4 deletions erdblick_app/app/inspection.panel.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ interface InspectorTab {
}`,
]
})
export class InspectionPanelComponent implements OnInit
export class InspectionPanelComponent
{
title = "";
tabs: InspectorTab[] = [];
Expand Down Expand Up @@ -86,8 +86,6 @@ export class InspectionPanelComponent implements OnInit
})
}

ngOnInit(): void {}

reset() {
/* We always keep the first tab, which is a feature inspector. */
this.setTab(0);
Expand Down Expand Up @@ -117,7 +115,7 @@ export class InspectionPanelComponent implements OnInit

pushSourceDataInspector(data: SelectedSourceData) {
let tab = {
title: data.layerId,
title: SourceDataPanelComponent.layerNameForLayerId(data.layerId),
icon: "pi-database",
component: SourceDataPanelComponent,
inputs: {
Expand Down
19 changes: 8 additions & 11 deletions erdblick_app/app/inspection.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export interface SelectedSourceData {
export function selectedSourceDataEqualTo(a: SelectedSourceData | null, b: SelectedSourceData | null) {
if (!a || !b)
return false;
return (a == b || (a.mapId == b.mapId && a.tileId == b.tileId && a.layerId == b.layerId && a.address == b.address && a.featureId == b.featureId));
return (a === b || (a.mapId === b.mapId && a.tileId === b.tileId && a.layerId === b.layerId && a.address === b.address && a.featureId === b.featureId));
}

@Injectable({providedIn: 'root'})
Expand Down Expand Up @@ -174,16 +174,13 @@ export class InspectionService {
async loadSourceDataLayer(tileId: number, layerId: string, mapId: string) : Promise<TileSourceDataLayer> {
console.log(`Loading SourceDataLayer layerId=${layerId} tileId=${tileId}`);

let requests = [{
mapId: mapId,
layerId: layerId,
tileIds: [tileId]
}];

let tileParser = new coreLib.TileLayerParser();

let newRequestBody = JSON.stringify({
requests: requests
const tileParser = new coreLib.TileLayerParser();
const newRequestBody = JSON.stringify({
requests: [{
mapId: mapId,
layerId: layerId,
tileIds: [tileId]
}]
});

let layer: TileSourceDataLayer | undefined;
Expand Down
70 changes: 36 additions & 34 deletions erdblick_app/app/map.panel.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,41 +39,43 @@ import {Menu} from "primeng/menu";
<span class="font-bold white-space-nowrap map-header">
{{ mapItem.key }}
</span>
<div *ngFor="let mapLayer of mapItem.value.layers | keyvalue: unordered" class="flex-container">
<div class="font-bold white-space-nowrap"
style="margin-left: 0.5em; display: flex; align-items: center;">
<span class="material-icons" style="font-size: 1.5em; cursor: pointer"
(click)="showLayersToggleMenu($event, mapItem.key, mapLayer.key)">more_vert</span>
<span>
<p-checkbox [(ngModel)]="mapLayer.value.visible"
(ngModelChange)="toggleLayer(mapItem.key, mapLayer.key)"
[label]="mapLayer.key" [binary]="true"/>
</span>
</div>
<div class="layer-controls">
<p-button (click)="toggleTileBorders(mapItem.key, mapLayer.key)"
label="" pTooltip="Toggle tile borders" tooltipPosition="bottom"
[style]="{'padding-left': '0', 'padding-right': '0'}">
<span class="material-icons"
style="font-size: 1.2em; margin: 0 auto;">{{ mapLayer.value.tileBorders ? 'select_all' : 'deselect' }}</span>
</p-button>
<p-button *ngIf="mapLayer.value.coverage.length"
(click)="focus(mapLayer.value.coverage[0], $event)"
label="" pTooltip="Focus on layer" tooltipPosition="bottom"
[style]="{'padding-left': '0', 'padding-right': '0'}">
<span class="material-icons" style="font-size: 1.2em; margin: 0 auto;">loupe</span>
</p-button>
<p-inputNumber [(ngModel)]="mapLayer.value.level"
(ngModelChange)="onLayerLevelChanged($event, mapItem.key, mapLayer.key)"
[showButtons]="true" [min]="0" [max]="15"
buttonLayout="horizontal" spinnerMode="horizontal" inputId="horizontal"
decrementButtonClass="p-button-secondary"
incrementButtonClass="p-button-secondary"
incrementButtonIcon="pi pi-plus" decrementButtonIcon="pi pi-minus"
pTooltip="Change zoom level" tooltipPosition="bottom">
</p-inputNumber>
<div *ngFor="let mapLayer of mapItem.value.layers | keyvalue: unordered">
<div *ngIf="mapLayer.value.type != 'SourceData'" class="flex-container">
<div class="font-bold white-space-nowrap"
style="margin-left: 0.5em; display: flex; align-items: center;">
<span class="material-icons" style="font-size: 1.5em; cursor: pointer"
(click)="showLayersToggleMenu($event, mapItem.key, mapLayer.key)">more_vert</span>
<span>
<p-checkbox [(ngModel)]="mapLayer.value.visible"
(ngModelChange)="toggleLayer(mapItem.key, mapLayer.key)"
[label]="mapLayer.key" [binary]="true"/>
</span>
</div>
<div class="layer-controls">
<p-button (click)="toggleTileBorders(mapItem.key, mapLayer.key)"
label="" pTooltip="Toggle tile borders" tooltipPosition="bottom"
[style]="{'padding-left': '0', 'padding-right': '0'}">
<span class="material-icons"
style="font-size: 1.2em; margin: 0 auto;">{{ mapLayer.value.tileBorders ? 'select_all' : 'deselect' }}</span>
</p-button>
<p-button *ngIf="mapLayer.value.coverage.length"
(click)="focus(mapLayer.value.coverage[0], $event)"
label="" pTooltip="Focus on layer" tooltipPosition="bottom"
[style]="{'padding-left': '0', 'padding-right': '0'}">
<span class="material-icons" style="font-size: 1.2em; margin: 0 auto;">loupe</span>
</p-button>
<p-inputNumber [(ngModel)]="mapLayer.value.level"
(ngModelChange)="onLayerLevelChanged($event, mapItem.key, mapLayer.key)"
[showButtons]="true" [min]="0" [max]="15"
buttonLayout="horizontal" spinnerMode="horizontal" inputId="horizontal"
decrementButtonClass="p-button-secondary"
incrementButtonClass="p-button-secondary"
incrementButtonIcon="pi pi-plus" decrementButtonIcon="pi pi-minus"
pTooltip="Change zoom level" tooltipPosition="bottom">
</p-inputNumber>
</div>
<input class="level-indicator" type="text" pInputText [disabled]="true" [(ngModel)]="mapLayer.value.level" />
</div>
<input class="level-indicator" type="text" pInputText [disabled]="true" [(ngModel)]="mapLayer.value.level" />
</div>
</div>
</div>
Expand Down
8 changes: 2 additions & 6 deletions erdblick_app/app/map.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export interface LayerInfoItem extends Object {
coverage: Array<number|CoverageRectItem>;
featureTypes: Array<{name: string, uniqueIdCompositions: Array<Object>}>;
layerId: string;
type: number;
type: string;
version: {major: number, minor: number, patch: number};
zoomLevels: Array<number>;
level: number;
Expand Down Expand Up @@ -265,10 +265,6 @@ export class MapService {
let maps = new Map<string, MapInfoItem>(result.filter(m => !m.addOn).map(mapInfo => {
let layers = new Map<string, LayerInfoItem>();
for (let [layerId, layerInfo] of Object.entries(mapInfo.layers)) {
// Filter out source-data layers
if (layerId.startsWith("SourceData-"))
continue;

[layerInfo.visible, layerInfo.level, layerInfo.tileBorders] = this.parameterService.mapLayerConfig(mapInfo.mapId, layerId, 13);
mapLayerLevels.push([
mapInfo.mapId + '/' + layerId,
Expand Down Expand Up @@ -299,7 +295,7 @@ export class MapService {

const layer = mapItem.layers.get(layerId);
if (layer) {
if (layer.type == coreLib.LayerType.SOURCEDATA.value)
if (layer.type == "SourceData")
return false;
return layer.visible;
}
Expand Down
2 changes: 1 addition & 1 deletion erdblick_app/app/parameters.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ export class ParametersService {
}
});

constructor(public router: Router /*, private inspectionService: InspectionService*/) {
constructor(public router: Router) {
let parameters = this.loadSavedParameters();
this.parameters = new BehaviorSubject<ErdblickParameters>(parameters!);
this.saveParameters();
Expand Down
98 changes: 71 additions & 27 deletions erdblick_app/app/sourcedata.panel.component.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import {Component, OnInit, Input, ViewChild} from "@angular/core";
import {TreeTableNode} from "primeng/api";
import {InspectionService, SelectedSourceData} from "./inspection.service";
import {MapService} from "./map.service";
import {coreLib} from "./wasm";
import {SourceDataAddressFormat} from "build/libs/core/erdblick-core";
import {TreeTable} from "primeng/treetable";
import {Menu} from "primeng/menu";

@Component({
selector: 'sourcedata-panel',
Expand Down Expand Up @@ -39,6 +41,7 @@ import {TreeTable} from "primeng/treetable";
/>
<i *ngIf="filterString" (click)="clearFilter()"
class="pi pi-times clear-icon" style="cursor: pointer"></i>
<p-button icon="pi pi-ellipsis-v" tooltip="Select Layer" (click)="layerMenuItemsMenu.toggle($event)" />
</div>
</ng-template>

Expand Down Expand Up @@ -77,39 +80,54 @@ import {TreeTable} from "primeng/treetable";
</div>
</div>
</ng-template>

<p-menu #layerMenuItemsMenu [model]="layerMenuItems" [popup]="true" appendTo="body" [style]="{'width': 'auto'}" />
`
})
export class SourceDataPanelComponent implements OnInit {
@Input()
sourceData!: SelectedSourceData;
@Input() sourceData!: SelectedSourceData;

@ViewChild('tt')
table!: TreeTable;
@ViewChild('tt') table!: TreeTable;
@ViewChild('layerMenuItemsMenu') layerListMenu!: Menu;

treeData: TreeTableNode[] = [];
filterFields = [
"key",
"value"
];
columns = [
{ key: "key", header: "Key", width: '180px', transform: (v: any) => v },
{ key: "key", header: "Key", width: '0*', transform: (v: any) => v },
{ key: "value", header: "Value", width: '0*', transform: (v: any) => v },
{ key: "address", header: "Address", width: '80px', transform: this.addressFormatter },
{ key: "address", header: "Address", width: '100px', transform: this.addressFormatter },
{ key: "type", header: "Type", width: 'auto', transform: this.schemaTypeURLFormatter },
]

loading: boolean = true;
filterString = "";
addressFormat: SourceDataAddressFormat = coreLib.SourceDataAddressFormat.BIT_RANGE;
errorMessage = "";
isExpanded = false;
filterString = "";

constructor(private inspectionService: InspectionService) {}
layerMenuItems: any[] = [];

/**
* Returns a human readable layer name for a layer id.
*
* @param layerId Layer id to get the name for
*/
public static layerNameForLayerId(layerId: string) {
const match = layerId.match(/^SourceData-([^.]+\.)*(.*)-([\d]+)/);
if (match)
return `${match[2]}.${match[3]}`;
return layerId;
}

constructor(private inspectionService: InspectionService, public mapService: MapService) {}

ngOnInit(): void {
this.inspectionService.loadSourceDataLayer(this.sourceData.tileId, this.sourceData.layerId, this.sourceData.mapId)
.then(layer => {
let root = layer.toObject()
const root = layer.toObject()
this.addressFormat = layer.addressFormat();

layer.delete();
Expand All @@ -128,6 +146,34 @@ export class SourceDataPanelComponent implements OnInit {
.finally(() => {
this.loading = false;
});

this.mapService.maps.subscribe(maps => {
const map = maps.get(this.sourceData.mapId);
if (map) {
this.layerMenuItems = [
{
label: "Switch Layer",
items: Array.from(map.layers.values())
.filter(item => item.type == "SourceData")
.map(item => {
return {
label: SourceDataPanelComponent.layerNameForLayerId(item.layerId),
disabled: item.layerId === this.sourceData.layerId,
command: () => {
let sourceData = {...this.sourceData};
sourceData.layerId = item.layerId;
sourceData.address = BigInt(0);

this.inspectionService.selectedSourceData.next(sourceData);
},
};
}),
},
];
} else {
this.layerMenuItems = [];
}
});
}

/**
Expand All @@ -141,7 +187,7 @@ export class SourceDataPanelComponent implements OnInit {
this.treeData = [];
this.errorMessage = message;

console.error(this.errorMessage);
console.error("Error while processing SourceData tree:", this.errorMessage);
}

/**
Expand All @@ -158,48 +204,48 @@ export class SourceDataPanelComponent implements OnInit {

const prefix = "https://developer.nds.live/schema/";

let match = schema.match(/^nds\.(([^.]+\.)+)v(\d{4}_\d{2})((\.[^.]*)+)/);
const match = schema.match(/^nds\.(([^.]+\.)+)v(\d{4}_\d{2})((\.[^.]*)+)/);
if (!match || match.length <= 4)
return schema;

// Sub-namespaces in front of the version get joined by "-". Names past the version get joined by "/"
let url =
const url =
match[1].replace(/^(.*)\.$/, "$1/").replaceAll(".", "-") +
match[3].replaceAll("_", ".") +
match[4].replaceAll(".", "/");
return `<a href="${prefix + url}" target="_blank">${schema}</a>`;
}

addressFormatter(address?: any) {
if (!address) {
return address;
}

addressFormatter(address?: any): string {
if (typeof address === 'object') {
return `${address.offset}:${address.size}`
} else {
} else if (address) {
return `${address}`
} else {
return '';
}
}

selectItemWithAddress(address: bigint) {
let searchAddress: any = address;
let addressInRange: any;
if (this.addressFormat == coreLib.SourceDataAddressFormat.BIT_RANGE) {
searchAddress = {
const searchAddress = {
offset: address >> BigInt(32) & BigInt(0xFFFFFFFF),
size: address & BigInt(0xFFFFFFFF),
}

const addressLow = typeof searchAddress === 'object' ? searchAddress['offset'] : searchAddress;
const addressHigh = addressLow + (typeof searchAddress === 'object' ? searchAddress['size'] : searchAddress);

addressInRange = (addr: any) => {
return addr.offset >= addressLow && addr.offset + addr.size <= addressHigh && (addr.size != 0 || addressLow == addressHigh);
addressInRange = (address: any) => {
return address.offset >= addressLow &&
address.offset + address.size <= addressHigh &&
(address.size != 0 || addressLow == addressHigh);
}
} else {
addressInRange = (addr: any) => {
return addr == searchAddress;
const searchAddress = address;
addressInRange = (address: any) => {
return address == searchAddress;
}
}

Expand All @@ -215,8 +261,7 @@ export class SourceDataPanelComponent implements OnInit {
node.data.styleClass = "highlight";
}

const address = node.data.address;
if (address && addressInRange(address)) {
if (node.data.address && addressInRange(node.data.address)) {
highlight = true;

if (!firstHighlightedItemIndex)
Expand All @@ -233,7 +278,6 @@ export class SourceDataPanelComponent implements OnInit {
}
};

console.log(`Highlighting item with address`, searchAddress);
this.treeData.forEach((item: TreeTableNode, index) => {
select(item, [], false, index);
});
Expand Down
Loading
Loading