mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Geomap: Minor style fixes (#38532)
* Fixed hover font-weight, option casing, and added simple test dashboard with 3 panels * Update theme colors * Style tweaks to legend * Updated Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
This commit is contained in:
parent
12320dda3c
commit
d5ed4e9c8c
@ -5,7 +5,7 @@ pkg/
|
||||
node_modules
|
||||
public/vendor/
|
||||
vendor/
|
||||
data/
|
||||
/data/
|
||||
e2e/tmp
|
||||
public/build/
|
||||
public/sass/*.generated.scss
|
||||
|
404
devenv/dev-dashboards/panel-geomap/panel-geomap.json
Normal file
404
devenv/dev-dashboards/panel-geomap/panel-geomap.json
Normal file
@ -0,0 +1,404 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": "-- Grafana --",
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"target": {
|
||||
"limit": 100,
|
||||
"matchAny": false,
|
||||
"tags": [],
|
||||
"type": "dashboard"
|
||||
},
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"gnetId": null,
|
||||
"graphTooltip": 0,
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"panels": [
|
||||
{
|
||||
"datasource": null,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "continuous-GrYlRd"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 11,
|
||||
"w": 9,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 62,
|
||||
"options": {
|
||||
"basemap": {
|
||||
"config": {},
|
||||
"type": "default"
|
||||
},
|
||||
"controls": {
|
||||
"mouseWheelZoom": true,
|
||||
"showAttribution": true,
|
||||
"showDebug": false,
|
||||
"showScale": false,
|
||||
"showZoom": true
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"config": {
|
||||
"color": {
|
||||
"field": "Price",
|
||||
"fixed": "dark-green"
|
||||
},
|
||||
"fillOpacity": 0.4,
|
||||
"shape": "circle",
|
||||
"showLegend": true,
|
||||
"size": {
|
||||
"field": "Count",
|
||||
"fixed": 5,
|
||||
"max": 15,
|
||||
"min": 2
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"gazetteer": "public/gazetteer/usa-states.json",
|
||||
"lookup": "State",
|
||||
"mode": "auto"
|
||||
},
|
||||
"type": "markers"
|
||||
}
|
||||
],
|
||||
"view": {
|
||||
"id": "coords",
|
||||
"lat": 38.297683,
|
||||
"lon": -99.228359,
|
||||
"shared": true,
|
||||
"zoom": 3.98
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"csvFileName": "flight_info_by_state.csv",
|
||||
"refId": "A",
|
||||
"scenarioId": "csv_file"
|
||||
}
|
||||
],
|
||||
"title": "Size, color mapped to different fields + share view",
|
||||
"type": "geomap"
|
||||
},
|
||||
{
|
||||
"datasource": null,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
},
|
||||
{
|
||||
"color": "#EAB839",
|
||||
"value": 90
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 11,
|
||||
"w": 9,
|
||||
"x": 9,
|
||||
"y": 0
|
||||
},
|
||||
"id": 66,
|
||||
"options": {
|
||||
"basemap": {
|
||||
"config": {},
|
||||
"type": "default"
|
||||
},
|
||||
"controls": {
|
||||
"mouseWheelZoom": true,
|
||||
"showAttribution": true,
|
||||
"showDebug": false,
|
||||
"showScale": false,
|
||||
"showZoom": true
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"config": {
|
||||
"color": {
|
||||
"field": "Price",
|
||||
"fixed": "dark-green"
|
||||
},
|
||||
"fillOpacity": 0.4,
|
||||
"shape": "circle",
|
||||
"showLegend": true,
|
||||
"size": {
|
||||
"field": "Count",
|
||||
"fixed": 5,
|
||||
"max": 15,
|
||||
"min": 2
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"gazetteer": "public/gazetteer/usa-states.json",
|
||||
"lookup": "State",
|
||||
"mode": "auto"
|
||||
},
|
||||
"type": "markers"
|
||||
}
|
||||
],
|
||||
"view": {
|
||||
"id": "coords",
|
||||
"lat": 38.297683,
|
||||
"lon": -99.228359,
|
||||
"shared": true,
|
||||
"zoom": 3.98
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"csvFileName": "flight_info_by_state.csv",
|
||||
"refId": "A",
|
||||
"scenarioId": "csv_file"
|
||||
}
|
||||
],
|
||||
"title": "Thresholds legend",
|
||||
"type": "geomap"
|
||||
},
|
||||
{
|
||||
"datasource": null,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "continuous-BlYlRd"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 11,
|
||||
"w": 9,
|
||||
"x": 0,
|
||||
"y": 11
|
||||
},
|
||||
"id": 63,
|
||||
"options": {
|
||||
"basemap": {
|
||||
"config": {},
|
||||
"type": "default"
|
||||
},
|
||||
"controls": {
|
||||
"mouseWheelZoom": true,
|
||||
"showAttribution": true,
|
||||
"showDebug": false,
|
||||
"showScale": false,
|
||||
"showZoom": true
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"config": {
|
||||
"blur": 27,
|
||||
"radius": 25,
|
||||
"weight": {
|
||||
"field": "Count",
|
||||
"fixed": 1,
|
||||
"max": 1,
|
||||
"min": 0
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"gazetteer": "public/gazetteer/usa-states.json",
|
||||
"lookup": "State",
|
||||
"mode": "auto"
|
||||
},
|
||||
"type": "heatmap"
|
||||
}
|
||||
],
|
||||
"view": {
|
||||
"id": "coords",
|
||||
"lat": 38.251497,
|
||||
"lon": -100.932144,
|
||||
"shared": false,
|
||||
"zoom": 4.15
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"csvFileName": "flight_info_by_state.csv",
|
||||
"refId": "A",
|
||||
"scenarioId": "csv_file"
|
||||
}
|
||||
],
|
||||
"title": "Heatmap data layer",
|
||||
"transformations": [],
|
||||
"type": "geomap"
|
||||
},
|
||||
{
|
||||
"datasource": null,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "continuous-GrYlRd"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 11,
|
||||
"w": 9,
|
||||
"x": 9,
|
||||
"y": 11
|
||||
},
|
||||
"id": 65,
|
||||
"options": {
|
||||
"basemap": {
|
||||
"config": {
|
||||
"server": "world-imagery"
|
||||
},
|
||||
"type": "esri-xyz"
|
||||
},
|
||||
"controls": {
|
||||
"mouseWheelZoom": true,
|
||||
"showAttribution": true,
|
||||
"showDebug": false,
|
||||
"showScale": false,
|
||||
"showZoom": true
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"config": {
|
||||
"color": {
|
||||
"fixed": "#ff001e"
|
||||
},
|
||||
"fillOpacity": 0.4,
|
||||
"shape": "star",
|
||||
"showLegend": true,
|
||||
"size": {
|
||||
"field": "Count",
|
||||
"fixed": 5,
|
||||
"max": 15,
|
||||
"min": 2
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"gazetteer": "public/gazetteer/usa-states.json",
|
||||
"lookup": "State",
|
||||
"mode": "auto"
|
||||
},
|
||||
"type": "markers"
|
||||
}
|
||||
],
|
||||
"view": {
|
||||
"id": "coords",
|
||||
"lat": 40.159084,
|
||||
"lon": -96.508021,
|
||||
"shared": true,
|
||||
"zoom": 3.83
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"csvFileName": "flight_info_by_state.csv",
|
||||
"refId": "A",
|
||||
"scenarioId": "csv_file"
|
||||
}
|
||||
],
|
||||
"title": "Base layer ArcGIS wold imagery + star shape + share view",
|
||||
"type": "geomap"
|
||||
}
|
||||
],
|
||||
"refresh": "",
|
||||
"schemaVersion": 30,
|
||||
"style": "dark",
|
||||
"tags": [
|
||||
"gdev",
|
||||
"panel-tests"
|
||||
],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {
|
||||
"refresh_intervals": [
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
]
|
||||
},
|
||||
"timezone": "",
|
||||
"title": "Panel Tests - Geomap",
|
||||
"uid": "2xuwrgV7z",
|
||||
"version": 5
|
||||
}
|
@ -46,8 +46,8 @@ const getStyles = stylesFactory((theme: GrafanaTheme2) => ({
|
||||
infoWrap: css`
|
||||
padding: 8px;
|
||||
th {
|
||||
font-weight: bold;
|
||||
padding: 2px 10px 2px 0px;
|
||||
font-weight: ${theme.typography.fontWeightMedium};
|
||||
padding: ${theme.spacing(0.25, 2)};
|
||||
}
|
||||
`,
|
||||
highlight: css`
|
||||
|
@ -60,7 +60,7 @@ export const LayerEditor: FC<LayerEditorProps> = ({ options, onChange, data, fil
|
||||
})
|
||||
.addFieldNamePicker({
|
||||
path: 'location.latitude',
|
||||
name: 'Latitude Field',
|
||||
name: 'Latitude field',
|
||||
settings: {
|
||||
filter: (f: Field) => f.type === FieldType.number,
|
||||
noFieldsMessage: 'No numeric fields found',
|
||||
@ -69,7 +69,7 @@ export const LayerEditor: FC<LayerEditorProps> = ({ options, onChange, data, fil
|
||||
})
|
||||
.addFieldNamePicker({
|
||||
path: 'location.longitude',
|
||||
name: 'Longitude Field',
|
||||
name: 'Longitude field',
|
||||
settings: {
|
||||
filter: (f: Field) => f.type === FieldType.number,
|
||||
noFieldsMessage: 'No numeric fields found',
|
||||
@ -78,7 +78,7 @@ export const LayerEditor: FC<LayerEditorProps> = ({ options, onChange, data, fil
|
||||
})
|
||||
.addFieldNamePicker({
|
||||
path: 'location.geohash',
|
||||
name: 'Geohash Field',
|
||||
name: 'Geohash field',
|
||||
settings: {
|
||||
filter: (f: Field) => f.type === FieldType.string,
|
||||
noFieldsMessage: 'No strings fields found',
|
||||
@ -89,7 +89,7 @@ export const LayerEditor: FC<LayerEditorProps> = ({ options, onChange, data, fil
|
||||
})
|
||||
.addFieldNamePicker({
|
||||
path: 'location.lookup',
|
||||
name: 'Lookup Field',
|
||||
name: 'Lookup field',
|
||||
settings: {
|
||||
filter: (f: Field) => f.type === FieldType.string,
|
||||
noFieldsMessage: 'No strings fields found',
|
||||
|
@ -2,7 +2,6 @@ import { css } from '@emotion/react';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
|
||||
import 'ol/ol.css';
|
||||
import tinycolor from 'tinycolor2';
|
||||
|
||||
/**
|
||||
* Will be loaded *after* the css above
|
||||
@ -45,11 +44,9 @@ export function getGlobalStyles(theme: GrafanaTheme2) {
|
||||
// border: 2px dotted rgba(0,60,136,0.7);
|
||||
// }
|
||||
|
||||
const bg = tinycolor(theme.v1.colors.panelBg);
|
||||
const button = tinycolor(theme.colors.secondary.main);
|
||||
return css`
|
||||
.ol-scale-line {
|
||||
background: ${bg.setAlpha(0.7).toRgbString()}; // rgba(0,60,136,0.3);
|
||||
background: ${theme.colors.border.weak}; // rgba(0,60,136,0.3);
|
||||
}
|
||||
.ol-scale-line-inner {
|
||||
border: 1px solid ${theme.colors.text.primary}; // #eee;
|
||||
@ -57,28 +54,27 @@ export function getGlobalStyles(theme: GrafanaTheme2) {
|
||||
color: ${theme.colors.text.primary}; // #eee;
|
||||
}
|
||||
.ol-control {
|
||||
background-color: ${bg.setAlpha(0.4).toRgbString()}; //rgba(255,255,255,0.4);
|
||||
background-color: ${theme.colors.background.secondary}; //rgba(255,255,255,0.4);
|
||||
}
|
||||
.ol-control:hover {
|
||||
background-color: ${bg.setAlpha(0.6).toRgbString()}; // rgba(255,255,255,0.6);
|
||||
background-color: ${theme.colors.action.hover}; // rgba(255,255,255,0.6);
|
||||
}
|
||||
.ol-control button {
|
||||
color: ${bg.setAlpha(0.8).toRgbString()}; // white;
|
||||
background-color: ${button.setAlpha(0.5).toRgbString()}; // rgba(0,60,136,0.5);
|
||||
color: ${theme.colors.secondary.text}; // white;
|
||||
background-color: ${theme.colors.secondary.main}; // rgba(0,60,136,0.5);
|
||||
}
|
||||
.ol-control button:hover {
|
||||
background-color: ${button.setAlpha(0.7).toRgbString()}; // rgba(0,60,136,0.7);
|
||||
background-color: ${theme.colors.secondary.shade}; // rgba(0,60,136,0.5);
|
||||
}
|
||||
.ol-control button:focus {
|
||||
// same as button
|
||||
background-color: ${button.setAlpha(0.5).toRgbString()}; // rgba(0,60,136,0.5);
|
||||
background-color: ${theme.colors.secondary.main}; // rgba(0,60,136,0.5);
|
||||
}
|
||||
.ol-attribution ul {
|
||||
color: ${theme.colors.text.primary}; // #000;
|
||||
text-shadow: 0 0 0px #fff; // removes internal styling!
|
||||
text-shadow: none;
|
||||
}
|
||||
.ol-attribution:not(.ol-collapsed) {
|
||||
background-color: ${bg.setAlpha(0.8).toRgbString()}; // rgba(255,255,255,0.8);
|
||||
background-color: ${theme.colors.background.secondary}; // rgba(255,255,255,0.8);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Label, stylesFactory } from '@grafana/ui';
|
||||
import { formattedValueToString, getFieldColorModeForField, GrafanaTheme } from '@grafana/data';
|
||||
import { Label, stylesFactory, useTheme2 } from '@grafana/ui';
|
||||
import { formattedValueToString, getFieldColorModeForField, GrafanaTheme2 } from '@grafana/data';
|
||||
import { css } from '@emotion/css';
|
||||
import { config } from 'app/core/config';
|
||||
import { DimensionSupplier } from 'app/features/dimensions';
|
||||
@ -10,21 +10,22 @@ export interface MarkersLegendProps {
|
||||
color?: DimensionSupplier<string>;
|
||||
size?: DimensionSupplier<number>;
|
||||
}
|
||||
|
||||
export function MarkersLegend(props: MarkersLegendProps) {
|
||||
const { color } = props;
|
||||
const theme = useTheme2();
|
||||
|
||||
if (!color || (!color.field && color.fixed)) {
|
||||
return (
|
||||
<></>
|
||||
)
|
||||
return <></>;
|
||||
}
|
||||
const style = getStyles(config.theme);
|
||||
|
||||
|
||||
const style = getStyles(theme);
|
||||
const fmt = (v: any) => `${formattedValueToString(color.field!.display!(v))}`;
|
||||
const colorMode = getFieldColorModeForField(color!.field!);
|
||||
|
||||
|
||||
if (colorMode.isContinuous && colorMode.getColors) {
|
||||
const colors = colorMode.getColors(config.theme2)
|
||||
const colorRange = getMinMaxAndDelta(color.field!)
|
||||
const colors = colorMode.getColors(config.theme2);
|
||||
const colorRange = getMinMaxAndDelta(color.field!);
|
||||
// TODO: explore showing mean on the gradiant scale
|
||||
// const stats = reduceField({
|
||||
// field: color.field!,
|
||||
@ -36,13 +37,18 @@ export function MarkersLegend(props: MarkersLegendProps) {
|
||||
// ]
|
||||
// })
|
||||
|
||||
return <>
|
||||
<Label>{color?.field?.name}</Label>
|
||||
<div className={style.gradientContainer} style={{backgroundImage: `linear-gradient(to right, ${colors.map((c) => c).join(', ')}`}}>
|
||||
<div>{fmt(colorRange.min)}</div>
|
||||
<div>{fmt(colorRange.max)}</div>
|
||||
</div>
|
||||
</>
|
||||
return (
|
||||
<>
|
||||
<Label>{color?.field?.name}</Label>
|
||||
<div
|
||||
className={style.gradientContainer}
|
||||
style={{ backgroundImage: `linear-gradient(to right, ${colors.map((c) => c).join(', ')}` }}
|
||||
>
|
||||
<div style={{ color: theme.colors.getContrastText(colors[0]) }}>{fmt(colorRange.min)}</div>
|
||||
<div style={{ color: theme.colors.getContrastText(colors[colors.length - 1]) }}>{fmt(colorRange.max)}</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const thresholds = color.field?.config?.thresholds;
|
||||
@ -54,7 +60,7 @@ export function MarkersLegend(props: MarkersLegendProps) {
|
||||
<div className={style.infoWrap}>
|
||||
{thresholds && (
|
||||
<div className={style.legend}>
|
||||
{thresholds.steps.map((step:any, idx:number) => {
|
||||
{thresholds.steps.map((step: any, idx: number) => {
|
||||
const next = thresholds!.steps[idx + 1];
|
||||
let info = <span>?</span>;
|
||||
if (idx === 0) {
|
||||
@ -78,21 +84,20 @@ export function MarkersLegend(props: MarkersLegendProps) {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const getStyles = stylesFactory((theme: GrafanaTheme) => ({
|
||||
const getStyles = stylesFactory((theme: GrafanaTheme2) => ({
|
||||
infoWrap: css`
|
||||
color: #999;
|
||||
background: #CCCC;
|
||||
background: ${theme.colors.background.secondary};
|
||||
border-radius: 2px;
|
||||
padding: 8px;
|
||||
padding: ${theme.spacing(1)};
|
||||
`,
|
||||
legend: css`
|
||||
line-height: 18px;
|
||||
color: #555;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-size: ${theme.typography.bodySmall.fontSize};
|
||||
|
||||
i {
|
||||
width: 18px;
|
||||
@ -109,5 +114,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => ({
|
||||
min-width: 200px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
`
|
||||
font-size: ${theme.typography.bodySmall.fontSize};
|
||||
padding: ${theme.spacing(0, 0.5)};
|
||||
`,
|
||||
}));
|
||||
|
@ -45,11 +45,11 @@ export const geojsonMapper: MapLayerRegistryItem<GeoJSONMapperConfig> = {
|
||||
return {
|
||||
init: () => vectorLayer,
|
||||
update: (data: PanelData) => {
|
||||
console.log( "todo... find values matching the ID and update");
|
||||
console.log('todo... find values matching the ID and update');
|
||||
|
||||
// Update each feature
|
||||
source.getFeatures().forEach( f => {
|
||||
console.log( "Find: ", f.getId(), f.getProperties() );
|
||||
source.getFeatures().forEach((f) => {
|
||||
console.log('Find: ', f.getId(), f.getProperties());
|
||||
});
|
||||
},
|
||||
};
|
||||
|
@ -24,7 +24,7 @@ export interface HeatmapConfig {
|
||||
const defaultOptions: HeatmapConfig = {
|
||||
weight: {
|
||||
fixed: 1,
|
||||
min: 0,
|
||||
min: 0,
|
||||
max: 1,
|
||||
},
|
||||
blur: 15,
|
||||
@ -76,8 +76,8 @@ export const heatmapLayer: MapLayerRegistryItem<HeatmapConfig> = {
|
||||
|
||||
// Get data points (latitude and longitude coordinates)
|
||||
const info = dataFrameToPoints(frame, matchers);
|
||||
if(info.warning) {
|
||||
console.log( 'WARN', info.warning);
|
||||
if (info.warning) {
|
||||
console.log('WARN', info.warning);
|
||||
return; // ???
|
||||
}
|
||||
|
||||
@ -86,18 +86,18 @@ export const heatmapLayer: MapLayerRegistryItem<HeatmapConfig> = {
|
||||
// Map each data value into new points
|
||||
for (let i = 0; i < frame.length; i++) {
|
||||
const cluster = new Feature({
|
||||
geometry: info.points[i],
|
||||
value: weightDim.get(i),
|
||||
geometry: info.points[i],
|
||||
value: weightDim.get(i),
|
||||
});
|
||||
vectorSource.addFeature(cluster);
|
||||
};
|
||||
}
|
||||
vectorLayer.setSource(vectorSource);
|
||||
|
||||
// Set heatmap gradient colors
|
||||
let colors = ['#00f', '#0ff', '#0f0', '#ff0', '#f00'];
|
||||
|
||||
// Either the configured field or the first numeric field value
|
||||
const field = weightDim.field ?? frame.fields.find(field => field.type === FieldType.number);
|
||||
const field = weightDim.field ?? frame.fields.find((field) => field.type === FieldType.number);
|
||||
if (field) {
|
||||
const colorMode = getFieldColorModeForField(field);
|
||||
if (colorMode.isContinuous && colorMode.getColors) {
|
||||
@ -123,7 +123,8 @@ export const heatmapLayer: MapLayerRegistryItem<HeatmapConfig> = {
|
||||
max: 1,
|
||||
hideRange: true, // Don't show the scale factor
|
||||
},
|
||||
defaultValue: { // Configured values
|
||||
defaultValue: {
|
||||
// Configured values
|
||||
fixed: 1,
|
||||
min: 0,
|
||||
max: 1,
|
||||
@ -135,9 +136,9 @@ export const heatmapLayer: MapLayerRegistryItem<HeatmapConfig> = {
|
||||
name: 'Radius',
|
||||
defaultValue: defaultOptions.radius,
|
||||
settings: {
|
||||
min: 1,
|
||||
max: 50,
|
||||
step: 1,
|
||||
min: 1,
|
||||
max: 50,
|
||||
step: 1,
|
||||
},
|
||||
})
|
||||
.addSliderInput({
|
||||
|
@ -7,8 +7,8 @@ import { lastPointTracker } from './lastPointTracker';
|
||||
* Registry for layer handlers
|
||||
*/
|
||||
export const dataLayers = [
|
||||
markersLayer,
|
||||
heatmapLayer,
|
||||
lastPointTracker,
|
||||
geojsonMapper, // dummy for now
|
||||
markersLayer,
|
||||
heatmapLayer,
|
||||
lastPointTracker,
|
||||
geojsonMapper, // dummy for now
|
||||
];
|
||||
|
@ -53,13 +53,13 @@ export const lastPointTracker: MapLayerRegistryItem<LastPointConfig> = {
|
||||
const frame = data.series[0];
|
||||
if (frame && frame.length) {
|
||||
const info = dataFrameToPoints(frame, matchers);
|
||||
if(info.warning) {
|
||||
console.log( 'WARN', info.warning);
|
||||
if (info.warning) {
|
||||
console.log('WARN', info.warning);
|
||||
return; // ???
|
||||
}
|
||||
|
||||
if(info.points?.length) {
|
||||
const last = info.points[info.points.length-1];
|
||||
if (info.points?.length) {
|
||||
const last = info.points[info.points.length - 1];
|
||||
point.setGeometry(last);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,11 @@
|
||||
|
||||
import React, { ReactNode } from 'react';
|
||||
import { MapLayerRegistryItem, MapLayerOptions, PanelData, GrafanaTheme2, FrameGeometrySourceMode } from '@grafana/data';
|
||||
import {
|
||||
MapLayerRegistryItem,
|
||||
MapLayerOptions,
|
||||
PanelData,
|
||||
GrafanaTheme2,
|
||||
FrameGeometrySourceMode,
|
||||
} from '@grafana/data';
|
||||
import Map from 'ol/Map';
|
||||
import Feature from 'ol/Feature';
|
||||
import * as layer from 'ol/layer';
|
||||
@ -8,7 +13,12 @@ import * as source from 'ol/source';
|
||||
|
||||
import tinycolor from 'tinycolor2';
|
||||
import { dataFrameToPoints, getLocationMatchers } from '../../utils/location';
|
||||
import { ColorDimensionConfig, ScaleDimensionConfig, getScaledDimension, getColorDimension } from 'app/features/dimensions';
|
||||
import {
|
||||
ColorDimensionConfig,
|
||||
ScaleDimensionConfig,
|
||||
getScaledDimension,
|
||||
getColorDimension,
|
||||
} from 'app/features/dimensions';
|
||||
import { ScaleDimensionEditor, ColorDimensionEditor } from 'app/features/dimensions/editors';
|
||||
import { ObservablePropsWrapper } from '../../components/ObservablePropsWrapper';
|
||||
import { MarkersLegend, MarkersLegendProps } from './MarkersLegend';
|
||||
@ -31,23 +41,23 @@ const defaultOptions: MarkersConfig = {
|
||||
max: 15,
|
||||
},
|
||||
color: {
|
||||
fixed: 'dark-green', // picked from theme
|
||||
fixed: 'dark-green', // picked from theme
|
||||
},
|
||||
fillOpacity: 0.4,
|
||||
shape: 'circle',
|
||||
showLegend: true,
|
||||
};
|
||||
|
||||
export const MARKERS_LAYER_ID = "markers";
|
||||
export const MARKERS_LAYER_ID = 'markers';
|
||||
|
||||
// Used by default when nothing is configured
|
||||
export const defaultMarkersConfig:MapLayerOptions<MarkersConfig> = {
|
||||
export const defaultMarkersConfig: MapLayerOptions<MarkersConfig> = {
|
||||
type: MARKERS_LAYER_ID,
|
||||
config: defaultOptions,
|
||||
location: {
|
||||
mode: FrameGeometrySourceMode.Auto,
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Map layer configuration for circle overlay
|
||||
@ -72,31 +82,27 @@ export const markersLayer: MapLayerRegistryItem<MarkersConfig> = {
|
||||
...options?.config,
|
||||
};
|
||||
|
||||
const legendProps= new ReplaySubject<MarkersLegendProps>(1);
|
||||
let legend:ReactNode = null;
|
||||
const legendProps = new ReplaySubject<MarkersLegendProps>(1);
|
||||
let legend: ReactNode = null;
|
||||
if (config.showLegend) {
|
||||
legend = <ObservablePropsWrapper
|
||||
watch={legendProps}
|
||||
initialSubProps={{}}
|
||||
child={MarkersLegend}
|
||||
/>
|
||||
legend = <ObservablePropsWrapper watch={legendProps} initialSubProps={{}} child={MarkersLegend} />;
|
||||
}
|
||||
const shape = markerMakers.getIfExists(config.shape) ?? circleMarker;
|
||||
|
||||
|
||||
return {
|
||||
init: () => vectorLayer,
|
||||
legend: legend,
|
||||
update: (data: PanelData) => {
|
||||
if(!data.series?.length) {
|
||||
if (!data.series?.length) {
|
||||
return; // ignore empty
|
||||
}
|
||||
|
||||
const features: Feature[] = [];
|
||||
|
||||
for(const frame of data.series) {
|
||||
for (const frame of data.series) {
|
||||
const info = dataFrameToPoints(frame, matchers);
|
||||
if(info.warning) {
|
||||
console.log( 'Could not find locations', info.warning);
|
||||
if (info.warning) {
|
||||
console.log('Could not find locations', info.warning);
|
||||
continue; // ???
|
||||
}
|
||||
|
||||
@ -114,7 +120,7 @@ export const markersLayer: MapLayerRegistryItem<MarkersConfig> = {
|
||||
const radius = sizeDim.get(i);
|
||||
|
||||
// Create a new Feature for each point returned from dataFrameToPoints
|
||||
const dot = new Feature( info.points[i] );
|
||||
const dot = new Feature(info.points[i]);
|
||||
dot.setProperties({
|
||||
frame,
|
||||
rowIndex: i,
|
||||
@ -122,7 +128,7 @@ export const markersLayer: MapLayerRegistryItem<MarkersConfig> = {
|
||||
|
||||
dot.setStyle(shape!.make(color, fillColor, radius));
|
||||
features.push(dot);
|
||||
};
|
||||
}
|
||||
|
||||
// Post updates to the legend component
|
||||
if (legend) {
|
||||
@ -149,7 +155,8 @@ export const markersLayer: MapLayerRegistryItem<MarkersConfig> = {
|
||||
name: 'Marker Color',
|
||||
editor: ColorDimensionEditor,
|
||||
settings: {},
|
||||
defaultValue: { // Configured values
|
||||
defaultValue: {
|
||||
// Configured values
|
||||
fixed: 'grey',
|
||||
},
|
||||
})
|
||||
@ -162,7 +169,8 @@ export const markersLayer: MapLayerRegistryItem<MarkersConfig> = {
|
||||
min: 1,
|
||||
max: 100, // possible in the UI
|
||||
},
|
||||
defaultValue: { // Configured values
|
||||
defaultValue: {
|
||||
// Configured values
|
||||
fixed: 5,
|
||||
min: 1,
|
||||
max: 20,
|
||||
@ -185,7 +193,7 @@ export const markersLayer: MapLayerRegistryItem<MarkersConfig> = {
|
||||
max: 1,
|
||||
step: 0.1,
|
||||
},
|
||||
showIf: (cfg) => (markerMakers.getIfExists((cfg as any).config?.shape)?.hasFill),
|
||||
showIf: (cfg) => markerMakers.getIfExists((cfg as any).config?.shape)?.hasFill,
|
||||
})
|
||||
.addBooleanSwitch({
|
||||
path: 'config.showLegend',
|
||||
|
@ -13,7 +13,7 @@ export const plugin = new PanelPlugin<GeomapPanelOptions>(GeomapPanel)
|
||||
.setPanelChangeHandler(mapPanelChangedHandler)
|
||||
.useFieldConfig()
|
||||
.setPanelOptions((builder) => {
|
||||
let category = ['Map View'];
|
||||
let category = ['Map view'];
|
||||
builder.addCustomEditor({
|
||||
category,
|
||||
id: 'view',
|
||||
@ -33,25 +33,25 @@ export const plugin = new PanelPlugin<GeomapPanelOptions>(GeomapPanel)
|
||||
});
|
||||
|
||||
builder.addCustomEditor({
|
||||
category: ['Base Layer'],
|
||||
category: ['Base layer'],
|
||||
id: 'basemap',
|
||||
path: 'basemap',
|
||||
name: 'Base Layer',
|
||||
name: 'Base layer',
|
||||
editor: BaseLayerEditor,
|
||||
defaultValue: DEFAULT_BASEMAP_CONFIG,
|
||||
});
|
||||
|
||||
builder.addCustomEditor({
|
||||
category: ['Data Layer'],
|
||||
category: ['Data layer'],
|
||||
id: 'layers',
|
||||
path: 'layers',
|
||||
name: 'Data Layer',
|
||||
name: 'Data layer',
|
||||
editor: DataLayersEditor,
|
||||
defaultValue: [defaultMarkersConfig],
|
||||
});
|
||||
|
||||
// The controls section
|
||||
category = ['Map Controls'];
|
||||
category = ['Map controls'];
|
||||
builder
|
||||
.addBooleanSwitch({
|
||||
category,
|
||||
|
Loading…
Reference in New Issue
Block a user