import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { CoordinateConverter } from '../../../angular-cesium/services/coordinate-converter/coordinate-converter.service';
import { EditActions } from '../../models/edit-actions.enum';
import { PolylineEditorObservable } from '../../models/polyline-editor-observable';
import { PolylineEditOptions } from '../../models/polyline-edit-options';
import { LabelProps, LabelStyle } from '../../models/label-props';
import { PolylineEditUpdate } from '../../models/polyline-edit-update';
import { EditModes } from '../../models/edit-mode.enum';
import { PolylinesEditorService } from '../../services/entity-editors/polyline-editor/polylines-editor.service';
/**
*
* Range and bearing component that is used to draw range and bearing on the map.
* The inputs are used to customize the range and bearing style and behavior.
* Create component reference and use the `create()` function to start creating R&B on the map.
* The function receives an optional RangeAndBearingOptions object that defines the created range and bearing style and behavior
* (on top of the default and global definitions).
*
* Usage:
*
* my-component.ts:
*
* ```
* \@ViewChild('rangeAndBearing', {static: false}) private rangeAndBearing: RangeAndBearingComponent; // Get R&B reference
* // ...
* this.rangeAndBearing.create({style: { pointProps: { pixelSize: 12 } }, bearingLabelsStyle: { fillColor: Cesium.Color.GREEN } });
* ```
*
* my-component.html
* ```
* <range-and-bearing #rangeAndBearing></range-and-bearing> // Optional inputs defines global style and behavior.
* ```
*
*/
@Component({
selector: 'range-and-bearing',
template: `
<polylines-editor></polylines-editor>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [PolylinesEditorService],
})
export class RangeAndBearingComponent {
@Input() lineEditOptions?: PolylineEditOptions = {};
@Input() labelsStyle?: LabelStyle = {};
@Input() distanceLabelsStyle?: LabelStyle = {};
@Input() bearingLabelsStyle?: LabelStyle = {};
@Input() bearingStringFn?: (value: number) => string;
@Input() distanceStringFn?: (value: number) => string;
@Input() labelsRenderFn?: (update: PolylineEditUpdate, labels: LabelProps[]) => LabelProps[];
constructor(private polylineEditor: PolylinesEditorService, private coordinateConverter: CoordinateConverter) {
}
create(
{
lineEditOptions = {},
labelsStyle = {},
distanceLabelsStyle = {},
bearingLabelsStyle = {},
bearingStringFn,
distanceStringFn,
labelsRenderFn,
}: RangeAndBearingOptions = {lineEditOptions: {}, labelsStyle: {}, distanceLabelsStyle: {}, bearingLabelsStyle: {}},
): PolylineEditorObservable {
const rnb = this.polylineEditor.create({
allowDrag: false,
pointProps: {
showVirtual: false,
pixelSize: 8,
},
polylineProps: {
width: 2,
},
...this.lineEditOptions,
...lineEditOptions,
});
if (labelsRenderFn) {
rnb.setLabelsRenderFn(labelsRenderFn);
} else if (this.labelsRenderFn) {
rnb.setLabelsRenderFn(this.labelsRenderFn);
} else {
rnb.setLabelsRenderFn(update => {
const positions = update.positions;
let totalDistance = 0;
if (!positions || positions.length === 0) {
return [];
}
return (update.editMode === EditModes.CREATE && update.editAction !== EditActions.ADD_LAST_POINT
? [...positions, update.updatedPosition]
: positions
).reduce(
(labels, position, index, array) => {
if (index !== 0) {
const previousPosition = array[index - 1];
const bearing = this.coordinateConverter.bearingToCartesian(previousPosition, position);
const distance = Cesium.Cartesian3.distance(previousPosition, position) / 1000;
labels.push(
{
text:
(bearingStringFn && bearingStringFn(bearing)) ||
(this.bearingStringFn && this.bearingStringFn(bearing)) ||
`${bearing.toFixed(2)}°`,
scale: 0.2,
font: '80px Helvetica',
pixelOffset: new Cesium.Cartesian2(-20, -8),
position: new Cesium.Cartesian3(
(position.x + previousPosition.x) / 2,
(position.y + previousPosition.y) / 2,
(position.z + previousPosition.z) / 2,
),
fillColor: Cesium.Color.WHITE,
outlineColor: Cesium.Color.WHITE,
showBackground: true,
...(this.labelsStyle as any),
...(labelsStyle as any),
...(this.bearingLabelsStyle as any),
...(bearingLabelsStyle as any),
},
{
text:
(distanceStringFn && distanceStringFn(totalDistance + distance)) ||
(this.distanceStringFn && this.distanceStringFn(totalDistance + distance)) ||
`${(totalDistance + distance).toFixed(2)} Km`,
scale: 0.2,
font: '80px Helvetica',
pixelOffset: new Cesium.Cartesian2(-35, -8),
position: position,
fillColor: Cesium.Color.WHITE,
outlineColor: Cesium.Color.WHITE,
showBackground: true,
...(this.labelsStyle as any),
...(labelsStyle as any),
...(this.distanceLabelsStyle as any),
...(distanceLabelsStyle as any),
},
);
totalDistance += distance;
}
return labels;
},
[
{
text: (distanceStringFn && distanceStringFn(0)) || (this.distanceStringFn && this.distanceStringFn(0)) || `0 Km`,
scale: 0.2,
font: '80px Helvetica',
pixelOffset: new Cesium.Cartesian2(-20, -8),
position: positions[0],
fillColor: Cesium.Color.WHITE,
outlineColor: Cesium.Color.WHITE,
showBackground: true,
...(this.labelsStyle as any),
...(labelsStyle as any),
...(this.distanceLabelsStyle as any),
...(distanceLabelsStyle as any),
},
],
);
});
}
return rnb;
}
}
export interface RangeAndBearingOptions {
lineEditOptions?: PolylineEditOptions;
labelsStyle?: LabelStyle;
distanceLabelsStyle?: LabelStyle;
bearingLabelsStyle?: LabelStyle;
bearingStringFn?: (value: number) => string;
distanceStringFn?: (value: number) => string;
labelsRenderFn?: (update: PolylineEditUpdate, labels: LabelProps[]) => LabelProps[];
}