mirror of
https://github.com/grafana/grafana.git
synced 2025-09-23 18:52:33 +08:00
262 lines
7.3 KiB
TypeScript
262 lines
7.3 KiB
TypeScript
import {
|
|
MapLayerRegistryItem,
|
|
MapLayerOptions,
|
|
PanelData,
|
|
GrafanaTheme2,
|
|
EventBus,
|
|
DataHoverEvent,
|
|
DataHoverClearEvent,
|
|
PluginState,
|
|
} from '@grafana/data';
|
|
import Map from 'ol/Map';
|
|
import VectorLayer from 'ol/layer/Vector';
|
|
import VectorSource from 'ol/source/Vector';
|
|
import { Fill, Stroke, Style, Circle } from 'ol/style';
|
|
import {Group as LayerGroup} from 'ol/layer';
|
|
import Feature from 'ol/Feature';
|
|
import Point from 'ol/geom/Point';
|
|
|
|
import DayNight from 'ol-ext/source/DayNight';
|
|
import { fromLonLat } from 'ol/proj';
|
|
import { Subscription } from 'rxjs';
|
|
import { MultiLineString } from 'ol/geom';
|
|
import { Coordinate } from 'ol/coordinate';
|
|
|
|
export enum ShowTime {
|
|
From = 'from',
|
|
To = 'to',
|
|
}
|
|
|
|
// Configuration options for Circle overlays
|
|
export interface DayNightConfig {
|
|
show: ShowTime;
|
|
sun: boolean;
|
|
nightColor: string;
|
|
}
|
|
|
|
const defaultConfig: DayNightConfig = {
|
|
show: ShowTime.To,
|
|
sun: false,
|
|
nightColor: '#a7a6ba4D'
|
|
};
|
|
|
|
export const DAY_NIGHT_LAYER_ID = 'dayNight';
|
|
|
|
// Used by default when nothing is configured
|
|
export const defaultDayNightConfig: MapLayerOptions<DayNightConfig> = {
|
|
type: DAY_NIGHT_LAYER_ID,
|
|
name: '', // will get replaced
|
|
config: defaultConfig,
|
|
tooltip: true,
|
|
};
|
|
|
|
/**
|
|
* Map layer configuration for circle overlay
|
|
*/
|
|
export const dayNightLayer: MapLayerRegistryItem<DayNightConfig> = {
|
|
id: DAY_NIGHT_LAYER_ID,
|
|
name: 'Night / Day',
|
|
description: 'Show day and night regions',
|
|
isBaseMap: false,
|
|
state: PluginState.alpha,
|
|
|
|
/**
|
|
* Function that configures transformation and returns a transformer
|
|
* @param map
|
|
* @param options
|
|
* @param theme
|
|
*/
|
|
create: async (map: Map, options: MapLayerOptions<DayNightConfig>, eventBus: EventBus, theme: GrafanaTheme2) => {
|
|
// Assert default values
|
|
const config = {
|
|
...defaultConfig,
|
|
...options?.config,
|
|
};
|
|
|
|
// DayNight source
|
|
const source = new DayNight({ });
|
|
const sourceMethods = Object.getPrototypeOf(source);
|
|
const sourceLine = new DayNight({ });
|
|
const sourceLineMethods = Object.getPrototypeOf(sourceLine);
|
|
|
|
// Night polygon
|
|
const vectorLayer = new VectorLayer({
|
|
source,
|
|
style: new Style({
|
|
fill: new Fill({
|
|
color: theme.visualization.getColorByName(config.nightColor)
|
|
})
|
|
})
|
|
});
|
|
|
|
// Night line (for crosshair sharing)
|
|
const nightLineLayer = new VectorLayer({
|
|
source: new VectorSource({
|
|
features: [],
|
|
}),
|
|
style: new Style ({
|
|
stroke: new Stroke({
|
|
color: '#607D8B',
|
|
width: 1.5,
|
|
lineDash: [2, 3],
|
|
})
|
|
}),
|
|
});
|
|
|
|
// Sun circle
|
|
const sunFeature = new Feature({
|
|
geometry: new Point([]),
|
|
});
|
|
|
|
const sunLayer = new VectorLayer({
|
|
source: new VectorSource({
|
|
features: [sunFeature],
|
|
}),
|
|
style: new Style({
|
|
image: new Circle({
|
|
radius: 13,
|
|
fill: new Fill({color: 'rgb(253,184,19)'}),
|
|
})
|
|
}),
|
|
});
|
|
|
|
// Sun line (for crosshair sharing)
|
|
const sunLineFeature = new Feature({
|
|
geometry: new Point([]),
|
|
});
|
|
|
|
const sunLineStyle = new Style({
|
|
image: new Circle({
|
|
radius: 13,
|
|
stroke: new Stroke({
|
|
color: 'rgb(253,184,19)',
|
|
width: 1.5
|
|
})
|
|
})
|
|
});
|
|
|
|
const sunLineStyleDash = new Style({
|
|
image: new Circle({
|
|
radius: 15,
|
|
stroke: new Stroke({
|
|
color: '#607D8B',
|
|
width: 1.5,
|
|
lineDash: [2,3]
|
|
})
|
|
})
|
|
});
|
|
|
|
const sunLineLayer = new VectorLayer({
|
|
source: new VectorSource({
|
|
features: [sunLineFeature],
|
|
}),
|
|
style: [sunLineStyleDash, sunLineStyle],
|
|
});
|
|
|
|
// Build group of layers
|
|
// TODO: add blended night region to "connect" current night region to lines
|
|
const layer = new LayerGroup({
|
|
layers: config.sun? [vectorLayer, sunLayer, sunLineLayer, nightLineLayer] : [vectorLayer, nightLineLayer]
|
|
});
|
|
|
|
// Crosshair sharing subscriptions
|
|
const subscriptions = new Subscription();
|
|
|
|
if (false) {
|
|
subscriptions.add(
|
|
eventBus.subscribe(DataHoverEvent, (event) => {
|
|
const time = event.payload?.point?.time as number;
|
|
if (time) {
|
|
const lineTime = new Date(time);
|
|
const nightLinePoints = sourceLine.getCoordinates(lineTime.toString(), 'line');
|
|
nightLineLayer.getSource()?.clear();
|
|
const lineStringArray:Coordinate[][] = [];
|
|
for (let l = 0; l < nightLinePoints.length - 1; l++){
|
|
const x1:number = Object.values(nightLinePoints[l])[0];
|
|
const y1:number = Object.values(nightLinePoints[l])[1];
|
|
const x2:number = Object.values(nightLinePoints[l+1])[0];
|
|
const y2:number = Object.values(nightLinePoints[l+1])[1];
|
|
const lineString = [fromLonLat([x1, y1]),fromLonLat([x2, y2])];
|
|
lineStringArray.push(lineString);
|
|
}
|
|
nightLineLayer.getSource()?.addFeature(new Feature({
|
|
geometry: new MultiLineString(lineStringArray),
|
|
}))
|
|
|
|
let sunLinePos: number[] = [];
|
|
sunLinePos = sourceLineMethods.getSunPosition(lineTime);
|
|
sunLineFeature.getGeometry()?.setCoordinates(fromLonLat(sunLinePos));
|
|
sunLineFeature.setStyle([sunLineStyle, sunLineStyleDash]);
|
|
}
|
|
})
|
|
);
|
|
|
|
subscriptions.add(
|
|
eventBus.subscribe(DataHoverClearEvent, (event) => {
|
|
nightLineLayer.getSource()?.clear();
|
|
sunLineFeature.setStyle(new Style({}));
|
|
})
|
|
);
|
|
}
|
|
|
|
return {
|
|
init: () => layer,
|
|
dispose: () => subscriptions.unsubscribe(),
|
|
update: (data: PanelData) => {
|
|
const from = new Date(data.timeRange.from.valueOf());
|
|
const to = new Date(data.timeRange.to.valueOf());
|
|
let selectedTime: Date = new Date();
|
|
let sunPos: number[] = [];
|
|
// TODO: add option for "Both"
|
|
if (config.show === ShowTime.From){
|
|
selectedTime = from;
|
|
} else {
|
|
selectedTime = to;
|
|
}
|
|
|
|
source.setTime(selectedTime);
|
|
if (config.sun){
|
|
sunPos = sourceMethods.getSunPosition(selectedTime);
|
|
sunFeature.getGeometry()?.setCoordinates(fromLonLat(sunPos));
|
|
}
|
|
},
|
|
|
|
// Marker overlay options
|
|
registerOptionsUI: (builder) => {
|
|
if(!options.config?.nightColor) {
|
|
options.config = { ...defaultConfig, ...options.config}
|
|
}
|
|
|
|
builder
|
|
.addRadio({
|
|
path: 'config.show',
|
|
name: 'Show',
|
|
settings: {
|
|
options: [
|
|
{ label: 'From', value: ShowTime.From },
|
|
{ label: 'To', value: ShowTime.To },
|
|
],
|
|
},
|
|
defaultValue: defaultConfig.show,
|
|
});
|
|
builder.addColorPicker({
|
|
path: 'config.nightColor',
|
|
name: 'Night region color',
|
|
description: 'Pick color of night region',
|
|
defaultValue: defaultConfig.nightColor,
|
|
settings: [{enableNamedColors: false}],
|
|
});
|
|
builder.addBooleanSwitch({
|
|
path: 'config.sun',
|
|
name: 'Display sun',
|
|
description: 'Show the sun',
|
|
defaultValue: defaultConfig.sun,
|
|
});
|
|
},
|
|
};
|
|
},
|
|
|
|
// fill in the default values
|
|
defaultOptions: defaultConfig,
|
|
};
|