Skip to content

Commit

Permalink
Merge commit 'bed88971c58ab68dbfb33183eacaef8481fd0954' into #9319_an…
Browse files Browse the repository at this point in the history
…notation

* commit 'bed88971c58ab68dbfb33183eacaef8481fd0954':
  Adding clause in documentation for google photorealistic 3D tiles (geosolutions-it#9458) (geosolutions-it#9460)
  geosolutions-it#9275 Fix issue Invalid date on Firefox  (geosolutions-it#9393) (geosolutions-it#9451)
  geosolutions-it#9163 Bug 3D Tiles offset with Google 3D tiles (geosolutions-it#9421) (geosolutions-it#9450)
  geosolutions-it#9269 fix issue of correct map embed url in sharing map (geosolutions-it#9395) (geosolutions-it#9452)
  geosolutions-it#9310 Annotation not works with sideBarmenu (geosolutions-it#9402) (geosolutions-it#9449)
  set resolve.fallback.http/https/zlib to false in webpack extension build config (geosolutions-it#9375) (geosolutions-it#9445)
  geosolutions-it#9422 Zoom level issue on OpenLayers (geosolutions-it#9429) (geosolutions-it#9442)
  geosolutions-it#9362 3D Styling issue (geosolutions-it#9403) (geosolutions-it#9441)
  geosolutions-it#9363 Wrong scale value reported using the scroll wheel (geosolutions-it#9401) (geosolutions-it#9440)
  geosolutions-it#9366 Problems with Bearing measurement (geosolutions-it#9400) (geosolutions-it#9439)
  geosolutions-it#9346 ensure the zoom is always round before using it as index (geosolutions-it#9357) (geosolutions-it#9438)
  • Loading branch information
dsuren1 committed Sep 20, 2023
2 parents 74c077b + bed8897 commit cfe5537
Show file tree
Hide file tree
Showing 22 changed files with 191 additions and 102 deletions.
3 changes: 3 additions & 0 deletions build/createExtensionWebpackConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ module.exports = ({ prod = true, name, exposes, sharedLibrariesEager = true, ali
resolve: {
fallback: {
path: false,
http: false,
https: false,
zlib: false,
timers: false,
stream: false
},
Expand Down
6 changes: 6 additions & 0 deletions docs/user-guide/catalog.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,3 +340,9 @@ MapStore allows to publish 3D Tiles contents in its 3D mode on top of the [Cesiu
In **general settings of** 3D Tiles service, the user can specify the title to assign to this service and the URL of the service.

<img src="../img/catalog/3dtiles_service.jpg" class="ms-docimage" style="max-width:600px;"/>

!!! warning
MapStore allows you to load also [Google Photorealistic 3D Tiles](https://cloud.google.com/blog/products/maps-platform/create-immersive-3d-map-experiences-photorealistic-3d-tiles) and some constraints need to be respected in this case.
Since the Google Photorealistic 3D Tiles are not ‘survey-grade’ at this time, the use of certain MapStore tools could be considered derivative and, for this reason, prohibited. Please, make sure you have read the [Google conditions of use](https://developers.google.com/maps/documentation/tile/policies)
(some [FAQs](https://cloud.google.com/blog/products/maps-platform/commonly-asked-questions-about-our-recently-launched-photorealistic-3d-tiles) are also available online for this purpose) before providing Google Photorealistic 3D Tile in your MapStore maps in order to enable only allowed tools (e.g. *Measurement* and *Identify* tools should be probably disabled).
For this purpose it is possible to appropriately set the [configuration of MapStore plugins](../../developer-guide/maps-configuration/#map-options) to exclude tools that could conflict with Google policies. Alternatively, it is possible to use a dedicated [application context](application-context.md#configure-plugins) to show Photorealistic 3D Tiles by including only the permitted tools within it.
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ function SelectInput({
function VisibilityLimitsForm({
title,
layer,
zoom,
zoom: zoomProp,
projection,
resolutions = getResolutions(),
defaultLimitsType,
Expand All @@ -104,6 +104,8 @@ function VisibilityLimitsForm({
onChange
}) {

const zoom = Math.round(zoomProp || 0);

const [limitsType, setLimitsType] = useState(defaultLimitsType || limitsTypesOptions[0].value);

const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,118 +5,178 @@
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
import React from 'react';
import ReactDOM from 'react-dom';
import expect from 'expect';
import React from "react";
import ReactDOM from "react-dom";
import expect from "expect";

import NumberFormat from '../../../../I18N/Number';
import {getFormatter, registerFormatter, unregisterFormatter} from '../index';
import NumberFormat from "../../../../I18N/Number";
import { getFormatter, registerFormatter, unregisterFormatter } from "../index";

describe('Tests for the formatter functions', () => {
it('test getFormatter for booleans', () => {
const formatter = getFormatter({localType: "boolean"});
describe("Tests for the formatter functions", () => {
it("test getFormatter for booleans", () => {
const formatter = getFormatter({ localType: "boolean" });
expect(typeof formatter).toBe("function");
expect(formatter()).toBe(null);
expect(formatter({value: true}).type).toBe("span");
expect(formatter({value: true}).props.children).toBe("true");
expect(formatter({value: false}).props.children).toBe("false");
expect(formatter({value: null})).toBe(null);
expect(formatter({value: undefined})).toBe(null);
expect(formatter({ value: true }).type).toBe("span");
expect(formatter({ value: true }).props.children).toBe("true");
expect(formatter({ value: false }).props.children).toBe("false");
expect(formatter({ value: null })).toBe(null);
expect(formatter({ value: undefined })).toBe(null);
});
it('test getFormatter for strings', () => {
const value = 'Test https://google.com with google link';
const formatter = getFormatter({localType: "string"});
it("test getFormatter for strings", () => {
const value = "Test https://google.com with google link";
const formatter = getFormatter({ localType: "string" });
expect(typeof formatter).toBe("function");
expect(formatter()).toBe(null);
expect(formatter({value: 'Test no links'})[0]).toBe('Test no links');
expect(formatter({value})[0]).toBe('Test ');
expect(formatter({value})[1].props.href).toBe('https://google.com');
expect(formatter({value})[2]).toBe(' with google link');
expect(formatter({value: null})).toBe(null);
expect(formatter({value: undefined})).toBe(null);
expect(formatter({ value: "Test no links" })[0]).toBe("Test no links");
expect(formatter({ value })[0]).toBe("Test ");
expect(formatter({ value })[1].props.href).toBe("https://google.com");
expect(formatter({ value })[2]).toBe(" with google link");
expect(formatter({ value: null })).toBe(null);
expect(formatter({ value: undefined })).toBe(null);
});
it('test getFormatter for number', () => {
const formatter = getFormatter({localType: "number"});
it("test getFormatter for number", () => {
const formatter = getFormatter({ localType: "number" });
expect(typeof formatter).toBe("function");
expect(formatter()).toBe(null);
expect(formatter({value: 44.3333434353535}).type).toBe(NumberFormat);
expect(formatter({value: 44.3333434353535}).props.value).toBe(44.3333434353535);
expect(formatter({value: null})).toBe(null);
expect(formatter({value: undefined})).toBe(null);
expect(formatter({value: 0}).props.value).toBe(0);
expect(formatter({ value: 44.3333434353535 }).type).toBe(NumberFormat);
expect(formatter({ value: 44.3333434353535 }).props.value).toBe(
44.3333434353535
);
expect(formatter({ value: null })).toBe(null);
expect(formatter({ value: undefined })).toBe(null);
expect(formatter({ value: 0 }).props.value).toBe(0);
});
it('test getFormatter for int', () => {
const formatter = getFormatter({localType: "int"});
it("test getFormatter for int", () => {
const formatter = getFormatter({ localType: "int" });
expect(typeof formatter).toBe("function");
expect(formatter()).toBe(null);
expect(formatter({value: 2455567}).type).toBe(NumberFormat);
expect(formatter({value: 2455567}).props.value).toBe(2455567);
expect(formatter({value: null})).toBe(null);
expect(formatter({value: undefined})).toBe(null);
expect(formatter({value: 0}).props.value).toBe(0);
expect(formatter({ value: 2455567 }).type).toBe(NumberFormat);
expect(formatter({ value: 2455567 }).props.value).toBe(2455567);
expect(formatter({ value: null })).toBe(null);
expect(formatter({ value: undefined })).toBe(null);
expect(formatter({ value: 0 }).props.value).toBe(0);
});
it('test getFormatter for geometry', () => {
const formatter = getFormatter({localType: "Geometry"});
it("test getFormatter for geometry", () => {
const formatter = getFormatter({ localType: "Geometry" });
expect(typeof formatter).toBe("function");
expect(formatter()).toBe(null);
expect(formatter({value: {properties: {}, geometry: {type: "Point", coordinates: [1, 2]}}})).toBe(null);
expect(formatter({value: null})).toBe(null);
expect(formatter({value: undefined})).toBe(null);
expect(
formatter({
value: {
properties: {},
geometry: { type: "Point", coordinates: [1, 2] }
}
})
).toBe(null);
expect(formatter({ value: null })).toBe(null);
expect(formatter({ value: undefined })).toBe(null);
});
describe('test featureGridFormatter', () => {
describe("test featureGridFormatter", () => {
beforeEach((done) => {
document.body.innerHTML = '<div id="container"></div>';
setTimeout(done);
});

afterEach((done) => {
ReactDOM.unmountComponentAtNode(document.getElementById("container"));
document.body.innerHTML = '';
ReactDOM.unmountComponentAtNode(
document.getElementById("container")
);
document.body.innerHTML = "";
setTimeout(done);
});
it('base', () => {
it("base", () => {
try {
registerFormatter("test", ({config, value}) => {
registerFormatter("test", ({ config, value }) => {
expect(config).toExist();
expect(value).toBe("test");
return <div>test</div>;
});
const Formatter = getFormatter({localType: "test"}, {featureGridFormatter: {name: "test"}});
ReactDOM.render(<Formatter value="test"/>, document.getElementById("container"));
expect(document.getElementById("container").innerHTML).toBe('<div>test</div>');
const Formatter = getFormatter(
{ localType: "test" },
{ featureGridFormatter: { name: "test" } }
);
ReactDOM.render(
<Formatter value="test" />,
document.getElementById("container")
);
expect(document.getElementById("container").innerHTML).toBe(
"<div>test</div>"
);
} finally {
unregisterFormatter("test");
}
});
it('with directRender option', () => {
it("with directRender option", () => {
try {
const TEST_FUNC = () => <div>test</div>;
registerFormatter("test", TEST_FUNC);
const formatter = getFormatter({localType: "test"}, {featureGridFormatter: {name: "test", directRender: true}});
const formatter = getFormatter(
{ localType: "test" },
{
featureGridFormatter: {
name: "test",
directRender: true
}
}
);
expect(formatter).toBe(TEST_FUNC);
} finally {
unregisterFormatter("test");
}
});
});
it('test getFormatter for date / date-time / time', () => {
it("test getFormatter for date / date-time / time", () => {
const dateFormats = {
date: 'YYYY',
"date-time": 'YYYY DD',
time: 'HH:mm'
date: "YYYY",
"date-time": "YYYY DD",
time: "HH:mm"
};
const dateFormatter = getFormatter({localType: "date"}, undefined, {dateFormats});
const dateTimeFormatter = getFormatter({localType: "date-time"}, undefined, {dateFormats});
const timeFormatter = getFormatter({localType: "time"}, undefined, {dateFormats});
const dateFormatter = getFormatter({ localType: "date" }, undefined, {
dateFormats
});
const dateTimeFormatter = getFormatter(
{ localType: "date-time" },
undefined,
{ dateFormats }
);
const timeFormatter = getFormatter({ localType: "time" }, undefined, {
dateFormats
});
expect(typeof dateFormatter).toBe("function");
expect(dateFormatter()).toBe(null);
expect(dateFormatter({value: '2015-02-01T12:45:00Z'})).toBe('2015');
expect(dateFormatter({ value: "2015-02-01T12:45:00Z" })).toBe("2015");
expect(typeof dateTimeFormatter).toBe("function");
expect(dateTimeFormatter()).toBe(null);
expect(dateTimeFormatter({value: '2015-02-01Z'})).toBe('2015 01');
expect(dateTimeFormatter({ value: "2015-02-01Z" })).toBe("2015 01");
expect(typeof timeFormatter).toBe("function");
expect(timeFormatter()).toBe(null);
expect(timeFormatter({value: '12:45:00Z'})).toBe('12:45');
expect(timeFormatter({ value: '1970-01-01T02:30:00Z' })).toBe('02:30'); // still able to format time even when found a full date (sometimes GeoServer returns full date instead of time only)
expect(timeFormatter({ value: "12:45:00Z" })).toBe("12:45");
expect(timeFormatter({ value: "1970-01-01T02:30:00Z" })).toBe("02:30"); // still able to format time even when found a full date (sometimes GeoServer returns full date instead of time only)
});

it("test getFormatter for invalid date-time YYYY-MM-DD[Z]", () => {
const dateFormats = {
"date-time": "YYYY-MM-DD[Z]"
};
const dateTimeWithZFormatter = getFormatter(
{ localType: "date-time" },
undefined,
{ dateFormats }
);
expect(typeof dateTimeWithZFormatter).toBe("function");
expect(dateTimeWithZFormatter({ value: "2015-02-01Z" })).toBe(
"2015-02-01Z"
);
expect(dateTimeWithZFormatter({ value: "2015-02-01" })).toBe(
"2015-02-01Z"
);
expect(dateTimeWithZFormatter({ value: "2015/02/01" })).toBe(
"2015-02-01Z"
);
expect(dateTimeWithZFormatter({ value: "2015/02/01 03:20:10" })).toBe(
"2015-02-01Z"
);
expect(dateTimeWithZFormatter({ value: "2015-02-01T12:45:00Z"})).toBe('2015-02-01Z');
});
});
5 changes: 4 additions & 1 deletion web/client/components/data/featuregrid/formatters/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@ const StringFormatter = ({value} = {}) => !isNil(value) ? reactStringReplace(val
)) : null;
const NumberFormatter = ({value} = {}) => !isNil(value) ? <NumberFormat value={value} numberParams={{maximumFractionDigits: 17}}/> : null;
const DEFAULT_DATE_PART = "1970-01-01";
const DATE_INPUT_FORAMAT = "YYYY-MM-DD[Z]";
const dateTimeFormatter = ({value, format, type}) => {
return !isNil(value)
? moment.utc(value).isValid() // geoserver sometimes returns UTC for time.
? moment.utc(value).format(format)
: type === 'time'
? moment(`${DEFAULT_DATE_PART}T${value}`).utc().format(format) // time format append default date part
: moment(value).format(format) // date or date-time formats
: type === "date" && value?.toLowerCase()?.endsWith("z") // in case: date format and value ends with z
? moment(value, DATE_INPUT_FORAMAT).format(format)
: moment(value).format(format)
: null;
};
export const register = {};
Expand Down
2 changes: 1 addition & 1 deletion web/client/components/map/cesium/Map.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,7 @@ class CesiumMap extends React.Component {
roll: this.map.camera.roll
}
},
getResolutions()[zoom]
getResolutions()[Math.round(zoom)]
);
};

Expand Down
6 changes: 3 additions & 3 deletions web/client/components/map/cesium/plugins/ThreeDTilesLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ function getStyle({ style }) {
function updateModelMatrix(tileSet, { heightOffset }) {
if (!isNaN(heightOffset) && isNumber(heightOffset)) {
const boundingSphere = tileSet.boundingSphere;
const cartographic = Cesium.Cartographic.fromCartesian(boundingSphere.center);
const surface = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, 0.0);
const offset = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, heightOffset);
const cartographic = Cesium.Cartographic.fromCartesian(boundingSphere.center); // undefined if the cartesian is at the center of the ellipsoid
const surface = Cesium.Cartesian3.fromRadians(cartographic?.longitude || 0, cartographic?.latitude || 0, 0.0);
const offset = Cesium.Cartesian3.fromRadians(cartographic?.longitude || 0, cartographic?.latitude || 0, heightOffset);
const translation = Cesium.Cartesian3.subtract(offset, surface, new Cesium.Cartesian3());
tileSet.modelMatrix = Cesium.Matrix4.fromTranslation(translation);
}
Expand Down
5 changes: 3 additions & 2 deletions web/client/components/map/leaflet/Layer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,9 @@ class LeafletLayer extends React.Component {
maxResolution = Infinity,
disableResolutionLimits
} = options || {};
if (!disableResolutionLimits && !isNil(resolutions[zoom])) {
const resolution = resolutions[zoom];
const zoomRound = Math.round(zoom);
if (!disableResolutionLimits && !isNil(resolutions[zoomRound])) {
const resolution = resolutions[zoomRound];
// use similar approach of ol
// maxResolution is exclusive
// minResolution is inclusive
Expand Down
2 changes: 1 addition & 1 deletion web/client/components/map/leaflet/Map.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ class LeafletMap extends React.Component {
this.props.id,
this.props.projection,
viewerOptions, // viewerOptions
this.getResolutions()[zoom] // resolution
this.getResolutions()[Math.round(zoom)] // resolution
);
};

Expand Down
7 changes: 6 additions & 1 deletion web/client/components/map/openlayers/Map.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,12 @@ class OpenlayersMap extends React.Component {
projection: normalizeSRS(projection),
center: [center.x, center.y],
zoom: zoom,
minZoom: limits.minZoom
minZoom: limits.minZoom,
// allow to zoom to level 0 and see world wrapping
multiWorld: true,
// does not allow intermediary zoom levels
// we need this at true to set correctly the scale box
constrainResolution: true
}, newOptions || {});
return new View(viewOptions);
};
Expand Down
Loading

0 comments on commit cfe5537

Please sign in to comment.