@opengeoweb/webmap-react 9.1.0 → 9.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.esm.js +228 -3
- package/package.json +1 -1
- package/src/lib/components/Axis/ProfileAxis.d.ts +8 -0
- package/src/lib/components/Axis/ProfileAxis.spec.d.ts +1 -0
- package/src/lib/components/Axis/ProfileAxis.stories.d.ts +9 -0
- package/src/lib/components/Axis/profileUtils.d.ts +17 -0
- package/src/lib/components/Axis/profileUtils.spec.d.ts +1 -0
- package/src/lib/components/MapView/MapView.ProfileSounding.stories.d.ts +9 -0
- package/src/lib/components/ReactMapView/types.d.ts +5 -0
- package/src/lib/layers/profileLayers.d.ts +19 -0
package/index.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import React__default, { Component, forwardRef, useContext, Children, isValidElement, cloneElement, useRef, useState, useEffect, useCallback, createRef, PureComponent } from 'react';
|
|
3
|
-
import { legendImageStore, WMImageEventType, webmapUtils, getLegendGraphicURLForLayer, getMapImageStore, LayerType, WMBBOX, debugLogger, DebugType, WMLayer, WMJSMap, tilesettings } from '@opengeoweb/webmap';
|
|
3
|
+
import { legendImageStore, WMImageEventType, webmapUtils, getLegendGraphicURLForLayer, getMapImageStore, LayerType, WMBBOX, debugLogger, DebugType, WMLayer, WMJSMap, tilesettings, getWMJSMapById } from '@opengeoweb/webmap';
|
|
4
4
|
import { CustomTooltip, ToolContainerDraggable, dateUtils, CustomIconButton } from '@opengeoweb/shared';
|
|
5
5
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
6
6
|
import * as ReactDOM from 'react-dom';
|
|
@@ -55468,7 +55468,12 @@ class ReactMapView extends React.Component {
|
|
|
55468
55468
|
onMapPinChangeLocation({
|
|
55469
55469
|
mapPinLocation: {
|
|
55470
55470
|
lat: mapPinLatLonCoordinate.lat,
|
|
55471
|
-
lon: mapPinLatLonCoordinate.lon
|
|
55471
|
+
lon: mapPinLatLonCoordinate.lon,
|
|
55472
|
+
projectionX: mapPinLatLonCoordinate.projectionX,
|
|
55473
|
+
projectionY: mapPinLatLonCoordinate.projectionY,
|
|
55474
|
+
screenOffsetX: mapPinLatLonCoordinate.screenOffsetX,
|
|
55475
|
+
screenOffsetY: mapPinLatLonCoordinate.screenOffsetY,
|
|
55476
|
+
srs: mapPinLatLonCoordinate.srs
|
|
55472
55477
|
},
|
|
55473
55478
|
mapId
|
|
55474
55479
|
});
|
|
@@ -56680,6 +56685,224 @@ const MapTime = ({
|
|
|
56680
56685
|
}, mapTime)));
|
|
56681
56686
|
};
|
|
56682
56687
|
|
|
56688
|
+
/* *
|
|
56689
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
56690
|
+
* you may not use this file except in compliance with the License.
|
|
56691
|
+
* You may obtain a copy of the License at
|
|
56692
|
+
*
|
|
56693
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
56694
|
+
*
|
|
56695
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
56696
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
56697
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
56698
|
+
* See the License for the specific language governing permissions and
|
|
56699
|
+
* limitations under the License.
|
|
56700
|
+
*
|
|
56701
|
+
* Copyright 2023 - Koninklijk Nederlands Meteorologisch Instituut (KNMI)
|
|
56702
|
+
* Copyright 2023 - Finnish Meteorological Institute (FMI)
|
|
56703
|
+
* */
|
|
56704
|
+
const MS_IN_HOUR = 3600 * 1000;
|
|
56705
|
+
// The following is necessary to allow to assign to the CanvasRenderingContext2D ctx property
|
|
56706
|
+
/* eslint-disable no-param-reassign */
|
|
56707
|
+
/**
|
|
56708
|
+
* This component registers to a webmap instance and draws axis for height and time in the map using the Map Canvas.
|
|
56709
|
+
*/
|
|
56710
|
+
const ProfileAxis = ({
|
|
56711
|
+
mapId
|
|
56712
|
+
}) => {
|
|
56713
|
+
const drawAxisOnMapDisplay = (ctx, webMap, axisStyle) => {
|
|
56714
|
+
const bbox = webMap.getBBOX();
|
|
56715
|
+
const width = webMap.getWidth();
|
|
56716
|
+
const height = webMap.getHeight();
|
|
56717
|
+
const offY = height - 50;
|
|
56718
|
+
const offX = 20;
|
|
56719
|
+
try {
|
|
56720
|
+
const startDate = new Date(bbox.left);
|
|
56721
|
+
const endDate = new Date(bbox.right);
|
|
56722
|
+
webMap.setMessage(`${startDate.toDateString()}, ${startDate.getUTCHours()} to ${endDate.getUTCHours()} hours UTC`);
|
|
56723
|
+
} catch (e) {
|
|
56724
|
+
webMap.setMessage('');
|
|
56725
|
+
}
|
|
56726
|
+
// Draw the horizontal time axis
|
|
56727
|
+
drawTimeAxis(ctx, bbox, offX, offY, width, height, axisStyle);
|
|
56728
|
+
// Draw the vertical elevation axis
|
|
56729
|
+
drawHeightAxis(ctx, bbox, offX, offY, width, height, axisStyle);
|
|
56730
|
+
// Draw the mouse cursor
|
|
56731
|
+
drawCursor(ctx, bbox, offX, offY, width, height, webMap, axisStyle);
|
|
56732
|
+
// Draw the layer name
|
|
56733
|
+
drawLayerName(ctx, bbox, offX, offY, width, height, webMap, axisStyle);
|
|
56734
|
+
};
|
|
56735
|
+
React__default.useEffect(() => {
|
|
56736
|
+
const axisStyle = {
|
|
56737
|
+
backgroundColor: 'white',
|
|
56738
|
+
color: 'black',
|
|
56739
|
+
fontStyleSmall: '10px Roboto, Helvetica, Arial',
|
|
56740
|
+
fontStyleBig: '14px Roboto, Helvetica, Arial'
|
|
56741
|
+
};
|
|
56742
|
+
// Draw on map canvas callback function
|
|
56743
|
+
const beforeCanvasDisplay = ctx => {
|
|
56744
|
+
drawAxisOnMapDisplay(ctx, getWMJSMapById(mapId), axisStyle);
|
|
56745
|
+
};
|
|
56746
|
+
// unMount logic
|
|
56747
|
+
const unMount = () => {
|
|
56748
|
+
const webMap = getWMJSMapById(mapId);
|
|
56749
|
+
if (webMap) {
|
|
56750
|
+
webMap.removeListener('beforecanvasdisplay', beforeCanvasDisplay);
|
|
56751
|
+
}
|
|
56752
|
+
};
|
|
56753
|
+
// Mount logic
|
|
56754
|
+
const webMap = getWMJSMapById(mapId);
|
|
56755
|
+
if (webMap && webMap.getProjection().srs === 'GFI:TIME_ELEVATION') {
|
|
56756
|
+
webMap.hideScaleBar();
|
|
56757
|
+
webMap.hideMouseCursorProperties();
|
|
56758
|
+
webMap.setTimeOffset('');
|
|
56759
|
+
webMap.addListener('beforecanvasdisplay', beforeCanvasDisplay, true);
|
|
56760
|
+
webMap.draw();
|
|
56761
|
+
}
|
|
56762
|
+
return unMount;
|
|
56763
|
+
}, [mapId]);
|
|
56764
|
+
return null;
|
|
56765
|
+
};
|
|
56766
|
+
/**
|
|
56767
|
+
* Calculates a time spacing. This is used to place labels on the X axis (time axis).
|
|
56768
|
+
* To make readable time labels, the time spacing is discretized to rounded times,
|
|
56769
|
+
* The time spacing changes according to zoom level.
|
|
56770
|
+
* @param bbox
|
|
56771
|
+
* @param width
|
|
56772
|
+
* @returns
|
|
56773
|
+
*/
|
|
56774
|
+
const getTimeSpacingInMs = (bbox, width) => {
|
|
56775
|
+
const hoursInView = Math.abs(bbox.right - bbox.left) / (MS_IN_HOUR * width / 500);
|
|
56776
|
+
return Math.pow(2, Math.round((Math.log10(hoursInView / 10) + 0.5) / Math.log10(2)) - 1) * MS_IN_HOUR;
|
|
56777
|
+
};
|
|
56778
|
+
const drawTimeAxis = (ctx, bbox, offsetX, offsetY, width, height, axisStyle) => {
|
|
56779
|
+
const {
|
|
56780
|
+
backgroundColor,
|
|
56781
|
+
color,
|
|
56782
|
+
fontStyleSmall,
|
|
56783
|
+
fontStyleBig
|
|
56784
|
+
} = axisStyle;
|
|
56785
|
+
// Draw rectangle with backgroundColor for axis
|
|
56786
|
+
ctx.textBaseline = 'middle';
|
|
56787
|
+
ctx.fillStyle = backgroundColor;
|
|
56788
|
+
ctx.fillRect(0, offsetY, width, 50);
|
|
56789
|
+
ctx.font = fontStyleSmall;
|
|
56790
|
+
ctx.textAlign = 'left';
|
|
56791
|
+
ctx.fillStyle = color;
|
|
56792
|
+
ctx.strokeStyle = color;
|
|
56793
|
+
const ticksMs = getTimeSpacingInMs(bbox, width);
|
|
56794
|
+
const roundedTimeLeftMs = Math.round(bbox.left / ticksMs) * ticksMs;
|
|
56795
|
+
const roundedTimeRightMs = Math.round(bbox.right / ticksMs) * ticksMs;
|
|
56796
|
+
const numHoursInView = Math.min((roundedTimeRightMs - roundedTimeLeftMs) / ticksMs + 1, 100);
|
|
56797
|
+
for (let hoursToPlot = 0; hoursToPlot < numHoursInView; hoursToPlot += 1) {
|
|
56798
|
+
const timeMs = roundedTimeLeftMs + hoursToPlot * ticksMs;
|
|
56799
|
+
const posX = Math.round((timeMs - bbox.left) / (bbox.right - bbox.left) * width) + 0.5;
|
|
56800
|
+
ctx.beginPath();
|
|
56801
|
+
ctx.moveTo(posX, offsetY + 0);
|
|
56802
|
+
ctx.lineTo(posX, offsetY + 10);
|
|
56803
|
+
const date = new Date(timeMs);
|
|
56804
|
+
const hourString = `0${date.getUTCHours()}`.slice(-2);
|
|
56805
|
+
const minuteString = `:${`0${date.getUTCMinutes()}`.slice(-2)}`;
|
|
56806
|
+
const txt = `${hourString}${minuteString}`;
|
|
56807
|
+
ctx.stroke();
|
|
56808
|
+
ctx.fillText(`${txt}`, posX - 13, offsetY + 16);
|
|
56809
|
+
}
|
|
56810
|
+
// Draw units in map
|
|
56811
|
+
ctx.font = fontStyleBig;
|
|
56812
|
+
ctx.fillText('time UTC (h)', width / 2 - 10, offsetY + 38);
|
|
56813
|
+
};
|
|
56814
|
+
/**
|
|
56815
|
+
* Calculates a spacing for the height axis. This is used to place labels on the Y axis (height axis).
|
|
56816
|
+
* To make readable height labels, the height spacing is discretized to rounded elevations,
|
|
56817
|
+
* The spacing changes according to zoom level.
|
|
56818
|
+
* @param bbox
|
|
56819
|
+
* @param height
|
|
56820
|
+
* @returns
|
|
56821
|
+
*/
|
|
56822
|
+
const getHeightSpacingInMs = (bbox, height) => {
|
|
56823
|
+
const numMeterInView = Math.abs(bbox.bottom - bbox.top) / height;
|
|
56824
|
+
return Math.pow(10, Math.round(Math.log10(numMeterInView * 100) + 0.5) - 1);
|
|
56825
|
+
};
|
|
56826
|
+
const drawHeightAxis = (ctx, bbox, offsetX, offsetY, width, height, axisStyle) => {
|
|
56827
|
+
const {
|
|
56828
|
+
backgroundColor,
|
|
56829
|
+
color,
|
|
56830
|
+
fontStyleSmall,
|
|
56831
|
+
fontStyleBig
|
|
56832
|
+
} = axisStyle;
|
|
56833
|
+
// Draw rectangle in backgroundColor for axis
|
|
56834
|
+
ctx.fillStyle = backgroundColor;
|
|
56835
|
+
ctx.fillRect(0, 0, 60 + offsetX, height);
|
|
56836
|
+
ctx.font = fontStyleSmall;
|
|
56837
|
+
ctx.textAlign = 'right';
|
|
56838
|
+
ctx.fillStyle = color;
|
|
56839
|
+
const ticksM = getHeightSpacingInMs(bbox, height);
|
|
56840
|
+
const roundedElevBottomMeter = Math.round(bbox.bottom / ticksM) * ticksM;
|
|
56841
|
+
const roundedElevTopMeter = Math.round(bbox.top / ticksM) * ticksM;
|
|
56842
|
+
const numKmInView = Math.min((roundedElevTopMeter - roundedElevBottomMeter) / ticksM + 1, 100);
|
|
56843
|
+
for (let kmToPlot = 0; kmToPlot < numKmInView; kmToPlot += 1) {
|
|
56844
|
+
const valueInKm = roundedElevBottomMeter + kmToPlot * ticksM;
|
|
56845
|
+
const posY = Math.round((bbox.top - valueInKm) / (bbox.top - bbox.bottom) * height) + 0.5;
|
|
56846
|
+
ctx.beginPath();
|
|
56847
|
+
ctx.moveTo(offsetX + 50, posY);
|
|
56848
|
+
ctx.lineTo(offsetX + 60, posY);
|
|
56849
|
+
ctx.stroke();
|
|
56850
|
+
const txt = valueInKm;
|
|
56851
|
+
ctx.fillText(`${txt}`, offsetX + 48, posY + 2);
|
|
56852
|
+
}
|
|
56853
|
+
// Draw height unit in axis
|
|
56854
|
+
ctx.font = axisStyle.fontStyleBig;
|
|
56855
|
+
ctx.save();
|
|
56856
|
+
ctx.translate(5, height / 2 - 50);
|
|
56857
|
+
ctx.rotate(-Math.PI / 2);
|
|
56858
|
+
ctx.font = fontStyleBig;
|
|
56859
|
+
ctx.fillText('height (m)', 5, 5);
|
|
56860
|
+
ctx.restore();
|
|
56861
|
+
ctx.fillStyle = backgroundColor;
|
|
56862
|
+
ctx.fillRect(0, height - 60, offsetX + 60, 60);
|
|
56863
|
+
// Draw line border for map
|
|
56864
|
+
ctx.moveTo(offsetX + 60, offsetY + 0.5);
|
|
56865
|
+
ctx.lineTo(width, offsetY + 0.5);
|
|
56866
|
+
ctx.moveTo(offsetX + 60.5, 0);
|
|
56867
|
+
ctx.lineTo(offsetX + 60.5, height - 50);
|
|
56868
|
+
ctx.stroke();
|
|
56869
|
+
};
|
|
56870
|
+
const drawCursor = (ctx, bbox, offsetX, offsetY, width, height, webMapJS, axisStyle) => {
|
|
56871
|
+
// Do not draw if mouse is not in the map
|
|
56872
|
+
if (webMapJS.mouseX < 5 && webMapJS.mouseY < 5) {
|
|
56873
|
+
return;
|
|
56874
|
+
}
|
|
56875
|
+
/* Draw cursor line */
|
|
56876
|
+
const mouseX = Math.round(webMapJS.mouseX) + 0.5;
|
|
56877
|
+
const mouseY = Math.round(webMapJS.mouseY) + 0.5;
|
|
56878
|
+
ctx.strokeStyle = '#303030';
|
|
56879
|
+
ctx.setLineDash([15, 5]);
|
|
56880
|
+
ctx.beginPath();
|
|
56881
|
+
ctx.moveTo(0, mouseY);
|
|
56882
|
+
ctx.lineTo(width, mouseY);
|
|
56883
|
+
ctx.moveTo(mouseX, 0);
|
|
56884
|
+
ctx.lineTo(mouseX, height);
|
|
56885
|
+
ctx.stroke();
|
|
56886
|
+
ctx.strokeStyle = axisStyle.color;
|
|
56887
|
+
ctx.lineWidth = 1;
|
|
56888
|
+
ctx.setLineDash([]);
|
|
56889
|
+
};
|
|
56890
|
+
const drawLayerName = (ctx, bbox, offsetX, offsetY, width, height, webMapJS, axisStyle) => {
|
|
56891
|
+
// Draw layername
|
|
56892
|
+
const layers = webMapJS.getLayers();
|
|
56893
|
+
if (layers.length > 0) {
|
|
56894
|
+
ctx.textBaseline = 'middle';
|
|
56895
|
+
ctx.fillStyle = axisStyle.backgroundColor;
|
|
56896
|
+
ctx.font = axisStyle.fontStyleBig;
|
|
56897
|
+
ctx.textAlign = 'left';
|
|
56898
|
+
ctx.fillStyle = axisStyle.color;
|
|
56899
|
+
ctx.strokeStyle = axisStyle.color;
|
|
56900
|
+
ctx.fillText(`Layer: ${layers[0].name}`, 10, offsetY + 38);
|
|
56901
|
+
}
|
|
56902
|
+
};
|
|
56903
|
+
// Re-enable the previousely disabled eslint rule
|
|
56904
|
+
/* eslint-enable no-param-reassign */
|
|
56905
|
+
|
|
56683
56906
|
const MapView = _a => {
|
|
56684
56907
|
var {
|
|
56685
56908
|
children,
|
|
@@ -56733,7 +56956,9 @@ const MapView = _a => {
|
|
|
56733
56956
|
top: 0,
|
|
56734
56957
|
position: 'absolute'
|
|
56735
56958
|
}
|
|
56736
|
-
}, /*#__PURE__*/React.createElement(
|
|
56959
|
+
}, /*#__PURE__*/React.createElement(ProfileAxis, {
|
|
56960
|
+
mapId: mapId
|
|
56961
|
+
}), /*#__PURE__*/React.createElement(ZoomControls, {
|
|
56737
56962
|
onZoomIn: () => {
|
|
56738
56963
|
const wmjsMap = webmapUtils.getWMJSMapById(mapId);
|
|
56739
56964
|
wmjsMap.zoomIn(undefined);
|
package/package.json
CHANGED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface ProfileAxisProps {
|
|
3
|
+
mapId: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* This component registers to a webmap instance and draws axis for height and time in the map using the Map Canvas.
|
|
7
|
+
*/
|
|
8
|
+
export declare const ProfileAxis: React.FC<ProfileAxisProps>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import 'jest-canvas-mock';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type GFIResult = [{
|
|
2
|
+
data: {
|
|
3
|
+
'0': number;
|
|
4
|
+
};
|
|
5
|
+
}];
|
|
6
|
+
export declare const CEILONETSTATIONLAYERNAME = "hasceilometerWMONAME";
|
|
7
|
+
export declare const CEILONETPROFILELAYERPREFIX = "ceilonet_";
|
|
8
|
+
/**
|
|
9
|
+
* Connects a Map with a WMS layer with ceilometer stations to a Map withj profile layers.
|
|
10
|
+
* Clicking on the station map causes the layer in the profile map to be changed accordingly.
|
|
11
|
+
* The layername comes from a GetFeatureInfo request on the stations layer.
|
|
12
|
+
*
|
|
13
|
+
* @param mapIdWithProfileViewer
|
|
14
|
+
* @param mapIdWithCeilometerStations
|
|
15
|
+
* @returns
|
|
16
|
+
*/
|
|
17
|
+
export declare const connectProfileMapViewToProfileStationsMapById: (mapIdWithProfileViewer: string, mapIdWithCeilometerStations: string) => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -34,6 +34,11 @@ export interface ReactMapViewProps {
|
|
|
34
34
|
export interface MapLocation {
|
|
35
35
|
lat: number;
|
|
36
36
|
lon: number;
|
|
37
|
+
screenOffsetX?: number;
|
|
38
|
+
screenOffsetY?: number;
|
|
39
|
+
projectionX?: number;
|
|
40
|
+
projectionY?: number;
|
|
41
|
+
srs?: string;
|
|
37
42
|
}
|
|
38
43
|
export interface MapPinLocationPayload {
|
|
39
44
|
mapId: string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { LayerType } from '@opengeoweb/webmap';
|
|
2
|
+
/**
|
|
3
|
+
* Base URL of the adaguc-service where all profiles are configured
|
|
4
|
+
*/
|
|
5
|
+
export declare const profileAdagucServiceBaseUrl = "https://geoservices.knmi.nl";
|
|
6
|
+
/** The station layer with overview of profile datasets */
|
|
7
|
+
export declare const profileStationLayer: {
|
|
8
|
+
service: string;
|
|
9
|
+
name: string;
|
|
10
|
+
style: string;
|
|
11
|
+
layerType: LayerType;
|
|
12
|
+
};
|
|
13
|
+
export declare const profileDataLayer: {
|
|
14
|
+
service: string;
|
|
15
|
+
name: string;
|
|
16
|
+
format: string;
|
|
17
|
+
enabled: boolean;
|
|
18
|
+
layerType: LayerType;
|
|
19
|
+
};
|