Skip to content

Commit

Permalink
feat(legend): make the legend adapt with the scale level
Browse files Browse the repository at this point in the history
  • Loading branch information
cbourget authored and mbarbeau committed Apr 23, 2019
1 parent 9bc9ddb commit d4b823f
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 52 deletions.
Expand Up @@ -27,7 +27,7 @@ export abstract class DataSource {
return generateIdFromSourceOptions(this.options);
}

getLegend(): DataSourceLegendOptions[] {
getLegend(scale?: number): DataSourceLegendOptions[] {
return this.options.legend ? [this.options.legend] : [];
}
}
Expand Up @@ -155,7 +155,7 @@ export class WMSDataSource extends DataSource {
return new olSourceImageWMS(this.options);
}

getLegend(): DataSourceLegendOptions[] {
getLegend(scale?: number): DataSourceLegendOptions[] {
let legend = super.getLegend();
if (legend.length > 0) {
return legend;
Expand All @@ -174,6 +174,7 @@ export class WMSDataSource extends DataSource {
'SERVICE=wms',
'FORMAT=image/png',
'SLD_VERSION=1.1.0',
`SCALE=${scale}`,
`VERSION=${sourceParams.version || '1.3.0'}`
];

Expand Down
Expand Up @@ -97,5 +97,8 @@ <h4 matLine [matTooltip]="layer.title" matTooltipShowDelay="500">{{layer.title}}
</div>

<div #legend class="igo-layer-legend-container">
<igo-layer-legend *ngIf="showLegend$ | async" [layer]="layer"></igo-layer-legend>
<igo-layer-legend
*ngIf="showLegend$ | async"
[layer]="layer">
</igo-layer-legend>
</div>
61 changes: 34 additions & 27 deletions packages/geo/src/lib/layer/layer-legend/layer-legend.component.html
@@ -1,29 +1,36 @@
<small *ngIf="legend.length === 0">
{{'igo.geo.layer.noLegendText' | translate}}
</small>
<ng-container *ngIf="legendItems$ | async as items">
<ng-container *ngIf="items.length; else noItems">
<ng-container *ngFor="let item of items">
<mat-list-item *ngIf="item.title">
<mat-icon
id="legend-toggle"
class="igo-chevron"
mat-list-avatar
igoCollapse
[target]="legend"
[collapsed]="false">
</mat-icon>
<h4 matLine>{{item.title}}</h4>
</mat-list-item>

<div #legend class="igo-layer-legend" [ngClass]="{'with-title': item.title}">
<img
*ngIf="item.url"
src="{{(item.url | secureImage) | async}}"
alt="{{'igo.geo.layer.loadingLegendText' | translate}}">
<div
[ngStyle]="item.style"
[innerHTML]="item.html"
*ngIf="item.html">
</div>
</div>
</ng-container>
</ng-container>

<ng-template ngFor let-item [ngForOf]="legend">
<mat-list-item *ngIf="item.title">
<mat-icon
id="legend-toggle"
class="igo-chevron"
mat-list-avatar
igoCollapse
[target]="legend"
[collapsed]="false">
</mat-icon>
<h4 matLine>{{item.title}}</h4>
</mat-list-item>
<ng-template #noItems>
<small>
{{'igo.geo.layer.noLegendText' | translate}}
</small>
</ng-template>

<div #legend class="igo-layer-legend" [ngClass]="{'with-title': item.title}">
<img
*ngIf="item.url"
src="{{(item.url | secureImage) | async}}"
alt="{{'igo.geo.layer.loadingLegendText' | translate}}">
<div
[ngStyle]="item.style"
[innerHTML]="item.html"
*ngIf="item.html">
</div>
</div>
</ng-template>
</ng-container>
@@ -1,5 +1,24 @@
img {
max-width: 100%;
min-height: 22px;
position: relative;
display: block;
}

img:after {
content: "\e53b";

font-size: 16px;
font-family: 'Material Icons';
color: rgb(100, 100, 100);

display: block;
position: absolute;
z-index: 2;
top: 0;
left: -4px;
width: 20px;
background-color: #fff;
}

.igo-layer-legend.with-title {
Expand Down
62 changes: 47 additions & 15 deletions packages/geo/src/lib/layer/layer-legend/layer-legend.component.ts
@@ -1,5 +1,8 @@
import { Component, Input, ChangeDetectionStrategy } from '@angular/core';
import { Component, Input, OnInit, OnDestroy, ChangeDetectionStrategy } from '@angular/core';

import { Subscription, BehaviorSubject } from 'rxjs';

import { DataSourceLegendOptions } from '../../datasource/shared/datasources/datasource.interface';
import { Layer } from '../shared/layers';

@Component({
Expand All @@ -8,24 +11,53 @@ import { Layer } from '../shared/layers';
styleUrls: ['./layer-legend.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class LayerLegendComponent {
@Input()
get layer(): Layer {
return this._layer;
export class LayerLegendComponent implements OnInit, OnDestroy {

/**
* Observable of the legend items
*/
legendItems$: BehaviorSubject<DataSourceLegendOptions[]> = new BehaviorSubject([]);

/**
* Subscription to the map's resolution
*/
private resolution$$: Subscription;

/**
* Layer
*/
@Input() layer: Layer;

constructor() {}

/**
* On init, subscribe to the map's resolution and update the legend accordingly
*/
ngOnInit() {
const resolution$ = this.layer.map.viewController.resolution$;
this.resolution$$ = resolution$.subscribe((resolution: number) => {
this.onResolutionChange(resolution);
});
}
set layer(value: Layer) {
this._layer = value;
this._legend = value.dataSource.getLegend();

/**
* On destroy, unsubscribe to the map,s resolution
*/
ngOnDestroy() {
this.resolution$$.unsubscribe();
}
private _layer: Layer;

get legend() {
if (this._legend && this._legend.display === false) {
return [];
/**
* On resolution change, compute the effective scale level and update the
* legend accordingly.
*/
private onResolutionChange(resolution: number) {
const scale = this.layer.map.viewController.getScale();
const legendItems = this.layer.dataSource.getLegend(scale);
if (legendItems.length === 0 && this.legendItems$.value.length === 0) {
return;
}
return this._legend;
this.legendItems$.next(legendItems);
}
private _legend;

constructor() {}
}
14 changes: 12 additions & 2 deletions packages/geo/src/lib/map/shared/map.utils.ts
@@ -1,3 +1,5 @@
import * as olproj from 'ol/proj';

import { MapViewState } from './map.interface';

/**
Expand Down Expand Up @@ -72,7 +74,15 @@ export function formatScale(scale) {
* @param Scale denom
* @returns Resolution
*/
export function getResolutionFromScale(scale: number): number {
const dpi = 25.4 / 0.28;
export function getResolutionFromScale(scale: number, dpi: number = 72): number {
return scale / (39.37 * dpi);
}

/**
* Return the resolution from a scale denom
* @param Scale denom
* @returns Resolution
*/
export function getScaleFromResolution(resolution: number, unit: string = 'm', dpi: number = 72): number {
return resolution * olproj.METERS_PER_UNIT[unit] * 39.37 * dpi;
}
1 change: 1 addition & 0 deletions packages/geo/src/lib/print/print/print.component.ts
Expand Up @@ -97,6 +97,7 @@ export class PrintComponent {

this.printService.downloadMapImage(
this.map,
+data.resolution,
data.imageFormat,
data.showProjection,
data.showScale,
Expand Down
11 changes: 6 additions & 5 deletions packages/geo/src/lib/print/shared/print.service.ts
Expand Up @@ -34,7 +34,7 @@ export class PrintService {
const status$ = new Subject();

const paperFormat: string = options.paperFormat;
const resolution = +options.resolution;
const resolution = +options.resolution; // Default is 96
const orientation = options.orientation;

this.activityId = this.activityService.register();
Expand Down Expand Up @@ -206,14 +206,14 @@ export class PrintService {
* Add projection and/or scale to the document
* @param doc - pdf document
* @param map - Map of the app
* @param resolution - DPI resolution of the document
* @param dpi - DPI resolution of the document
* @param projection - Bool to indicate if projection need to be added
* @param scale - Bool to indicate if scale need to be added
*/
private addProjScale(
doc: jsPDF,
map: IgoMap,
resolution: number,
dpi: number,
projection: boolean,
scale: boolean
) {
Expand All @@ -233,7 +233,7 @@ export class PrintService {
textProjScale += ' ';
}
const scaleText = translate.instant('igo.geo.printForm.scale');
const mapScale = map.viewController.getScale(resolution);
const mapScale = map.viewController.getScale(dpi);
textProjScale += scaleText + ' ~ 1 ' + formatScale(mapScale);
}
doc.setFont('courier');
Expand Down Expand Up @@ -398,6 +398,7 @@ export class PrintService {
*/
downloadMapImage(
map: IgoMap,
resolution: number,
format = 'png',
projection = false,
scale = false,
Expand All @@ -407,7 +408,7 @@ export class PrintService {
doZipFile = true
) {
const status$ = new Subject();
const resolution = map.ol.getView().getResolution();
// const resolution = map.ol.getView().getResolution();
this.activityId = this.activityService.register();
const translate = this.languageService.translate;
map.ol.once('postcompose', (event: any) => {
Expand Down

0 comments on commit d4b823f

Please sign in to comment.