diff --git a/web/client/actions/__tests__/rasterstyler-test.js b/web/client/actions/__tests__/rasterstyler-test.js deleted file mode 100644 index 2abeb2ee40..0000000000 --- a/web/client/actions/__tests__/rasterstyler-test.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -import expect from 'expect'; - -import { - SET_RASTERSTYLE_PARAMETER, - SET_RASTER_LAYER, - setRasterStyleParameter, - setRasterLayer -} from '../rasterstyler'; - -describe('Test correctness of the rasterstyle actions', () => { - - it('setRasterStyleParameter', () => { - const retVal = setRasterStyleParameter('cmp', 'property', 'val'); - expect(retVal).toExist(); - expect(retVal.type).toBe(SET_RASTERSTYLE_PARAMETER); - expect(retVal.component).toBe('cmp'); - expect(retVal.property).toBe('property'); - expect(retVal.value).toBe('val'); - }); - it('setRasterLayer', () => { - const retVal = setRasterLayer('layer'); - expect(retVal).toExist(); - expect(retVal.type).toBe(SET_RASTER_LAYER); - expect(retVal.layer).toBe('layer'); - }); -}); diff --git a/web/client/actions/__tests__/styler-test.js b/web/client/actions/__tests__/styler-test.js deleted file mode 100644 index f4565831de..0000000000 --- a/web/client/actions/__tests__/styler-test.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright 20167, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -import expect from 'expect'; - -import { STYLER_RESET, SET_STYLER_LAYER, setStylerLayer, reset } from '../styler'; - -describe('Test correctness of the rasterstyle actions', () => { - - it('setStylerLayer', () => { - const layer = {name: "TEST"}; - const retVal = setStylerLayer(layer); - expect(retVal).toExist(); - expect(retVal.type).toBe(SET_STYLER_LAYER); - expect(retVal.layer).toBe(layer); - }); - it('setRasterLayer', () => { - const layer = {name: "TEST"}; - const retVal = reset(layer); - expect(retVal).toExist(); - expect(retVal.type).toBe(STYLER_RESET); - expect(retVal.layer).toBe(layer); - }); -}); diff --git a/web/client/actions/rasterstyler.js b/web/client/actions/rasterstyler.js deleted file mode 100644 index cbca1700c1..0000000000 --- a/web/client/actions/rasterstyler.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -export const SET_RASTERSTYLE_PARAMETER = 'SET_RASTERSTYLE_PARAMETER'; -export const SET_RASTER_LAYER = 'SET_RASTER_LAYER'; - -export function setRasterStyleParameter(component, property, value) { - return { - type: SET_RASTERSTYLE_PARAMETER, - component, - property, - value - }; -} -export function setRasterLayer(layer) { - return { - type: SET_RASTER_LAYER, - layer - }; -} diff --git a/web/client/actions/styler.js b/web/client/actions/styler.js deleted file mode 100644 index 673f4dbd2a..0000000000 --- a/web/client/actions/styler.js +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -export const STYLE_SAVED = 'STYLER_STYLE_SAVED'; -export const SET_STYLER_LAYER = 'SET_STYLER_LAYER'; -export const STYLE_SAVE_ERROR = 'STYLE_SAVE_ERROR'; -export const STYLER_RESET = 'STYLER_RESET'; - -import Layers from '../api/geoserver/Layers'; -import { saveStyle } from '../api/geoserver/Styles'; - -export function setStylerLayer(layer) { - return { - type: SET_STYLER_LAYER, - layer - }; -} -export function styleSaved(name, style) { - return { - type: STYLE_SAVED, - name, - style - }; -} -export function styleSaveError(layer, style, error) { - return { - type: STYLE_SAVE_ERROR, - layer, - style, - error - }; -} -export function reset(layer) { - return { - type: STYLER_RESET, - layer - }; -} -export function saveLayerDefaultStyle(geoserverBaseUrl, layerName, style) { - return (dispatch) => { - return Layers.getLayer(geoserverBaseUrl, layerName).then((layer) => { - saveStyle(geoserverBaseUrl, layer.defaultStyle && layer.defaultStyle.name, style).then(()=> { - dispatch(styleSaved(layer.defaultStyle.name, style)); - }).catch((e) => {styleSaveError(layerName, layer.defaultStyle, e); }); - - }).catch((e) => {styleSaveError(layerName, null, e); }); - - }; -} diff --git a/web/client/actions/vectorstyler.js b/web/client/actions/vectorstyler.js deleted file mode 100644 index 44bea603ee..0000000000 --- a/web/client/actions/vectorstyler.js +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ -import uuid from 'uuid'; - -export const SET_VECTOR_RULE_PARAMETER = 'SET_VECTOR_RULE_PARAMETER'; -export const NEW_VECTOR_RULE = 'NEW_VECTOR_RULE'; -export const REMOVE_VECTOR_RULE = 'REMOVE_VECTOR_RULE'; -export const SELECT_VECTOR_RULE = 'SELECT_VECTOR_RULE'; -export const SET_VECTORSTYLE_PARAMETER = 'SET_VECTORSTYLE_PARAMETER'; -export const SET_VECTOR_LAYER = 'SET_VECTOR_LAYER'; - -export function setVectorStyleParameter(component, property, value) { - return { - type: SET_VECTORSTYLE_PARAMETER, - component, - property, - value - }; -} -export function setVectorRuleParameter(property, value) { - return { - type: SET_VECTOR_RULE_PARAMETER, - property, - value - }; -} -export function setVectorLayer(layer) { - return { - type: SET_VECTOR_LAYER, - layer - }; -} -export function newVectorRule() { - return { - type: NEW_VECTOR_RULE, - id: uuid.v1() - }; -} -export function removeVectorRule(id) { - return { - type: REMOVE_VECTOR_RULE, - id - }; -} -export function selectVectorRule(id) { - return { - type: SELECT_VECTOR_RULE, - id - }; -} diff --git a/web/client/api/WFS3.js b/web/client/api/WFS3.js deleted file mode 100644 index b3d5aff87d..0000000000 --- a/web/client/api/WFS3.js +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2019, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -import axios from 'axios'; -import head from 'lodash/head'; -import isString from 'lodash/isString'; -import ConfigUtils from '../utils/ConfigUtils'; - -const capabilitiesCache = {}; - -const collectionToLayer = (collection) => { - const { name, title, extent, links } = collection; - const spatial = extent && extent.spatial || [-180, -90, 180, 90]; - const { href: layerUrl, type: format } = head((links || []).filter(({ rel }) => rel === 'tiles')) || {}; - const { href: tilingSchemes } = head((links || []).filter(({ rel }) => rel === 'tilingSchemes')) || {}; - const { href: tilingScheme } = head((links || []).filter(({ rel }) => rel === 'tilingScheme')) || {}; - return { - name, - title, - type: 'wfs3', - visibility: true, - url: layerUrl, - format, - tilingScheme, - tilingSchemes, - bbox: { - crs: 'EPSG:4326', - bounds: { - minx: spatial[0], - miny: spatial[1], - maxx: spatial[2], - maxy: spatial[3] - } - } - }; -}; - -const searchAndPaginate = (json = {}, startPosition, maxRecords, text, url) => { - const { collections } = json; - const filteredLayers = collections - .filter((layer = {}) => !text - || layer.name && layer.name.toLowerCase().indexOf(text.toLowerCase()) !== -1 - || layer.title && layer.title.toLowerCase().indexOf(text.toLowerCase()) !== -1); - return { - numberOfRecordsMatched: filteredLayers.length, - numberOfRecordsReturned: Math.min(maxRecords, filteredLayers.length), - nextRecord: startPosition + Math.min(maxRecords, filteredLayers.length) + 1, - records: filteredLayers - .filter((layer, index) => index >= startPosition - 1 && index < startPosition - 1 + maxRecords) - .map((collection) => ({ - ...collection, - ...collectionToLayer(collection), - capabilitiesUrl: url - })) - }; -}; - -const parseUrl = function(url) { - const serviceUrl = (url || '').split(/\/wfs3\//)[0]; - return `${serviceUrl}/wfs3/collections`; -}; - -export const getRecords = function(url, startPosition, maxRecords, text) { - const cached = capabilitiesCache[url]; - if (cached && new Date().getTime() < cached.timestamp + (ConfigUtils.getConfigProp('cacheExpire') || 60) * 1000) { - return new Promise((resolve) => { - resolve(searchAndPaginate(cached.data, startPosition, maxRecords, text, url)); - }); - } - return axios.get(parseUrl(url)) - .then(({ data }) => { - capabilitiesCache[url] = { - timestamp: new Date().getTime(), - data - }; - return searchAndPaginate(data, startPosition, maxRecords, text, url); - }); -}; - -export const textSearch = function(url, startPosition, maxRecords, text) { - return getRecords(url, startPosition, maxRecords, text); -}; - -export const getTilingSchemes = (layer) => { - const { tilingSchemes, tilingScheme } = layer; - if (isString(tilingSchemes)) { - return axios.get(tilingSchemes) - .then(({ data }) => { - return data && data.tilingSchemes && data.tilingSchemes.length > 0 - ? axios.all( - data.tilingSchemes.map((tilingSchemeId) => - axios.get(tilingScheme.replace('{tilingSchemeId}', tilingSchemeId)) - .then(({ data: scheme }) => scheme) - .catch(() => null) - ) - ) - .then((schemes) => ({ - tilingSchemes: { - url: tilingSchemes, - schemes: schemes.filter(scheme => scheme) - }, - allowedSRS: schemes - .filter(scheme => scheme) - .reduce((acc, { supportedCRS }) => { - return { - ...acc, - [supportedCRS]: true - }; - }, {}) - })) - : { - tilingSchemes: { - url: tilingSchemes, - schemes: null - }, - allowedSRS: {} - }; - }); - } - return new Promise((resolve) => resolve(tilingSchemes)); -}; - -export const getLayerFromId = (serviceUrl, collectionId) => { - return axios.get(`${parseUrl(serviceUrl)}/${collectionId}`) - .then(({ data: collection }) => { - const layer = collectionToLayer(collection); - return getTilingSchemes(layer) - .then((params) => ({ - ...layer, - ...params - })); - }); -}; - -export const reset = () => { - Object.keys(capabilitiesCache).forEach(key => { - delete capabilitiesCache[key]; - }); -}; diff --git a/web/client/api/__tests__/WFS3-test.js b/web/client/api/__tests__/WFS3-test.js deleted file mode 100644 index c3b28b5ba3..0000000000 --- a/web/client/api/__tests__/WFS3-test.js +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright 2019, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -import expect from 'expect'; -import { - getTilingSchemes, - getLayerFromId, - textSearch, - reset -} from '../WFS3'; -import MockAdapter from 'axios-mock-adapter'; -import axios from '../../libs/ajax'; - -let mockAxios; - -describe('Test WFS3 API', () => { - - beforeEach(done => { - mockAxios = new MockAdapter(axios); - setTimeout(done); - }); - - afterEach(done => { - mockAxios.restore(); - setTimeout(done); - reset(); - }); - - it('test getTilingSchemes', (done) => { - - const TILING_SCHEMES_URL = '/geoserver/wfs3/collections/layer_name/tiles'; - const TILING_SCHEMES_ID = 'GoogleMapsCompatible'; - const TILING_SCHEME = { - type: 'TileMatrixSet', - identifier: 'GoogleMapsCompatible', - title: 'GoogleMapsCompatible', - supportedCRS: 'EPSG:3857', - tileMatrix: [{ - matrixHeight: 1, - matrixWidth: 1, - tileHeight: 256, - tileWidth: 256, - identifier: '0', - scaleDenominator: 559082263.9508929, - topLeftCorner: [ - -20037508.34, - 20037508 - ], - type: 'TileMatrix' - }], - boundingBox: { - crs: 'http://www.opengis.net/def/crs/EPSG/0/3857', - lowerCorner: [ - -20037508.34, - -20037508.34 - ], - upperCorner: [ - 20037508.34, - 20037508.34 - ], - type: 'BoundingBox' - }, - wellKnownScaleSet: 'http://www.opengis.net/def/wkss/OGC/1.0/GoogleMapsCompatible' - }; - - mockAxios.onGet(TILING_SCHEMES_URL).reply(() => { - return [ 200, { tilingSchemes: [ TILING_SCHEMES_ID ] }]; - }); - - mockAxios.onGet(`${TILING_SCHEMES_URL}/${TILING_SCHEMES_ID}`).reply(() => { - return [ 200, TILING_SCHEME]; - }); - - const layer = { - tilingScheme: `${TILING_SCHEMES_URL}/{tilingSchemeId}`, - tilingSchemes: TILING_SCHEMES_URL - }; - - getTilingSchemes(layer) - .then(({ tilingSchemes, allowedSRS }) => { - expect(allowedSRS).toEqual({ 'EPSG:3857': true }); - expect(tilingSchemes).toEqual({ - url: TILING_SCHEMES_URL, - schemes: [ TILING_SCHEME ] - }); - done(); - }); - }); - - it('test getLayerFromId', (done) => { - const SERVICE_URL = '/geoserver/wfs3/collections/'; - const COLLECTIONS_ID = 'layer_name'; - const TILING_SCHEMES_URL = '/geoserver/wfs3/collections/layer_name/tiles'; - const TILING_SCHEMES_ID = 'GoogleMapsCompatible'; - const COLLECTION = { - name: COLLECTIONS_ID, - title: 'Layer Title', - extent: { - spatial: [-180, -90, 180, 90] - }, - links: [ - { - href: '/geoserver/wfs3/collections/layer_name/tiles/{tilingSchemeId}/{level}/{row}/{col}', - rel: 'tiles', - type: 'application/vnd.mapbox-vector-tile' - }, - { - href: '/geoserver/wfs3/collections/layer_name/tiles/{tilingSchemeId}', - rel: 'tilingScheme', - type: 'application/json', - title: '...' - }, - { - href: TILING_SCHEMES_URL, - rel: 'tilingSchemes', - type: 'application/json', - title: '...' - } - ] - }; - - const TILING_SCHEME = { - type: 'TileMatrixSet', - identifier: 'GoogleMapsCompatible', - title: 'GoogleMapsCompatible', - supportedCRS: 'EPSG:3857', - tileMatrix: [{ - matrixHeight: 1, - matrixWidth: 1, - tileHeight: 256, - tileWidth: 256, - identifier: '0', - scaleDenominator: 559082263.9508929, - topLeftCorner: [ - -20037508.34, - 20037508 - ], - type: 'TileMatrix' - }], - boundingBox: { - crs: 'http://www.opengis.net/def/crs/EPSG/0/3857', - lowerCorner: [ - -20037508.34, - -20037508.34 - ], - upperCorner: [ - 20037508.34, - 20037508.34 - ], - type: 'BoundingBox' - }, - wellKnownScaleSet: 'http://www.opengis.net/def/wkss/OGC/1.0/GoogleMapsCompatible' - }; - - mockAxios.onGet(`${SERVICE_URL}${COLLECTIONS_ID}`).reply(() => { - return [ 200, COLLECTION]; - }); - - mockAxios.onGet(TILING_SCHEMES_URL).reply(() => { - return [ 200, { tilingSchemes: [ TILING_SCHEMES_ID ] }]; - }); - - mockAxios.onGet(`${TILING_SCHEMES_URL}/${TILING_SCHEMES_ID}`).reply(() => { - return [ 200, TILING_SCHEME]; - }); - - getLayerFromId(SERVICE_URL, COLLECTIONS_ID) - .then((layer) => { - expect(layer).toEqual({ - name: COLLECTIONS_ID, - title: 'Layer Title', - type: 'wfs3', - visibility: true, - url: '/geoserver/wfs3/collections/layer_name/tiles/{tilingSchemeId}/{level}/{row}/{col}', - format: 'application/vnd.mapbox-vector-tile', - tilingScheme: '/geoserver/wfs3/collections/layer_name/tiles/{tilingSchemeId}', - tilingSchemes: { - url: TILING_SCHEMES_URL, - schemes: [ TILING_SCHEME ] - }, - allowedSRS: { 'EPSG:3857': true }, - bbox: { - crs: 'EPSG:4326', - bounds: { - minx: -180, - miny: -90, - maxx: 180, - maxy: 90 - } - }}); - done(); - }); - }); - it('test textSearch', (done) => { - const TILING_SCHEMES_URL = '/geoserver/wfs3/collections'; - const START_POSITION = 1; - const MAX_RECORDS = 1; - const TEXT = ''; - const COLLECTIONS = [ - { - name: 'layer_name_01', - title: 'layer title 01', - extent: { - spatial: [-180, -90, 180, 90] - }, - links: [] - }, - { - name: 'layer_name_02', - title: 'layer title 02', - extent: { - spatial: [-180, -90, 180, 90] - }, - links: [] - } - ]; - - mockAxios.onGet(TILING_SCHEMES_URL) - .reply(() => { - return [ 200, { collections: COLLECTIONS }]; - }); - textSearch(TILING_SCHEMES_URL, START_POSITION, MAX_RECORDS, TEXT) - .then((res) => { - expect(res).toEqual({ - numberOfRecordsMatched: 2, - numberOfRecordsReturned: 1, - nextRecord: 3, - records: [{ - name: 'layer_name_01', - title: 'layer title 01', - extent: { spatial: [ -180, -90, 180, 90 ] }, - links: [], - type: 'wfs3', - visibility: true, - url: undefined, - format: undefined, - tilingScheme: undefined, - tilingSchemes: undefined, - bbox: { crs: 'EPSG:4326', bounds: { minx: -180, miny: -90, maxx: 180, maxy: 90 } }, - capabilitiesUrl: '/geoserver/wfs3/collections' - }] - }); - done(); - }); - }); -}); - diff --git a/web/client/components/map/leaflet/FeatureCollection.jsx b/web/client/components/map/leaflet/FeatureCollection.jsx deleted file mode 100644 index 2017a56782..0000000000 --- a/web/client/components/map/leaflet/FeatureCollection.jsx +++ /dev/null @@ -1,31 +0,0 @@ -var PropTypes = require('prop-types'); -/** - * Copyright 2015, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -var React = require('react'); - - -class Feature extends React.Component { - static propTypes = { - type: PropTypes.string, - container: PropTypes.object, // TODO it must be a L.GeoJSON - geometry: PropTypes.object - }; - - componentDidMount() { - } - - componentWillUnmount() { - } - - render() { - return null; - } -} - -module.exports = Feature; diff --git a/web/client/components/map/openlayers/__tests__/Layer-test.jsx b/web/client/components/map/openlayers/__tests__/Layer-test.jsx index 00886485a3..e6f8a26af4 100644 --- a/web/client/components/map/openlayers/__tests__/Layer-test.jsx +++ b/web/client/components/map/openlayers/__tests__/Layer-test.jsx @@ -23,7 +23,6 @@ import '../plugins/GraticuleLayer'; import '../plugins/OverlayLayer'; import '../plugins/TMSLayer'; import '../plugins/WFSLayer'; -import '../plugins/WFS3Layer'; import '../plugins/ElevationLayer'; import '../plugins/ArcGISLayer'; @@ -2878,78 +2877,6 @@ describe('Openlayers layer', () => { expect(layer.layer.getSource()).toBeTruthy(); }); - it('test render a wfs3 layer', () => { - - const options = { - id: 'layer_id', - name: 'layer_name', - title: 'Layer Title', - type: 'wfs3', - visibility: true, - url: '/geoserver/wfs3/collections/layer_name/tiles/{tilingSchemeId}/{level}/{row}/{col}', - format: 'application/vnd.mapbox-vector-tile', - tilingScheme: '/geoserver/wfs3/collections/layer_name/tiles/{tilingSchemeId}', - tilingSchemes: { - url: '/geoserver/wfs3/collections/layer_name/tiles', - schemes: [ - { - type: 'TileMatrixSet', - identifier: 'GoogleMapsCompatible', - title: 'GoogleMapsCompatible', - supportedCRS: 'EPSG:3857', - tileMatrix: [{ - matrixHeight: 1, - matrixWidth: 1, - tileHeight: 256, - tileWidth: 256, - identifier: '0', - scaleDenominator: 559082263.9508929, - topLeftCorner: [ - -20037508.34, - 20037508 - ], - type: 'TileMatrix' - }], - boundingBox: { - crs: 'http://www.opengis.net/def/crs/EPSG/0/3857', - lowerCorner: [ - -20037508.34, - -20037508.34 - ], - upperCorner: [ - 20037508.34, - 20037508.34 - ], - type: 'BoundingBox' - }, - wellKnownScaleSet: 'http://www.opengis.net/def/wkss/OGC/1.0/GoogleMapsCompatible' - } - ] - }, - bbox: { - crs: 'EPSG:4326', - bounds: { - minx: -156.2575, - miny: -90, - maxx: 123.33333333333333, - maxy: 46.5475 - } - }, - allowedSRS: { - 'EPSG:3857': true - } - }; - let layer = ReactDOM.render(, document.getElementById("container")); - - expect(layer).toBeTruthy(); - expect(map.getLayers().getLength()).toBe(1); - expect(layer.layer.constructor.name).toBe('VectorTileLayer'); - expect(layer.layer.getSource().format_.constructor.name).toBe('MVT'); - }); - it('should apply native ol min and max resolution on wms layer', () => { const minResolution = 1222; // ~ zoom 7 Web Mercator const maxResolution = 39135; // ~ zoom 2 Web Mercator diff --git a/web/client/components/map/openlayers/plugins/WFS3Layer.js b/web/client/components/map/openlayers/plugins/WFS3Layer.js deleted file mode 100644 index fa1aec492c..0000000000 --- a/web/client/components/map/openlayers/plugins/WFS3Layer.js +++ /dev/null @@ -1,136 +0,0 @@ -/** - * Copyright 2018, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -import head from 'lodash/head'; -import urlParser from 'url'; - -import CoordinatesUtils from '../../../../utils/CoordinatesUtils'; -import MapUtils from '../../../../utils/MapUtils'; -import Layers from '../../../../utils/openlayers/Layers'; -import {addAuthenticationParameter} from '../../../../utils/SecurityUtils'; - -import {get, getTransform} from 'ol/proj'; -import {applyTransform} from 'ol/extent'; -import TileGrid from 'ol/tilegrid/TileGrid'; -import VectorTileLayer from 'ol/layer/VectorTile'; -import VectorTile from 'ol/source/VectorTile'; -import MVT from 'ol/format/MVT'; - -import { isVectorFormat } from '../../../../utils/VectorTileUtils'; -import { OL_VECTOR_FORMATS, applyStyle } from '../../../../utils/openlayers/VectorTileUtils'; - -const createLayer = (options) => { - - const srs = CoordinatesUtils.normalizeSRS(options.srs || 'EPSG:3857', options.allowedSRS); - const projection = get(srs); - const metersPerUnit = projection.getMetersPerUnit(); - - const tilingScheme = head(options.tilingSchemes - && options.tilingSchemes.schemes - && options.tilingSchemes.schemes.filter(({ supportedCRS }) => supportedCRS === srs)); - - const { identifier: tilingSchemeId, tileMatrix, boundingBox } = tilingScheme || {}; - const scales = tileMatrix && tileMatrix.map(({ scaleDenominator }) => scaleDenominator); - const mapResolutions = MapUtils.getResolutions(); - - const scaleToResolution = s => s * 0.28E-3 / metersPerUnit; - const matrixResolutions = options.resolutions || scales && scales.map(scaleToResolution); - const resolutions = matrixResolutions || mapResolutions; - - const switchOriginXY = projection.getAxisOrientation().substr(0, 2) === 'ne'; - const origins = tileMatrix && tileMatrix - .map(({ topLeftCorner } = {}) => topLeftCorner) - .map(([ x, y ] = []) => switchOriginXY ? [y, x] : [x, y]); - - const tileSizes = tileMatrix && tileMatrix - .map(({tileWidth, tileHeight}) => [tileWidth, tileHeight]); - - const bbox = options.bbox; - - const extent = bbox - ? applyTransform([ - parseFloat(bbox.bounds.minx), - parseFloat(bbox.bounds.miny), - parseFloat(bbox.bounds.maxx), - parseFloat(bbox.bounds.maxy) - ], getTransform(bbox.crs, options.srs)) - : null; - - const tileGridExtent = boundingBox && boundingBox.lowerCorner && boundingBox.upperCorner - ? [ - ...boundingBox.lowerCorner, - ...boundingBox.upperCorner - ] - : null; - - const tileGrid = new TileGrid({ - extent: tileGridExtent, - minZoom: 0, - origins, - origin: !origins ? [20037508.3428, -20037508.3428] : undefined, - resolutions, - tileSizes, - tileSize: !tileSizes ? [256, 256] : undefined - }); - - let url = (options.url || '') - .replace(/\{tilingSchemeId\}/, tilingSchemeId) - .replace(/\{level\}/, '{z}') - .replace(/\{row\}/, '{y}') - .replace(/\{col\}/, '{x}'); - - let queryParameters = { }; - addAuthenticationParameter(url, queryParameters, options.securityToken); - - const layerUrl = decodeURI(url); - const queryParametersString = urlParser.format({ query: { ...queryParameters } }); - - const Format = isVectorFormat(options.format) && OL_VECTOR_FORMATS[options.format] || MVT; - - const source = new VectorTile({ - format: new Format({ - dataProjection: srs, - layerName: '_layer_' - }), - tileGrid, - url: layerUrl + queryParametersString - }); - - const layer = new VectorTileLayer({ - extent, - msId: options.id, - source: source, - visible: options.visibility !== false, - zIndex: options.zIndex, - minResolution: options.minResolution, - maxResolution: options.maxResolution - }); - - applyStyle(options.vectorStyle, layer); - - return layer; -}; -Layers.registerType('wfs3', { - create: createLayer, - update: (layer, newOptions, oldOptions) => { - if (oldOptions.securityToken !== newOptions.securityToken - || oldOptions.srs !== newOptions.srs) { - return createLayer(newOptions); - } - if (oldOptions.minResolution !== newOptions.minResolution) { - layer.setMinResolution(newOptions.minResolution === undefined ? 0 : newOptions.minResolution); - } - if (oldOptions.maxResolution !== newOptions.maxResolution) { - layer.setMaxResolution(newOptions.maxResolution === undefined ? Infinity : newOptions.maxResolution); - } - return null; - }, - render: () => { - return null; - } -}); diff --git a/web/client/components/map/openlayers/plugins/index.js b/web/client/components/map/openlayers/plugins/index.js index 028fd239f3..5fc479405d 100644 --- a/web/client/components/map/openlayers/plugins/index.js +++ b/web/client/components/map/openlayers/plugins/index.js @@ -17,7 +17,6 @@ export default { TileProviderLayer: require('./TileProviderLayer').default, VectorLayer: require('./VectorLayer').default, WFSLayer: require('./WFSLayer').default, - WFS3Layer: require('./WFS3Layer').default, WMSLayer: require('./WMSLayer').default, WMTSLayer: require('./WMTSLayer').default, COGLayer: require('./COGLayer').default, diff --git a/web/client/components/mapcontrols/annotations/Annotations.jsx b/web/client/components/mapcontrols/annotations/Annotations.jsx deleted file mode 100644 index e9e0d60591..0000000000 --- a/web/client/components/mapcontrols/annotations/Annotations.jsx +++ /dev/null @@ -1,429 +0,0 @@ -/* - * Copyright 2017, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -import bbox from '@turf/bbox'; -import { countBy, head, isUndefined, keys, values } from 'lodash'; -import assign from 'object-assign'; -import PropTypes from 'prop-types'; -import React from 'react'; -import { Glyphicon } from 'react-bootstrap'; -import uuidv1 from 'uuid/v1'; - -import { getGeometryGlyphInfo } from '../../../utils/LegacyAnnotationsUtils'; -import { getMessageById } from '../../../utils/LocaleUtils'; -import Message from '../../I18N/Message'; -import BorderLayout from '../../layout/BorderLayout'; -import SideGrid from '../../misc/cardgrids/SideGrid'; -import Filter from '../../misc/Filter'; -import Loader from '../../misc/Loader'; -import Toolbar from '../../misc/toolbar/Toolbar'; -import defaultConfig from './AnnotationsConfig'; -import SelectAnnotationsFile from './SelectAnnotationsFile'; -import Button from '../../misc/Button'; - -/** - * Annotations panel component. - * It can be in different modes: - * - list: when showing the current list of annotations on the map - * - detail: when showing a detail of a specific annotation - * - editing: when editing an annotation - * When in list mode, the list of current map annotations is shown, with: - * - summary card for each annotation, with full detail show on click - * - upload annotations Button - * - new annotation Button - * - download annotations Button - * - filtering widget - * When in detail mode the configured editor is shown on the selected annotation, in viewer mode. - * When in editing mode the configured editor is shown on the selected annotation, in editing mode. - * - * It also handles removal confirmation modals - * @memberof components.mapControls.annotations - * @class - * @prop {string} id id of the borderlayout Component - * @prop {boolean} closing user asked for closing panel when editing - * @prop {boolean} styling flag to state status of styling during editing - * @prop {boolean} showUnsavedChangesModal flag to state status of UnsavedChangesModal - * @prop {boolean} showUnsavedStyleModal flag to state status of UnsavedStyleModal - * @prop {object} editing annotation object currently under editing (null if we are not in editing mode) - * @prop {function} toggleControl triggered when the user closes the annotations panel - * @prop {object} removing object to remove, it is also a flag that means we are currently asking for removing an annotation / geometry. Toggles visibility of the confirm dialog - * @prop {string} mode current mode of operation (list, editing, detail) - * @prop {object} editor editor component, used in detail and editing modes - * @prop {object[]} annotations list of annotations objects to list - * @prop {string} current id of the annotation currently shown in the editor (when not in list mode) - * @prop {object} config configuration object, where overridable stuff is stored (fields config for annotations, marker library, etc.) {@link #components.mapControls.annotations.AnnotationsConfig} - * @prop {string} filter current filter entered by the user - * @prop {function} onToggleUnsavedChangesModal toggles the view of the UnsavedChangesModal - * @prop {function} onToggleUnsavedStyleModal toggles the view of the UnsavedStyleModal - * @prop {function} onCancelRemove triggered when the user cancels removal - * @prop {function} onCancelEdit triggered when the user cancels any changes to the properties or geometry - * @prop {function} onCancelStyle triggered when the user cancels any changes to the style - * @prop {function} onConfirmRemove triggered when the user confirms removal - * @prop {function} onCancelClose triggered when the user cancels closing - * @prop {function} onConfirmClose triggered when the user confirms closing - * @prop {function} onAdd triggered when the user clicks on the new annotation button - * @prop {function} onEdit triggered when the user clicks on the annotation card into annotation viewer - * @prop {function} onZoom triggered when the user zooms to an annotation - * @prop {function} onHighlight triggered when the mouse hovers an annotation card - * @prop {function} onCleanHighlight triggered when the mouse is out of any annotation card - * @prop {function} onDetail triggered when the user clicks on an annotation card - * @prop {function} onFilter triggered when the user enters some text in the filtering widget - * @prop {function} classNameSelector optional selector to assign custom a CSS class to annotations, based on - * @prop {function} onSetErrorSymbol set a flag in the state to say if the default symbols exists - * @prop {function} onDownload triggered when the user clicks on the download annotations button - * @prop {function} onUpdateSymbols triggered when user click on refresh icon of the symbols addon - * @prop {function} onToggleVisibility triggered when user click on annotation visibility icon - * @prop {boolean} symbolErrors errors related to the symbols - * @prop {object[]} lineDashOptions list of options for dashed lines - * @prop {string} symbolsPath path to the svg folder - * @prop {object[]} symbolList list of symbols - * @prop {string} defaultShape default Shape - * @prop {number} maxZoom max zoom for annotation (default 18) - * @prop {string} defaultShapeStrokeColor default symbol stroke color - * @prop {string} defaultShapeFillColor default symbol fill color - * @prop {string} defaultShapeSize default symbol shape size in px - * @prop {object} defaultStyles object with default symbol styles - * @prop {number} textRotationStep rotation step of text styler - * @prop {boolean} geodesic draw geodesic annotation (Currently applicable only for Circle annotation) - * - * the annotation's attributes. - */ -class Annotations extends React.Component { - static propTypes = { - id: PropTypes.string, - styling: PropTypes.bool, - toggleControl: PropTypes.func, - loading: PropTypes.bool, - closing: PropTypes.bool, - showUnsavedChangesModal: PropTypes.bool, - showUnsavedStyleModal: PropTypes.bool, - editing: PropTypes.object, - removing: PropTypes.object, - onCancelRemove: PropTypes.func, - onConfirmRemove: PropTypes.func, - onCancelClose: PropTypes.func, - onToggleUnsavedChangesModal: PropTypes.func, - onToggleUnsavedStyleModal: PropTypes.func, - onResetCoordEditor: PropTypes.func, - onAddNewFeature: PropTypes.func, - onToggleUnsavedGeometryModal: PropTypes.func, - onConfirmClose: PropTypes.func, - onCancelEdit: PropTypes.func, - onCancelStyle: PropTypes.func, - onAdd: PropTypes.func, - onZoom: PropTypes.func, - onHighlight: PropTypes.func, - onCleanHighlight: PropTypes.func, - onDetail: PropTypes.func, - mode: PropTypes.string, - editor: PropTypes.func, - annotations: PropTypes.array, - current: PropTypes.string, - config: PropTypes.object, - filter: PropTypes.string, - onFilter: PropTypes.func, - classNameSelector: PropTypes.func, - width: PropTypes.number, - onDownload: PropTypes.func, - onLoadAnnotations: PropTypes.func, - onUpdateSymbols: PropTypes.func, - onSetErrorSymbol: PropTypes.func, - onToggleVisibility: PropTypes.func, - onEdit: PropTypes.func, - symbolErrors: PropTypes.array, - lineDashOptions: PropTypes.array, - symbolList: PropTypes.array, - defaultShape: PropTypes.string, - symbolsPath: PropTypes.string, - maxZoom: PropTypes.number, - defaultShapeSize: PropTypes.number, - defaultShapeFillColor: PropTypes.string, - defaultShapeStrokeColor: PropTypes.string, - defaultStyles: PropTypes.object, - onLoadDefaultStyles: PropTypes.func, - textRotationStep: PropTypes.number, - measurementAnnotationEdit: PropTypes.bool, - geodesic: PropTypes.bool - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - mode: 'list', - config: defaultConfig, - classNameSelector: () => '', - toggleControl: () => {}, - onUpdateSymbols: () => {}, - onSetErrorSymbol: () => {}, - onLoadAnnotations: () => {}, - annotations: [], - maxZoom: 18, - onLoadDefaultStyles: () => {} - }; - state = { - selectFile: false - } - - componentDidMount() { - this.props.onLoadDefaultStyles(this.props.defaultShape, this.props.defaultShapeSize, this.props.defaultShapeFillColor, this.props.defaultShapeStrokeColor, - this.props.symbolsPath); - } - - getConfig = () => { - return assign({}, defaultConfig, this.props.config); - }; - - getGeomsThumbnail(geometry) { - let glyph; - const geoms = geometry?.features.reduce((p, c) => { - if (c.properties && c.properties.isCircle) { - return {...p, "Circle": true}; - } - if (c.properties && c.properties.isText) { - return {...p, "Text": true}; - } - return {...p, [c.geometry.type]: true}; - }, {"Circle": false, "Text": false}); - - if (countBy(values(geoms))?.true > 1) { - glyph = "geometry-collection"; - } else { - const type = keys(geoms).find(key => geoms[key] === true); - glyph = getGeometryGlyphInfo(type)?.glyph; - } - - return ; - } - - renderField = (field, annotation) => { - return (
- {this.renderFieldValue(field, annotation)} -
); - }; - - renderFieldValue = (field, annotation) => { - const fieldValue = annotation.properties[field.name] || ''; - if (field.type === 'html') { - // Return the text content of the first child of the html string (to prevent collating all texts into a single word) - return (new DOMParser).parseFromString(fieldValue, "text/html").documentElement.lastElementChild - ?.firstChild - ?.textContent || ''; - } - return fieldValue; - }; - - renderThumbnail = ({featureType, geometry, properties = {}}) => { - if (properties?.type === "Measure") { - return ( - - ); - } else if (featureType === "LineString" || featureType === "MultiLineString" ) { - return ( - ; - ); - } - if (featureType === "Polygon" || featureType === "MultiPolygon" ) { - return ( - ; - ); - } - if (featureType === "Circle") { - return ( - ; - ); - } - if (featureType === "GeometryCollection" || featureType === "FeatureCollection") { - return ( - {(!!(geometry.geometries || geometry.features || []).filter(f => f.type !== "MultiPoint").length || (properties.textValues && properties.textValues.length)) && (this.getGeomsThumbnail(geometry))} - ); - } - return ( - ; - ); - }; - - renderItems = (annotation) => { - const {features: aFeatures, properties} = annotation; - const cardActions = { - onMouseEnter: () => {this.props.onHighlight(properties.id); }, - onMouseLeave: this.props.onCleanHighlight, - onClick: () => this.props.onEdit(properties.id) - }; - const annotationVisibility = properties && !isUndefined(properties.visibility) ? properties.visibility : true; - return { - ...this.getConfig().fields.reduce( (p, c)=> { - return assign({}, p, {[c.name]: this.renderField(c, annotation)}); - }, {}), - preview: this.renderThumbnail({featureType: "FeatureCollection", geometry: {features: aFeatures}, properties }), - tools: { - event.stopPropagation(); - const extent = bbox(annotation); - this.props.onZoom(extent, 'EPSG:4326', this.props.maxZoom); - } - }, - { - glyph: annotationVisibility ? 'eye-open' : 'eye-close', - tooltipId: annotationVisibility ? "annotations.hide" : "annotations.show", - onClick: (event) => { - event.stopPropagation(); - this.props.onToggleVisibility(properties?.id); - } - } - - ]}/>, - ...cardActions - }; - }; - - renderCards = () => { - if (this.props.loading) { - return ( -
- -
- ); - } - if (this.props.mode === 'list') { - const annotationsPresent = !!this.props.annotations.length; - return ( - <> -
- , - visible: this.props.mode === "list", - onClick: () => { this.setState(() => ({selectFile: true})); } - }, - { - glyph: 'plus', - tooltip: , - visible: this.props.mode === "list", - onClick: () => { this.props.onAdd(); } - }, - { - glyph: 'download', - disabled: !(annotationsPresent), - tooltip: , - visible: this.props.mode === "list", - onClick: () => { this.props.onDownload(); } - } - ]}/> -
-
- -
-
- {!annotationsPresent && } - { annotationsPresent && - this.renderItems(a))}/> - } -
- - ); - } - const annotation = this.props.annotations && head(this.props.annotations.filter(a => a.properties.id === this.props.current)); - const Editor = this.props.editor; - if (this.props.mode === 'detail') { - return (); - } - // mode = editing - return this.props.editing && ; - }; - - renderHeader() { - return ( -
-
-
- -
-
-

-
-
- -
-
-
- ); - } - - render() { - let body; - if (this.state.selectFile) { - body = ( - } - onFileChoosen={this.props.onLoadAnnotations} - show={this.state.selectFile} - disableOvveride={!(this.props.annotations && this.props.annotations.length > 0)} - onClose={() => this.setState(() => ({selectFile: false}))} - />); - - - } else { - body = ( {this.renderCards()} ); - } - return ( - {body} - ); - - } - - applyFilter = (annotation) => { - return !this.props.filter || this.getConfig().fields.reduce((previous, field) => { - return (annotation.properties[field.name] || '').toUpperCase().indexOf(this.props.filter.toUpperCase()) !== -1 || previous; - }, false); - }; -} - -export default Annotations; diff --git a/web/client/components/mapcontrols/annotations/AnnotationsConfig.js b/web/client/components/mapcontrols/annotations/AnnotationsConfig.js deleted file mode 100644 index 00ee466e56..0000000000 --- a/web/client/components/mapcontrols/annotations/AnnotationsConfig.js +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2017, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -import MarkerUtils from '../../../utils/MarkerUtils'; - -const defaultIcon = MarkerUtils.markers.extra.icons[0]; -const defaultMarkers = MarkerUtils.markers.extra.getGrid(); -const glyphPrefix = 'fa'; - -/** - * Annotations configuration object. - * Stores overridable configuration. - * - * The default configuration is the following: - * - 2 fields (title and description) - * - extra markers library {@link https://github.com/coryasilva/Leaflet.ExtraMarkers} - * - font awesome glyphs for markers - * - multiGeometry enabled - * - * To (partially) override the configuration use initialState in localConfig.json: - * @example - * Only overrides the list of fields - * { - * ... - * "initialState": { - * "defaultState": { - * "annotations": { - * "config": { - * "fields": [{ - * "name": "myattribute", - * "editable": true - * "validator": "value.indexOf('fake') === -1", - * "validateError": "annotations.error.fake" - * }] - * } - * } - * } - * } - * } - * - * @memberof components.mapControls.annotations - * @class AnnotationsConfig - */ -export default { - /** - * Available annotation fields. - * A list of object specifying: - * - name: the field synthetic name - * - type: type of value for the field (text or html) - * - validator: (optional) rule for validation - * - validationError: (optional) id for the translations file containing the validation error message - * - showLabel: whether to show or not the label of the field in the viewer / editor - * - editable: whether the field can be edited or not in editing mode - */ - fields: [ - { - name: 'title', - type: 'text', - validator: (val) => val, - validateError: 'annotations.mandatory', - showLabel: true, - editable: true - }, - { - name: 'description', - type: 'html', - showLabel: true, - editable: true - } - ], - /** - * Grid of markers used to style annotations. - */ - markers: defaultMarkers, - /** - * Markers icon sprite resource. - */ - markerIcon: defaultIcon, - /** - * Markers used to style annotations configuration object. - */ - markersConfig: MarkerUtils.markers.extra, - /** - * Allow multiGeometry or not (MultiPoint on a single annotation). - */ - multiGeometry: false, - /** - * Available glyphs list (used by the markers styler). - */ - glyphs: Object.keys(MarkerUtils.getGlyphs('fontawesome')), - /** - * Returns a CSS classname usable to draw a glyph for the given style (iconGlyph), - * using the default glyphs library (font-awesome). - * @param {string} style style object - * @return {string} classname to draw the glyph - */ - getGlyphClassName: (style) => { - return glyphPrefix + " " + glyphPrefix + "-" + style.iconGlyph; - }, - /** - * Returns a marker configuration object for the given style, using the default (extra) - * markers library. - * - * @param {string} style style object - * @return {object} marker config object - */ - getMarkerFromStyle: (style) => { - return defaultMarkers.filter(m => m.name === style.iconShape)[0] - .markers.filter(m2 => m2.name === style.iconColor)[0]; - } -}; diff --git a/web/client/components/mapcontrols/annotations/AnnotationsEditor.jsx b/web/client/components/mapcontrols/annotations/AnnotationsEditor.jsx deleted file mode 100644 index 1c9fdc1997..0000000000 --- a/web/client/components/mapcontrols/annotations/AnnotationsEditor.jsx +++ /dev/null @@ -1,900 +0,0 @@ -/* - * Copyright 2018, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. -*/ - -import { head, isEmpty, isFunction, isUndefined } from 'lodash'; -import assign from 'object-assign'; -import PropTypes from 'prop-types'; -import React from 'react'; -import { - Checkbox, - Col, - ControlLabel, - FormControl, - FormGroup, - Glyphicon, - Grid, - Nav, - NavItem, - Row -} from 'react-bootstrap'; -import ReactQuill from '../../../libs/quill/react-quill-suspense'; - -import { - coordToArray, - getComponents, - getGeometryGlyphInfo, - getGeometryType, - validateCoords -} from '../../../utils/LegacyAnnotationsUtils'; -import { MEASURE_TYPE } from '../../../utils/MeasurementUtils'; -import { handleExpression } from '../../../utils/PluginsUtils'; -import Message from '../../I18N/Message'; -import ConfirmDialog from '../../misc/ConfirmDialog'; -import Portal from '../../misc/Portal'; -import Toolbar from '../../misc/toolbar/Toolbar'; -import Manager from '../../style/vector/Manager'; -import defaultConfig from './AnnotationsConfig'; -import FeaturesList from './FeaturesList'; -import GeometryEditor from '../../../plugins/Annotations/components/GeometryEditor'; -import { getApi } from '../../../api/userPersistedStorage'; - -/** - * (Default) Viewer / Editor for Annotations. - * @memberof components.mapControls.annotations - * @class - * @prop {string} id identifier of the current annotation feature - * @prop {function} onChangeFormat triggered every format change - * @prop {string} format decimal or aeronautical degree for coordinates - * @prop {string} mapProjection crs of the map - * @prop {object} config configuration object, where overridable stuff is stored (fields config for annotations, marker library, etc.) {@link #components.mapControls.annotations.AnnotationsConfig} - * @prop {object} editing feature object of the feature under editing (when editing mode is enabled, null otherwise) - * @prop {boolean} drawing flag to state status of drawing during editing - * @prop {boolean} styling flag to state status of styling during editing - * @prop {object} errors key/value set of validation errors (field_name: error_id) - * @prop {object} feature object with the annotation properties - * @prop {bool} showBack shows / hides the back button in the view mode - * @prop {bool} showEdit shows / hides the edit button in the view mode - * @prop {function} onEdit triggered when the user clicks on the edit button - * @prop {function} onCancelEdit triggered when the user cancels current editing session - * @prop {function} onCancelStyle triggered when the user cancels style selection - * @prop {function} onCancel triggered when the user cancels the addition/changes made to the annotation - * @prop {function} onCleanHighlight triggered when the user exits 'details' mode - * @prop {function} onHighlight triggered when the user hover the infoviewer card - * @prop {function} onConfirmDeleteFeature triggered when the user confirms deletion of a feature - * @prop {function} onAddText triggered when the user adds new Text geometry to the feature - * @prop {function} onToggleUnsavedChangesModal toggles the view of the UnsavedChangesModal - * @prop {function} onToggleUnsavedStyleModal toggles the view of the UnsavedStyleModal - * @prop {function} onToggleUnsavedGeometryModal toggles the view of the UnsavedGeometryModal - * @prop {function} onSetUnsavedChanges triggered when the user changes the value of any field, it sets a flag used to trigger the view of the UnsavedChangesModal - * @prop {function} onAddNewFeature triggered when user click on save icon of the coordinate editor, this will add the feature being drawn to the list of features of the ft coll of the annotation - * @prop {function} onChangeProperties triggered when the user changes the value of any field - * @prop {function} onSetUnsavedStyle triggered when the user changes the style , it sets a flag used to trigger the view of the UnsavedStyleModal - * @prop {function} onConfirmRemove triggered when the user confirms removal - * @prop {function} onCancelRemove triggered when the user cancels removal - * @prop {function} onCancelClose triggered when the user cancels closing - * @prop {function} onConfirmClose triggered when the user confirms closing - * @prop {function} onStartDrawing triggered before the user starts the drawing process - * @prop {object} editedFields fields of the annotation - * @prop {object} drawingText it contains info of the text annotation, 'drawing' if being added or 'show' used to show the modal to add the relative value - * @prop {boolean} unsavedChanges flag used to trigger changes of showUnsavedChangesModal - * @prop {boolean} unsavedStyle flag used to trigger changes of showUnsavedChangesModal - * @prop {boolean} closing user asked for closing panel when editing - * @prop {string} stylerType selected styler to be shown as body - * @prop {boolean} showUnsavedStyleModal flag used to show the UnsavedChangesModal - * @prop {boolean} showUnsavedChangesModal flag used to show the UnsavedStyleModal - * @prop {boolean} showUnsavedGeometryModal flag used to display the modal after user clicks on back and has changed something in the coord editor - * @prop {boolean} showDeleteFeatureModal flag used to display the modal after deleting a feature for confirmation - * @prop {boolean} unsavedGeometry flag used to say if something has changed when coord editor is open - * @prop {string} mode current mode of operation (list, editing, detail) - * @prop {function} onRemove triggered when the user clicks on the remove button - * @prop {function} onSave triggered when the user clicks on the save button - * @prop {function} onSaveStyle triggered when the user saves changes to the style - * @prop {function} onError triggered when a validation error occurs - * @prop {function} onAddGeometry triggered when the user clicks on the add point button TODO FIX THIS - * @prop {function} onDeleteGeometry triggered when the user clicks on the remove points button - * @prop {function} onStyleGeometry triggered when the user clicks on the style button - * @prop {function} onSetStyle triggered when the user changes a style property - * @prop {function} onChangeSelected triggered when the user changes a value(lat or lon) of a coordinate in the coordinate editor - * @prop {function} onChangeRadius triggered when the user changes the radius of the Circle in its coordinate editor - * @prop {function} onChangeText triggered when the user changes the text of the Text Annotation in its coordinate editor - * @prop {function} onSetInvalidSelected triggered when the user insert an invalid coordinate or remove a valid one i.e. "" - * @prop {function} onHighlightPoint triggered when mouse goes over/off a CoordinatesRow - * @prop {function} onResetCoordEditor triggered when the user goes back from the coordinate editor, it will open a dialog for unsaved changes - * @prop {function} onZoom triggered when the user zooms to an annotation - * @prop {function} onDownload triggered when the user exports - * @prop {function} onChangeGeometryTitle triggered when the user changes geometry title in coordinate editor panel - * @prop {function} onSelectFeature triggered when the user clicks on a geometry card - * @prop {boolean} coordinateEditorEnabled triggered when the user zooms to an annotation - * @prop {object} selected Feature containing the geometry and the properties used for the coordinated editor - * @prop {object} aeronauticalOptions options for aeronautical format (seconds decimals and step) - * @prop {number} maxZoom max zoome the for annotation (default 18) - * @prop {function} onDeleteFeature triggered when user click on trash icon of the coordinate editor - * @prop {function} onUpdateSymbols triggered when user click on refresh icon of the symbols addon - * @prop {function} onSetErrorSymbol set a flag in the state to say if the default symbols exists - * @prop {number} width of the annotation panel - * @prop {string} pointType the type of the point, values are "marker" or "symbol" - * @prop {object[]} lineDashOptions list of options for dashed lines - * @prop {object[]} symbolList list of symbols - * @prop {string} symbolsPath path to the svg folder - * @prop {string} defaultShape default shape for symbol - * @prop {string} defaultShapeStrokeColor default symbol stroke color - * @prop {string} defaultShapeFillColor default symbol fill color - * @prop {string} defaultShapeSize default symbol shape size in px - * @prop {object} defaultStyles object with default symbol styles - * @prop {number} textRotationStep rotation step of text styler - * @prop {function} onSetAnnotationMeasurement triggered on click of edit measurement button when annotation is of type 'Measure' - * @prop {function} onFilterMarker triggered when marker/glyph name is specified for filtering - * @prop {object[]} annotations list of annotations - * @prop {boolean} measurementAnnotationEdit flag for measurement specific annotation features - * @prop {boolean} geodesic enable to draw a geodesic geometry (supported only for Circle) - * @prop {function} onHideMeasureWarning triggered when warning is ignored with "Don't show again" flag - * @prop {boolean} showAgain flag for checkbox on the measure annotation popup warning - * @prop {boolean} showPopupWarning flag to show warning modal on navigating to measurement panel from annotation - * @prop {function} onToggleShowAgain triggered when interacting with the checkbox on measure annotation warning popup - * @prop {function} onInitPlugin triggered when annotation editor is mounted - * @prop {function} onGeometryHighlight triggered onMouseEnter and onMouseLeave of the geometry card - * @prop {function} onUnSelectFeature triggered on unselecting a geometry card - * - * In addition, as the Identify viewer interface mandates, every feature attribute is mapped as a component property (in addition to the feature object). - */ -class AnnotationsEditor extends React.Component { - static displayName = 'AnnotationsEditor'; - - static propTypes = { - id: PropTypes.string, - onEdit: PropTypes.func, - onCancelEdit: PropTypes.func, - onCancelStyle: PropTypes.func, - onCleanHighlight: PropTypes.func, - onHighlight: PropTypes.func, - onAddText: PropTypes.func, - onCancel: PropTypes.func, - onConfirmDeleteFeature: PropTypes.func, - onRemove: PropTypes.func, - onSave: PropTypes.func, - onSaveStyle: PropTypes.func, - onError: PropTypes.func, - onAddGeometry: PropTypes.func, - onToggleUnsavedChangesModal: PropTypes.func, - onToggleUnsavedGeometryModal: PropTypes.func, - onToggleUnsavedStyleModal: PropTypes.func, - onToggleDeleteFtModal: PropTypes.func, - onSetUnsavedChanges: PropTypes.func, - onSetUnsavedStyle: PropTypes.func, - onChangeProperties: PropTypes.func, - onChangeSelected: PropTypes.func, - onConfirmClose: PropTypes.func, - onCancelRemove: PropTypes.func, - onConfirmRemove: PropTypes.func, - onChangeRadius: PropTypes.func, - onChangeText: PropTypes.func, - onChangeGeometryTitle: PropTypes.func, - onCancelClose: PropTypes.func, - onSetInvalidSelected: PropTypes.func, - onDeleteGeometry: PropTypes.func, - onAddNewFeature: PropTypes.func, - onStyleGeometry: PropTypes.func, - onResetCoordEditor: PropTypes.func, - onHighlightPoint: PropTypes.func, - onSetStyle: PropTypes.func, - onStartDrawing: PropTypes.func, - onZoom: PropTypes.func, - editing: PropTypes.object, - editedFields: PropTypes.object, - drawingText: PropTypes.object, - drawing: PropTypes.bool, - unsavedChanges: PropTypes.bool, - unsavedGeometry: PropTypes.bool, - unsavedStyle: PropTypes.bool, - mouseHoverEvents: PropTypes.bool, - coordinateEditorEnabled: PropTypes.bool, - styling: PropTypes.bool, - closing: PropTypes.bool, - removing: PropTypes.bool, - errors: PropTypes.object, - stylerType: PropTypes.string, - featureType: PropTypes.string, - showBack: PropTypes.bool, - showEdit: PropTypes.bool, - showUnsavedChangesModal: PropTypes.bool, - showUnsavedStyleModal: PropTypes.bool, - showDeleteFeatureModal: PropTypes.bool, - showUnsavedGeometryModal: PropTypes.bool, - config: PropTypes.object, - feature: PropTypes.object, - features: PropTypes.object, - selected: PropTypes.object, - mode: PropTypes.string, - maxZoom: PropTypes.number, - width: PropTypes.number, - onDownload: PropTypes.func, - onChangeFormat: PropTypes.func, - onSelectFeature: PropTypes.func, - mapProjection: PropTypes.string, - format: PropTypes.string, - aeronauticalOptions: PropTypes.object, - onDeleteFeature: PropTypes.func, - pointType: PropTypes.string, - symbolsPath: PropTypes.string, - onUpdateSymbols: PropTypes.func, - onSetErrorSymbol: PropTypes.func, - symbolErrors: PropTypes.array, - lineDashOptions: PropTypes.array, - symbolList: PropTypes.array, - defaultShape: PropTypes.string, - defaultShapeSize: PropTypes.number, - defaultShapeFillColor: PropTypes.string, - defaultShapeStrokeColor: PropTypes.string, - defaultStyles: PropTypes.object, - textRotationStep: PropTypes.number, - onSetAnnotationMeasurement: PropTypes.func, - onFilterMarker: PropTypes.func, - annotations: PropTypes.array, - measurementAnnotationEdit: PropTypes.bool, - geodesic: PropTypes.bool, - onHideMeasureWarning: PropTypes.func, - showAgain: PropTypes.bool, - showPopupWarning: PropTypes.bool, - onToggleShowAgain: PropTypes.func, - onInitPlugin: PropTypes.func, - onGeometryHighlight: PropTypes.func, - onUnSelectFeature: PropTypes.func, - onValidateFeature: PropTypes.func - }; - - static defaultProps = { - config: defaultConfig, - errors: {}, - selected: null, - editedFields: {}, - showBack: false, - showEdit: true, - coordinateEditorEnabled: false, - feature: {}, - maxZoom: 18, - format: "decimal", - pointType: "marker", - stylerType: "marker", - annotations: [], - measurementAnnotationEdit: false, - geodesic: true, - onInitPlugin: () => {} - }; - /** - @prop {object} removing object to remove, it is also a flag that means we are currently asking for removing an annotation / geometry. Toggles visibility of the confirm dialog - */ - state = { - editedFields: {}, - removing: null, - textValue: "", - tabValue: "coordinates", - showPopupWarning: false - }; - - componentDidMount() { - this.props.onInitPlugin(); - } - - getConfig = () => { - return {...defaultConfig, ...this.props.config, onFilterMarker: this.props.onFilterMarker}; - }; - - getBodyItems = (editing) => { - return this.getConfig().fields - .filter((field) => !editing || field.editable) - .map((field) => { - const isError = editing && this.props.errors[field.name]; - const additionalCls = isError ? 'field-error' : ''; - return ( -
- {field.showLabel ? : null} - {isError ? this.renderErrorOn(field.name) : ''} - {this.renderProperty(field, this.props[field.name] || field.value, editing)} -
- ); - }); - }; - - - getValidator = (validator) => { - if (isFunction(validator)) { - return validator; - } - return handleExpression({}, {}, '{(function(value) {return ' + validator + ';})}'); - }; - - renderViewButtons = () => { - return ( - - - - { - this.props.onCancelEdit(this.props?.feature?.properties); - this.props.onCancel(); this.props.onCleanHighlight(); - } - }, { - glyph: "pencil", - tooltipId: "annotations.edit", - visible: this.props.showEdit, - multiGeometry: this.props.config.multiGeometry, - onClick: () => { this.props.onEdit(this.props.id); }, - disabled: !this.props.config.multiGeometry && this.props.editing && this.props.editing.features && this.props.editing.features.length, - bsStyle: this.props.drawing ? "success" : "primary" - }, { - glyph: 'trash', - tooltipId: "annotations.remove", - visible: true, - onClick: () => { - this.setState({removing: this.props.id}); - } - }, { - glyph: 'download', - tooltip: , - visible: true, - onClick: () => { this.props.onDownload(this.props.features); } - } - ]} /> - - - ); - }; - - renderEditingCoordButtons = () => { - const areAllFeaturesValid = this.validateFeatures(); - return ( - - - { - if (this.props.styling && this.isMeasureEditDisabled()) { - if (this.props.unsavedStyle) { - this.props.onToggleUnsavedStyleModal(); - } else { - this.props.onCancelStyle(); - } - } else if (this.props.unsavedGeometry) { - this.props.onToggleUnsavedGeometryModal(); - } else if (this.props.unsavedChanges) { - this.props.onToggleUnsavedChangesModal(); - } else { - this.props.onResetCoordEditor(); - this.props.onCancelEdit(this.props.editing?.properties); - // Reset geometry editor tab - this.setState({...this.state, tabValue: 'coordinates'}); - } - - } - }, { - glyph: 'trash', - tooltipId: "annotations.remove", - tooltipPosition: 'bottom', - disabled: !this.props.annotations.length, - visible: !this.props.selected, - onClick: () => { - this.setState({removing: this.props.id}); - } - }, { - glyph: 'floppy-disk', - tooltipPosition: 'bottom', - tooltipId: !areAllFeaturesValid ? "annotations.annotationSaveGeometryError" : !isEmpty(this.props.selected) ? "annotations.saveGeometry" : "annotations.save", - disabled: (this.props.selected && this.props.selected.properties && !this.props.selected.properties.isValidFeature) || !areAllFeaturesValid, - onClick: () => this.save() - }, - { - glyph: 'download', - tooltip: , - tooltipPosition: 'bottom', - disabled: Object.keys(this.validate()).length !== 0 || this.props.unsavedChanges, - visible: !this.props.selected, - onClick: () => { - const {newFeature, ...features} = this.props.editing; - this.props.onDownload(features); - } - } - ]} /> - - - ); - }; - - renderButtons = (editing) => { - let toolbar; - if (editing) { - toolbar = this.renderEditingCoordButtons(); - } else { - toolbar = this.renderViewButtons(); - } - return (
{toolbar}
); - }; - - renderProperty = (field, prop, editing) => { - const fieldValue = this.props.editedFields[field.name] === undefined ? prop : this.props.editedFields[field.name]; - if (editing) { - switch (field.type) { - case 'html': - return ( { this.change(field.name, val); if (!this.props.unsavedChanges) { this.props.onSetUnsavedChanges(true); } }} - />); - case 'component': - const Component = fieldValue; - return } onChange={(e) => { this.change(field.name, e.target.value); if (!this.props.unsavedChanges) { this.props.onSetUnsavedChanges(true); } }} />; - default: - return { this.change(field.name, e.target.value); if (!this.props.unsavedChanges) { this.props.onSetUnsavedChanges(true); } }} />; - } - - } - switch (field.type) { - case 'html': - return ; - case 'component': - const Component = fieldValue; - return ; - default: - return (

{fieldValue}

); - } - }; - - renderErrorOn = (field) => { - return
; - }; - - renderMarkers = (markers, prefix = '') => { - return markers.map((marker) => { - if (marker.markers) { - return (
- {this.renderMarkers(marker.markers, marker.name + '-')} -
); - } - return ( -
this.selectStyle(marker)} - className={"mapstore-annotations-info-viewer-marker mapstore-annotations-info-viewer-marker-" + prefix + marker.name + - (this.isCurrentStyle(marker) ? " mapstore-annotations-info-viewer-marker-selected" : "")} style={marker.thumbnailStyle} />); - }); - }; - - renderBody = (editing) => { - const items = this.getBodyItems(editing); - if (items.length === 0) { - return null; - } - - return (
-
- {items} - {editing && - } -
-
); - }; - - renderError = (editing) => { - return editing ? (Object.keys(this.props.errors) - .filter(field => this.getConfig().fields.filter(f => f.name === field).length === 0).map(field => this.renderErrorOn(field))) : null; - }; - - renderModals = () => { - if (this.props.closing) { - return ( this.props.onConfirmClose(this.props.editing?.properties)} - confirmButtonBSStyle="default" - closeGlyph="1-close" - confirmButtonContent={} - closeText={}> - - ); - } else if (this.props.showUnsavedChangesModal) { - return ( { - this.props.selected && this.props.onResetCoordEditor(); - this.props.onCancelEdit(this.props.editing?.properties); this.props.onToggleUnsavedChangesModal(); - }} - confirmButtonBSStyle="default" - closeGlyph="1-close" - confirmButtonContent={} - closeText={}> - - ); - } else if (this.props.showUnsavedGeometryModal) { - return ( { - this.props.onResetCoordEditor(); - this.props.onCancelEdit(this.props.editing?.properties); - }} - confirmButtonBSStyle="default" - closeGlyph="1-close" - title={} - confirmButtonContent={} - closeText={}> - - ); - } else if (this.props.showUnsavedStyleModal) { - return ( { - this.props.onCancelStyle(); - this.props.onToggleUnsavedStyleModal(); - if (this.isMeasureEditDisabled()) { - this.setTabValue('coordinates'); - } else { - this.setTabValue('style'); - } - }} - confirmButtonBSStyle="default" - closeGlyph="1-close" - confirmButtonContent={} - closeText={}> - - ); - } else if (this.props.showDeleteFeatureModal) { - return ( { this.props.onConfirmDeleteFeature(); this.props.onToggleDeleteFtModal(); }} - confirmButtonBSStyle="default" - closeGlyph="1-close" - confirmButtonContent={} - closeText={}> - - ); - } else if (this.state.removing || this.props.removing) { - return ({ - this.state.removing && this.setState({removing: null}); - this.props.onCancelRemove(); - }} - focusConfirm={this.props.removing} - onConfirm={() => { - if (this.state.removing) { - this.setState({removing: null}); - this.props.onConfirmRemove(this.state.removing, "features"); - } else { - this.props.onConfirmRemove(this.props.removing, "geometry"); - } - }} - confirmButtonBSStyle="default" - closeGlyph="1-close" - confirmButtonContent={} - closeText={}> - {this.props.mode === 'editing' ? : - } - ); - } else if (this.state.showPopupWarning && this.props.showPopupWarning) { - return (} - onClose={this.hideWarning} - onConfirm={this.setAnnotationMeasurement} - confirmButtonBSStyle="default" - closeGlyph="1-close" - confirmButtonContent={} - closeText={}> - -

-

- - - -

-
-
); - } - - return null; - } - - render() { - const editing = this.props.editing && (this.props.editing.properties.id === this.props.id); - let mouseHoverEvents = this.props.mouseHoverEvents ? { - onMouseEnter: () => { - this.props.onHighlight(this.props.id); - }, - onMouseLeave: () => { - this.props.onCleanHighlight(); - } - } : {}; - const type = this.props.selected ? getGeometryType(this.props.selected) : ""; - const {glyph = "", label = ""} = isEmpty(type) ? {} : getGeometryGlyphInfo(type); - return ( -
-
- {this.renderButtons(editing)} - {this.renderError(editing)} - {this.renderModals()} - {this.renderBody(editing)} -
- {!isEmpty(this.props.selected) && -
-
- -
- { - const valueText = e.target.value.trim(); - this.props.onChangeGeometryTitle(valueText ? valueText : label); - }} - type="text"/> -
-
- {this.props.selected?.properties?.isText &&
- - - - { - const valueText = e.target.value; - const components = this.props?.selected?.geometry?.coordinates?.length ? - getComponents(this.props.selected.geometry) : []; - if (this.validateText(components, valueText )) { - this.props.onChangeText(valueText, components.map(coordToArray)); - } else if (valueText !== "") { - this.props.onChangeText(valueText, components.map(coordToArray)); - } else { - this.props.onChangeText("", components.map(coordToArray)); - this.props.onSetInvalidSelected("text", components.map(coordToArray)); - } - }} - type="text"/> - - -
} - -
- {this.state.tabValue === 'coordinates' && - - } - {this.state.tabValue === 'style' && - { - this.props.onSetStyle(style); - this.props.onSetUnsavedStyle(true); - this.props.onSetUnsavedChanges(true); - }} - pointType={this.props.pointType} - style={this.props.selected && this.props.selected.style || this.props.editing.style} - width={this.props.width} - symbolsPath={this.props.symbolsPath} - onSetErrorSymbol={this.props.onSetErrorSymbol} - symbolErrors={this.props.symbolErrors} - onUpdateSymbols={this.props.onUpdateSymbols} - symbolList={this.props.symbolList} - defaultShape={this.props.defaultShape} - defaultShapeSize={this.props.defaultShapeSize} - defaultShapeFillColor={this.props.defaultShapeFillColor} - defaultShapeStrokeColor={this.props.defaultShapeStrokeColor} - defaultStyles={this.props.defaultStyles} - lineDashOptions={this.props.lineDashOptions} - markersOptions={this.getConfig()} - textRotationStep={this.props.textRotationStep} - /> - } -
-
- } -
- ); - } - - validateFeatures = () => { - let areAllGeometriesValid = true; - if (Array.isArray(this.props?.editing?.features)) { - areAllGeometriesValid = this.props.editing.features.every(feature => feature?.properties?.isValidFeature); - } - return areAllGeometriesValid; - }; - - change = (field, value) => { - this.props.onChangeProperties(field, value); - }; - - isCurrentStyle = (m) => { - return this.getConfig().markersConfig.matches(this.props.editing.style.MultiPoint, m.style); - }; - - selectStyle = (marker) => { - return this.props.onSetStyle(assign({}, { - "Point": { - ...this.getConfig().markersConfig.getStyle(marker.style), - iconGlyph: this.props.editing.style.Point && this.props.editing.style.Point.iconGlyph - }, - "MultiPoint": { - ...this.getConfig().markersConfig.getStyle(marker.style), - iconGlyph: this.props.editing.style.MultiPoint && this.props.editing.style.MultiPoint.iconGlyph - } - })); - }; - - selectGlyph = (option) => { - return this.props.onSetStyle( - assign({}, this.props.editing.style, { - "Point": { - ...this.props.editing.style.Point, - iconGlyph: option && option.value || "" - }, - "MultiPoint": { - ...this.props.editing.style.MultiPoint, - iconGlyph: option && option.value || "" - } - })); - }; - - validate = () => { - return assign(this.getConfig().fields.filter(field => field.editable).reduce((previous, field) => { - const value = this.props.editedFields[field.name] === undefined ? this.props[field.name] : this.props.editedFields[field.name]; - if (field.validator && !this.getValidator(field.validator)(value)) { - return assign(previous, { - [field.name]: field.validateError - }); - } - return previous; - }, {}), this.props.editing.features && this.props.editing.features.length ? {} : { - geometry: 'annotations.emptygeometry' - }); - - }; - - validateText = (components, valueText) => { - if (components && components.length) { - const cmp = head(components); - return !!valueText && validateCoords(cmp); - } - return false; - } - - save = () => { - if (!isEmpty(this.props.selected)) { - this.props.onAddNewFeature(); - } else { - const errors = this.validate(); - if (Object.keys(errors).length === 0) { - this.props.onError({}); - this.props.onSave(this.props.id, assign({}, this.props.editedFields), - this.props.editing.features, this.props.editing.style, this.props.editing.newFeature || false, { - ...this.props.editing.properties, - visibility: !isUndefined(this.props.editing.properties.visibility) - ? this.props.editing.properties.visibility - : this.props.editing.visibility - } - ); - } else { - this.props.onError(errors); - } - } - }; - - setTabValue = (tabValue) =>{ - if (this.state.tabValue !== tabValue) { - this.setState({...this.state, tabValue}); - } - } - - setPopupWarning = (showPopupWarning) =>{ - this.setState({...this.state, showPopupWarning}); - } - - isMeasureEditDisabled = () => { - const isMeasureAnnotation = this.props.editing?.properties?.type === MEASURE_TYPE || false; - return !this.props.measurementAnnotationEdit || !isMeasureAnnotation; - } - - setAnnotationMeasurement = () => { - // Excluding geometry types not supported by measurement - this.props.onSetAnnotationMeasurement(this.props.editing.features.filter(f=> f.geometry.type !== 'Point' && !f.properties.isCircle), this.props.editing?.properties); - this.hideWarning(); - } - - hideWarning = () => { - if (this.props.showAgain) { - try { - getApi().setItem("showPopupWarning", false); - } catch (e) { - console.error(e); - } - this.props.onHideMeasureWarning(); - } - this.setPopupWarning(false); - } -} - -export default AnnotationsEditor; diff --git a/web/client/components/mapcontrols/annotations/DropdownFeatureType.jsx b/web/client/components/mapcontrols/annotations/DropdownFeatureType.jsx deleted file mode 100644 index a7c4b76823..0000000000 --- a/web/client/components/mapcontrols/annotations/DropdownFeatureType.jsx +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2018, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. -*/ -import { Glyphicon, DropdownButton, MenuItem } from 'react-bootstrap'; - -import tooltip from '../../misc/enhancers/tooltip'; -import { DEFAULT_ANNOTATIONS_STYLES, getStartEndPointsForLinestring } from '../../../utils/LegacyAnnotationsUtils'; -import React from 'react'; -import uuidv1 from 'uuid/v1'; -import assign from 'object-assign'; - - -const DropdownButtonT = tooltip(DropdownButton); -const DropdownFeatureType = ({ - onClick = () => {}, - onStartDrawing = () => {}, - onAddText = () => {}, - onSetStyle = () => {}, - defaultStyles = {}, - defaultPointType = 'marker', - titles = {}, - glyph = "", - bsStyle = "primary", - ...props -} = {}) => ( - } - disabled={!!props.disabled} - noCaret> - - { - onClick("Point"); - onSetStyle([{ ...defaultStyles.POINT?.[defaultPointType], highlight: true, id: uuidv1()}]); - onStartDrawing(); - }}> - {titles.marker} - - - { - onClick("LineString"); - onSetStyle( - [{ ...DEFAULT_ANNOTATIONS_STYLES.LineString, highlight: true, id: uuidv1()}] - .concat(getStartEndPointsForLinestring())); - onStartDrawing(); - }}> - {titles.line} - - - { - onClick("Polygon"); - onSetStyle([ - {...DEFAULT_ANNOTATIONS_STYLES.Polygon, highlight: true, id: uuidv1()} - ]); - onStartDrawing(); - }}> - {titles.polygon} - - - { - onClick("Text"); - onAddText(); - onSetStyle([ - assign({}, {...DEFAULT_ANNOTATIONS_STYLES.Text, highlight: true, type: "Text", title: "Text Style", id: uuidv1()}) - ]); - onStartDrawing(); - }}> - {titles.text} - - - { - onClick("Circle"); - onSetStyle([ - assign({}, {...DEFAULT_ANNOTATIONS_STYLES.Circle, highlight: true, type: "Circle", title: "Circle Style", id: uuidv1()} ), - {...DEFAULT_ANNOTATIONS_STYLES.Point, highlight: true, iconAnchor: [0.5, 0.5], type: "Point", title: "Center Style", filtering: false, geometry: "centerPoint", id: uuidv1()} - ]); - onStartDrawing(); - }}> - {titles.circle} - - -); - -export default DropdownFeatureType; diff --git a/web/client/components/mapcontrols/annotations/FeaturesList.jsx b/web/client/components/mapcontrols/annotations/FeaturesList.jsx deleted file mode 100644 index c69fa022c3..0000000000 --- a/web/client/components/mapcontrols/annotations/FeaturesList.jsx +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright 2020, GeoSolutions Sas. - * All rights reserved. - * - * 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 {Glyphicon, ControlLabel, Tooltip } from 'react-bootstrap'; -import uuidv1 from 'uuid/v1'; -import bbox from '@turf/bbox'; -import Toolbar from '../../misc/toolbar/Toolbar'; -import OverlayTrigger from '../../misc/OverlayTrigger'; -import cs from 'classnames'; -import Message from '../../I18N/Message'; -import {get} from 'lodash'; -import {DEFAULT_ANNOTATIONS_STYLES, getStartEndPointsForLinestring, getGeometryGlyphInfo, getGeometryType} from '../../../utils/LegacyAnnotationsUtils'; - -/** - * Feature List component for Annotation Viewer. - * @memberof components.mapControls.annotations - * @function - * -*/ -const FeaturesList = (props) => { - const { - editing, - onAddGeometry, - onSetStyle, - onStartDrawing, - onAddText, - onStyleGeometry, - setTabValue, - isMeasureEditDisabled, - onSetAnnotationMeasurement, - showPopupWarning, - setPopupWarning, - geodesic, - defaultStyles, - defaultPointType, - onValidateFeature, - validateFeatures - } = props; - const {features = []} = editing || {}; - const isValidFeature = get(props, "selected.properties.isValidFeature", true); - const areAllFeaturesValid = validateFeatures(); - - const onClickGeometry = (type, style) => { - onStyleGeometry(false); - onAddGeometry(type); - type === "Text" && onAddText(); - onSetStyle(style); - onStartDrawing({geodesic}); - setTabValue('coordinates'); - onValidateFeature(); - }; - const circleCenterStyles = defaultPointType === "symbol" ? defaultStyles.POINT?.[defaultPointType] : DEFAULT_ANNOTATIONS_STYLES.Point; - - const linePointStyles = defaultPointType === "symbol" ? [{...defaultStyles.POINT?.[defaultPointType], highlight: true, iconAnchor: [0.5, 0.5], type: "Point", title: "StartPoint Style", geometry: "startPoint", filtering: false, id: uuidv1()}, - {...defaultStyles.POINT?.[defaultPointType], highlight: true, iconAnchor: [0.5, 0.5], type: "Point", title: "EndPoint Style", geometry: "endPoint", filtering: false, id: uuidv1()}] : getStartEndPointsForLinestring(); - - return ( - <> -
- - { - showPopupWarning ? setPopupWarning(true) : onSetAnnotationMeasurement(); - }, - tooltip: - }, - { - glyph: 'point-plus', - visible: isMeasureEditDisabled, - disabled: !isValidFeature, - onClick: () => { - const style = [{ ...defaultStyles.POINT?.[defaultPointType], highlight: true, id: uuidv1()}]; - onClickGeometry("Point", style); - }, - tooltip: - }, - { - glyph: 'polyline-plus', - visible: isMeasureEditDisabled, - disabled: !isValidFeature, - onClick: () => { - const style = [{ ...DEFAULT_ANNOTATIONS_STYLES.LineString, highlight: true, id: uuidv1()}] - .concat(linePointStyles); - onClickGeometry("LineString", style); - }, - tooltip: - }, - { - glyph: 'polygon-plus', - visible: isMeasureEditDisabled, - disabled: !isValidFeature, - onClick: () => { - const style = [ - {...DEFAULT_ANNOTATIONS_STYLES.Polygon, highlight: true, id: uuidv1()}]; - onClickGeometry("Polygon", style); - }, - tooltip: - }, - { - glyph: 'font-add', - visible: isMeasureEditDisabled, - disabled: !isValidFeature, - onClick: () => { - const style = [ - {...DEFAULT_ANNOTATIONS_STYLES.Text, highlight: true, type: "Text", title: "Text Style", id: uuidv1()}]; - onClickGeometry("Text", style); - }, - tooltip: - }, - { - glyph: '1-circle-add', - visible: isMeasureEditDisabled, - disabled: !isValidFeature, - onClick: () => { - const style = [ - {...DEFAULT_ANNOTATIONS_STYLES.Circle, highlight: true, type: "Circle", title: "Circle Style", id: uuidv1()}, - { ...circleCenterStyles, highlight: true, iconAnchor: [0.5, 0.5], type: "Point", title: "Center Style", filtering: false, geometry: "centerPoint", id: uuidv1()} - ]; - onClickGeometry("Circle", style); - }, - tooltip: - } - ]} - /> -
- {features && features.length === 0 &&
} - {features?.map((feature, key) => { - return ( - - ); - })} - - ); -}; - -/** - * Feature or Geometry card component for FeatureList. - * @function - * - */ -const FeatureCard = ({ - feature, - selected, - disabled, - onDeleteGeometry, - onZoom, - maxZoom, - onSelectFeature, - onUnselectFeature, - setTabValue, - isMeasureEditDisabled, - onStyleGeometry, - onGeometryHighlight, - onValidateFeature -}) => { - const type = getGeometryType(feature); - const {properties} = feature; - const {glyph, label} = getGeometryGlyphInfo(type); - const isSelected = selected?.properties?.id === properties?.id; - - const selectedIsValidFeature = get(selected, "properties.isValidFeature", true); - const isValidFeature = properties?.isValidFeature; - const allowCardMouseEvent = !isSelected && selectedIsValidFeature; - - const overlayWrapper = (content) => ( - }> - {content} - - ); - - const content = ( -
allowCardMouseEvent && onGeometryHighlight(properties.id)} - onMouseLeave={() => allowCardMouseEvent && onGeometryHighlight(properties.id, false)} - onClick={() =>{ - - if (isSelected && isValidFeature) { - onUnselectFeature(); - onGeometryHighlight(properties.id); - } else if (!disabled) { - onSelectFeature([feature]); - setTabValue(isMeasureEditDisabled ? 'coordinates' : 'style'); - onStyleGeometry(!isMeasureEditDisabled); - } - onValidateFeature(); - } } - > -
- -
-
-
{properties?.geometryTitle || label || properties?.id}
-
- , - onClick: (event) => { - event.stopPropagation(); - const extent = bbox(feature); - onZoom(extent, 'EPSG:4326', maxZoom); - } - }, - { - glyph: 'trash', - className: cs({'inactive': disabled && !isSelected, 'square-button-md no-border': true}), - tooltip: , - onClick: (event) => { - event.stopPropagation(); - onDeleteGeometry(properties?.id); - } - } - ]} - /> -
- ); - - return disabled && !isSelected ? overlayWrapper(content) : content; -}; - -FeaturesList.defaultProps = { - onAddGeometry: () => {}, - onSetStyle: () => {}, - onStartDrawing: () => {}, - onAddText: () => {}, - onStyleGeometry: () => {}, - onSetAnnotationMeasurement: () => {}, - onSelectFeature: () => {}, - setTabValue: () => {}, - isMeasureEditDisabled: true, - defaultPointType: 'marker', - defaultStyles: {}, - onValidateFeature: () => {}, - validateFeatures: () => { return true; } -}; - -export default FeaturesList; diff --git a/web/client/components/mapcontrols/annotations/SelectAnnotationsFile.jsx b/web/client/components/mapcontrols/annotations/SelectAnnotationsFile.jsx deleted file mode 100644 index 6eb6595d60..0000000000 --- a/web/client/components/mapcontrols/annotations/SelectAnnotationsFile.jsx +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2017, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -import { Promise } from 'es6-promise'; -import PropTypes from 'prop-types'; -import React from 'react'; -import { Checkbox } from 'react-bootstrap'; -import Dropzone from 'react-dropzone'; -import Spinner from 'react-spinkit'; - -import { ANNOTATION_TYPE } from '../../../plugins/Annotations/utils/AnnotationsUtils'; -import { readGeoJson } from '../../../utils/FileUtils'; -import Message from '../../I18N/Message'; -import ResizableModal from '../../misc/ResizableModal'; - -class SelectAnnotationsFile extends React.Component { - static propTypes = { - show: PropTypes.bool, - text: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), - onFileChoosen: PropTypes.func, - error: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), - errorMessage: PropTypes.string, - onClose: PropTypes.func, - title: PropTypes.node, - closeGlyph: PropTypes.string, - disableOvveride: PropTypes.bool - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - show: false, - text: , - onFileChoosen: () => {}, - onClose: () => {}, - closeGlyph: "", - errorMessage: "annotations.loaderror", - title: , - disableOvveride: false - }; - state = { - override: false, - loading: false - } - renderError = () => ( -
-
- -
-
) - render() { - return ( - -
- {this.state.error && this.renderError()} - -
{this.state.loading && }{this.props.text}
-
-
- this.setState(() => ({override: !this.state.override}))}> - - -
-
-
- ); - } - setError = () => { - this.setState(() => ({error: this.props.errorMessage, loading: false})); - } - // Modificare per accettare file json ma non devono per forza avere ext.json - // inoltre può accettare qualsiasi collezione di features inoltre filtrare le features che hanno medesimo id - checkfile = (files) => { - this.setState(() => ({loading: true})); - Promise.all(files.map(file => readGeoJson(file))).then((contents) => { - if (this.state.error) { - this.setState(() => ({error: null})); - } - // Get only features - const annotations = contents.filter(({geoJSON, errors = []}) => errors.length === 0 || geoJSON.type === ANNOTATION_TYPE).reduce((acc, {geoJSON}) => acc.concat(geoJSON.features || geoJSON), []); - if (annotations.length === 0) { - throw new Error(); - } - this.props.onFileChoosen(annotations, this.state.override); - this.setState(() => ({loading: false})); - this.props.onClose(); - }).catch(() => { - this.setError(); - }); - }; -} - -export default SelectAnnotationsFile; diff --git a/web/client/components/mapcontrols/annotations/__tests__/Annotations-test.js b/web/client/components/mapcontrols/annotations/__tests__/Annotations-test.js deleted file mode 100644 index 5eb466e541..0000000000 --- a/web/client/components/mapcontrols/annotations/__tests__/Annotations-test.js +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright 2015-2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ -import expect from 'expect'; - -import React from 'react'; -import ReactDOM from 'react-dom'; -import Annotations from '../Annotations'; -import TestUtils from 'react-dom/test-utils'; - -describe("test the Annotations Panel", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.body); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('test default properties', () => { - const annotations = ReactDOM.render(, document.getElementById("container")); - expect(annotations).toBeTruthy(); - const annotationsNode = ReactDOM.findDOMNode(annotations); - expect(annotationsNode).toBeTruthy(); - }); - - it('test removing annotations', () => { - const annotations = ReactDOM.render(, document.getElementById("container")); - expect(annotations).toBeTruthy(); - - const annotationsNode = ReactDOM.findDOMNode(annotations); - expect(annotationsNode).toBeTruthy(); - }); - - it('test rendering detail mode', () => { - const annotationsList = [{ - properties: { - id: '1', - title: 'a', - description: 'b' - }, - geometry: { - type: "MultiPoint" - }, - style: { - iconShape: 'square', - iconColor: 'blue' - } - }, { - properties: { - id: '2', - title: 'a', - description: 'b' - }, - geometry: { - type: "MultiPoint" - }, - style: { - iconShape: 'square', - iconColor: 'blue' - } - }]; - - const Editor = () =>
; - const annotations = ReactDOM.render(, document.getElementById("container")); - expect(annotations).toBeTruthy(); - expect(TestUtils.scryRenderedDOMComponentsWithClass(annotations, "mapstore-annotations-panel-card").length).toBe(0); - expect(TestUtils.scryRenderedDOMComponentsWithClass(annotations, "myeditor").length).toBe(1); - }); - - it('test rendering editing mode', () => { - const Editor = () =>
; - const annotations = ReactDOM.render(, document.getElementById("container")); - expect(annotations).toBeTruthy(); - expect(TestUtils.scryRenderedDOMComponentsWithClass(annotations, "mapstore-annotations-panel-card").length).toBe(0); - expect(TestUtils.scryRenderedDOMComponentsWithClass(annotations, "myeditor").length).toBe(1); - }); - - it('test rendering custom class', () => { - const annotationsList = [{ - properties: { - title: 'a', - description: 'b' - }, - geometry: { - type: "MultiPoint" - }, - style: { - iconShape: 'square', - iconColor: 'blue', - iconGlyph: 'comment' - } - }, { - properties: { - external: true, - title: 'c', - description: 'd' - }, - geometry: { - type: "MultiPoint" - }, - style: { - iconShape: 'square', - iconColor: 'blue', - iconGlyph: 'comment' - } - }]; - - const classNameSelector = (annotation) => { - if (annotation && annotation.properties && annotation.properties.external) { - return 'external'; - } - return ''; - }; - - const annotations = ReactDOM.render(, document.getElementById("container")); - - expect(annotations).toBeTruthy(); - - /* - TODO verify the external properties - const cardsExternal = TestUtils.scryRenderedDOMComponentsWithClass(annotations, "mapstore-annotations-panel-card external"); - expect(cardsExternal.length).toBe(1);*/ - }); - - it('test custom editor', () => { - const annotationsList = [{ - properties: { - id: '1', - title: 'a', - description: 'b' - }, - style: { - iconShape: 'square', - iconColor: 'blue' - } - }, { - properties: { - id: '2', - title: 'a', - description: 'b' - }, - style: { - iconShape: 'square', - iconColor: 'blue' - } - }]; - - const Editor = (props) => { - return This is my editor; - }; - const annotations = ReactDOM.render(, document.getElementById("container")); - expect(annotations).toBeTruthy(); - expect(TestUtils.scryRenderedDOMComponentsWithClass(annotations, "mapstore-annotations-panel-card").length).toBe(0); - expect(TestUtils.scryRenderedDOMComponentsWithClass(annotations, "myeditor1").length).toBe(1); - }); - - it('test annotation card', ()=> { - const actions = { - onZoom: () => {}, - onToggleVisibility: () => {}, - onHighlight: () => {} - }; - const spyOnToggleVisibility = expect.spyOn(actions, 'onToggleVisibility'); - const spyOnHighlight = expect.spyOn(actions, 'onHighlight'); - const spyOnZoom = expect.spyOn(actions, 'onZoom'); - const annotations = [{ - "type": "FeatureCollection", - "properties": { - "id": "819b4120-aa2c-11ea-95b6-c74060290256", - "title": "Poly", - "description": "

Description

Next Line

", - "visibility": true - }, - "features": [ - { - "type": "Feature", - "geometry": { - "coordinates": [[[-121.07812513411045, 42.11778385718358], - [ -116.2265622317791, 44.72175879125132], - [ -115.87499973177908, 40.773885871584866], - [ -114.96093589067458, 42.68889580392076], - [ -121.07812513411045, 42.11778385718358]] - ], - "type": "Polygon" - }, - "properties": { - "id": "829d47d0-aa2c-11ea-95b6-c74060290256", - "isValidFeature": true, - "canEdit": false, - "geometryTitle": "Polygon-test" - } - } - ] - }]; - const container = ReactDOM.render(, document.getElementById("container")); - expect(container).toBeTruthy(); - - const sideCard = TestUtils.scryRenderedDOMComponentsWithClass(container, "mapstore-side-card"); - expect(sideCard).toBeTruthy(); - expect(sideCard.length).toBe(1); - const sideCardTitle = TestUtils.scryRenderedDOMComponentsWithClass(container, "mapstore-annotations-panel-card-title"); - expect(sideCardTitle[0].innerText).toBe('Poly'); - const sideCardDescription = TestUtils.scryRenderedDOMComponentsWithClass(container, "mapstore-annotations-panel-card-description"); - expect(sideCardDescription[0].innerText).toBe('Description'); - const sideCardTools = document.querySelectorAll('.mapstore-side-card-tool .btn-group'); - expect(sideCardTools).toBeTruthy(); - const cardButtons = sideCardTools[0].querySelectorAll('button'); - expect(cardButtons.length).toBe(2); - - // Zoom to annotation - const zoomBtn = cardButtons[0]; - TestUtils.Simulate.click(zoomBtn); - expect(spyOnZoom).toHaveBeenCalled(); - - // Toggle annotations visibility - const visibilityBtn = cardButtons[1]; - TestUtils.Simulate.click(visibilityBtn); - expect(spyOnToggleVisibility).toHaveBeenCalled(); - - // Toggle annotation highlight - TestUtils.Simulate.mouseEnter(sideCard[0]); - expect(spyOnHighlight).toHaveBeenCalled(); - }); -}); diff --git a/web/client/components/mapcontrols/annotations/__tests__/AnnotationsEditor-test.js b/web/client/components/mapcontrols/annotations/__tests__/AnnotationsEditor-test.js deleted file mode 100644 index 6759f77098..0000000000 --- a/web/client/components/mapcontrols/annotations/__tests__/AnnotationsEditor-test.js +++ /dev/null @@ -1,587 +0,0 @@ -/** - * Copyright 2015-2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ -import expect from 'expect'; -import React from 'react'; -import { DragDropContext as dragDropContext } from 'react-dnd'; -import html5Backend from 'react-dnd-html5-backend'; -import ReactDOM from 'react-dom'; -import TestUtils from 'react-dom/test-utils'; - -import AnnotationsEditorComp from '../AnnotationsEditor'; - -const AnnotationsEditor = dragDropContext(html5Backend)(AnnotationsEditorComp); - -const actions = { - onChangeProperties: () => {}, - onSetUnsavedChanges: () => {}, - onEdit: () => {}, - onCancelEdit: () => {}, - onSetUnsavedStyle: () => {}, - onError: () => {}, - onSetAnnotationMeasurement: () => {}, - onDownload: () => {}, - onHideMeasureWarning: () => {}, - onSelectFeature: () => {}, - onUnSelectFeature: () => {}, - onValidateFeature: () => {} -}; -describe("test the AnnotationsEditor Panel", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.body); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('test default properties', () => { - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - const viewerNode = ReactDOM.findDOMNode(viewer); - expect(viewerNode).toExist(); - }); - - it('test display annotation', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - - const viewerNode = ReactDOM.findDOMNode(viewer); - expect(viewerNode).toExist(); - expect(viewerNode.innerText.indexOf('mytitle') !== -1).toBe(true); - expect(viewerNode.innerHTML.indexOf('desc') !== -1).toBe(true); - }); - - it('test display annotation with component field', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - const MyComponent = (props) => { - return my feature: {props.annotation.id}; - }; - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - - const viewerNode = ReactDOM.findDOMNode(viewer); - expect(viewerNode).toExist(); - expect(viewerNode.innerText.indexOf('my feature: 1') !== -1).toBe(true); - }); - - it('test editing annotation', () => { - const properties = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - expect(TestUtils.scryRenderedDOMComponentsWithTag(viewer, "input").length).toEqual(1); - expect(TestUtils.scryRenderedDOMComponentsWithClass(viewer, "quill").length).toEqual(1); - }); - - it('test click remove annotation', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - - const testHandlers = { - onRemoveHandler: () => { } - }; - - const spyRemove = expect.spyOn(testHandlers, 'onRemoveHandler'); - - let viewer = ReactDOM.render({}} onSetUnsavedChanges={()=>{}} - onConfirmRemove={testHandlers.onRemoveHandler}/>, document.getElementById("container")); - expect(viewer).toExist(); - let btnGroup = document.querySelector(".mapstore-annotations-info-viewer-buttons"); - let toolBarButtons = btnGroup.querySelectorAll('button'); - let removeBtn = toolBarButtons[1]; - expect(toolBarButtons.length).toBe(4); - expect(removeBtn).toExist(); - TestUtils.Simulate.click(removeBtn); - const dialog = document.getElementById("confirm-dialog"); - expect(dialog).toExist(); - const confirm = dialog.querySelectorAll('button')[1]; - TestUtils.Simulate.click(confirm); - expect(spyRemove).toHaveBeenCalled(); - - // Disable remove button when no annotations present except for the unsaved new annotation - viewer = ReactDOM.render({}} onSetUnsavedChanges={()=>{}} - onConfirmRemove={testHandlers.onRemoveHandler}/>, document.getElementById("container")); - expect(viewer).toExist(); - btnGroup = document.querySelector(".mapstore-annotations-info-viewer-buttons"); - toolBarButtons = btnGroup.querySelectorAll('button'); - removeBtn = toolBarButtons[1]; - expect(toolBarButtons.length).toBe(4); - expect(removeBtn.classList.contains('disabled')).toBe(true); - - }); - - it('test click save annotation', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - - const testHandlers = { - onSaveHandler: (id) => { return id; }, - onCancelHandler: (id) => { return id; }, - onToggleGeometryEditHandler: (flag) => { return flag; } - }; - - const spySave = expect.spyOn(testHandlers, 'onSaveHandler'); - const spyCancel = expect.spyOn(testHandlers, 'onCancelHandler'); - - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - - let saveButton = ReactDOM.findDOMNode(TestUtils.scryRenderedDOMComponentsWithTag(viewer, "button")[2]); - - expect(saveButton).toExist(); - TestUtils.Simulate.click(saveButton); - expect(spySave.calls.length).toEqual(1); - expect(spySave.calls[0].arguments[0]).toEqual(1); - expect(spySave.calls[0].arguments[5]).toEqual({...feature, visibility: true}); - expect(spyCancel.calls.length).toEqual(0); - }); - - it('test click save annotation', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - - const testHandlers = { - onAddNewFeature: () => {} - }; - - const spySaveGeometry = expect.spyOn(testHandlers, 'onAddNewFeature'); - const defaultStyles = {POINT: { - marker: ["Test marker"], - symbol: ["Test symbol"] - }}; - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - - let saveButton = ReactDOM.findDOMNode(TestUtils.scryRenderedDOMComponentsWithTag(viewer, "button")[1]); - - expect(saveButton).toExist(); - TestUtils.Simulate.click(saveButton); - expect(spySaveGeometry).toHaveBeenCalled(); - }); - - it('test click cancel', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc', - visibility: false - }; - - const testHandlers = { - onSaveHandler: (id) => { return id; }, - onCancelHandler: (id) => { return id; } - }; - - const spySave = expect.spyOn(testHandlers, 'onSaveHandler'); - const spyCancel = expect.spyOn(testHandlers, 'onCancelHandler'); - - const viewer = ReactDOM.render(null}/>, document.getElementById("container")); - expect(viewer).toExist(); - - let cancelButton = ReactDOM.findDOMNode(TestUtils.scryRenderedDOMComponentsWithTag(viewer, "button")[0]); - - expect(cancelButton).toExist(); - TestUtils.Simulate.click(cancelButton); - - expect(spySave.calls.length).toEqual(0); - expect(spyCancel.calls.length).toEqual(1); - const properties = spyCancel.calls[0].arguments[0]; - expect(Object.keys(properties).length > 0).toBe(true); - expect(spyCancel.calls[0].arguments[0].id).toBe('1'); - expect(spyCancel.calls[0].arguments[0].visibility).toBe(false); - }); - - it('test click cancel trigger UnsavedChangesModal', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - - const testHandlers = { - onToggleUnsavedChangesModal: (id) => { return id; } - }; - - const spyUnsavedModal = expect.spyOn(testHandlers, 'onToggleUnsavedChangesModal'); - - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - - let cancelButton = ReactDOM.findDOMNode(TestUtils.scryRenderedDOMComponentsWithTag(viewer, "button")[0]); - - expect(cancelButton).toExist(); - TestUtils.Simulate.click(cancelButton); - - expect(spyUnsavedModal.calls.length).toEqual(1); - }); - - it('test click save validate title error', () => { - const feature = { - id: "1", - title: '', - description: 'desc' - }; - - const testHandlers = { - onSaveHandler: (id) => { return id; }, - onErrorHandler: (msg) => { return msg; } - }; - - const spySave = expect.spyOn(testHandlers, 'onSaveHandler'); - const spyError = expect.spyOn(testHandlers, 'onErrorHandler'); - - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - - let saveButton = ReactDOM.findDOMNode(TestUtils.scryRenderedDOMComponentsWithTag(viewer, "button")[2]); - - expect(saveButton).toExist(); - TestUtils.Simulate.click(saveButton); - - expect(spySave.calls.length).toEqual(0); - expect(spyError.calls.length).toEqual(1); - expect(spyError.calls[0].arguments[0].title).toBe('annotations.mandatory'); - }); - - it('test click save validate geometry error', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - - const testHandlers = { - onSaveHandler: (id) => { return id; }, - onErrorHandler: (msg) => { return msg; } - }; - - const spySave = expect.spyOn(testHandlers, 'onSaveHandler'); - const spyError = expect.spyOn(testHandlers, 'onErrorHandler'); - - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - - let saveButton = ReactDOM.findDOMNode(TestUtils.scryRenderedDOMComponentsWithTag(viewer, "button")[2]); - - expect(saveButton).toExist(); - TestUtils.Simulate.click(saveButton); - - expect(spySave.calls.length).toEqual(0); - expect(spyError.calls.length).toEqual(1); - expect(spyError.calls[0].arguments[0].geometry).toBe('annotations.emptygeometry'); - }); - - it('test edit field', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - const testHandlers = { - onChangeProperties: (id) => { return id; } - }; - const spyChangeProperties = expect.spyOn(testHandlers, 'onChangeProperties'); - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - - const titleField = ReactDOM.findDOMNode(TestUtils.scryRenderedDOMComponentsWithTag(viewer, "input")[0]); - titleField.value = 'anothertitle'; - TestUtils.Simulate.change(titleField); - expect(spyChangeProperties.calls.length).toEqual(2); - - }); - - it('test errors', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - const viewerNode = ReactDOM.findDOMNode(viewer); - expect(viewerNode.innerText.indexOf('myerror') !== -1).toBe(true); - }); - - it('test styling', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - const viewerNode = ReactDOM.findDOMNode(viewer); - expect(viewerNode.className).toBe('mapstore-annotations-info-viewer'); - - const stylerPanel = TestUtils.findRenderedDOMComponentWithClass(viewer, "mapstore-annotations-info-viewer-styler"); - expect(stylerPanel).toExist(); - }); - - it('test Measurement annotation', () => { - const feature = { - id: "1", - title: 'Measure Length', - description: 'Description', - type: "Measure", - iconGlyph: "1-measure-length" - }; - const spyOnSetAnnotationMeasurement = expect.spyOn(actions, "onSetAnnotationMeasurement"); - const spyOnHideMeasureWarning = expect.spyOn(actions, "onHideMeasureWarning"); - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toBeTruthy(); - const viewerNode = ReactDOM.findDOMNode(viewer); - expect(viewerNode.className).toBe('mapstore-annotations-info-viewer'); - - const annotationInfoViewer = TestUtils.findRenderedDOMComponentWithClass(viewer, "mapstore-annotations-info-viewer-items"); - const geometriesToolbar = document.querySelector('.geometries-toolbar'); - const geometryCard = document.querySelectorAll('.geometry-card'); - expect(annotationInfoViewer).toBeTruthy(); - expect(geometriesToolbar).toBeTruthy(); - - const geomButton = geometriesToolbar.children[1].getElementsByTagName('button'); - expect(geomButton.length).toBe(1); - const editMeasureButton = geomButton[0]; - expect(editMeasureButton.children[0].className).toContain(feature.iconGlyph); - expect(geometryCard.length).toBe(2); - - // Edit measurement - TestUtils.Simulate.click(editMeasureButton); - expect(spyOnSetAnnotationMeasurement).toHaveBeenCalled(); - expect(spyOnHideMeasureWarning).toHaveBeenCalled(); - expect(spyOnSetAnnotationMeasurement.calls[0].arguments).toBeTruthy(); - expect(spyOnSetAnnotationMeasurement.calls[0].arguments.length).toBe(2); - const features = spyOnSetAnnotationMeasurement.calls[0].arguments[0]; - const properties = spyOnSetAnnotationMeasurement.calls[0].arguments[1]; - expect(features.length).toBe(1); - expect(features[0].geometry.type).toBe('LineString'); - expect(properties).toBeTruthy(); - expect(Object.keys(properties).length > 0).toBe(true); - }); - - it('test Measurement geometry', () => { - const properties = { - id: "1", - title: 'Measure Length', - description: 'Description', - type: "Measure", - iconGlyph: "1-measure-length" - }; - const feature = { - properties, - features: [{ - type: 'Feature', - geometry: {type: "LineString"}, - properties: { - id: 1, - values: [{ - value: '1511', - formattedValues: "1,511 m", - position: [1, 1], - type: 'length' - }] - } - }, - {type: 'Feature', geometry: {type: "Point"}}], - style: [{}] - }; - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toBeTruthy(); - const viewerNode = ReactDOM.findDOMNode(viewer); - expect(viewerNode.className).toBe('mapstore-annotations-info-viewer'); - - const annotationInfoViewer = TestUtils.findRenderedDOMComponentWithClass(viewer, "mapstore-annotations-info-viewer-items"); - const geometryCard = document.querySelectorAll('.geometry-card'); - expect(annotationInfoViewer).toBeTruthy(); - expect(geometryCard.length).toBe(2); - - // Onclick of measurement geometry - TestUtils.Simulate.click(geometryCard[0]); - const navTabs = document.querySelector('.nav-tabs'); - expect(navTabs.children.length).toBe(1); - const styleTab = navTabs.children[0].childNodes[0].textContent; - expect(styleTab).toContain('Style'); - }); - - it('test onDownload annotation', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - - const spyOnDownload = expect.spyOn(actions, 'onDownload'); - let viewer = ReactDOM.render(, document.getElementById("container")); - - expect(viewer).toExist(); - let viewerNode = ReactDOM.findDOMNode(viewer); - expect(viewerNode.className).toBe('mapstore-annotations-info-viewer'); - - let buttonsRow = viewerNode.querySelector('.mapstore-annotations-info-viewer-buttons .noTopMargin'); - expect(buttonsRow).toBeTruthy(); - - let buttons = buttonsRow.querySelectorAll('button'); - expect(buttons.length).toBe(4); - - let downloadCurrentAnnotation = buttons[3]; - expect(downloadCurrentAnnotation.classList.contains('disabled')).toBe(false); - - TestUtils.Simulate.click(downloadCurrentAnnotation); - expect(spyOnDownload).toHaveBeenCalled(); - expect(spyOnDownload.calls[0].arguments[0]).toEqual({features: [{id: "1"}], properties: feature}); - }); - it('test onDownload when unsavedChanges', ()=>{ - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - - const viewer = ReactDOM.render(, document.getElementById("container")); - - expect(viewer).toExist(); - const viewerNode = ReactDOM.findDOMNode(viewer); - const buttonsRow = viewerNode.querySelector('.mapstore-annotations-info-viewer-buttons .noTopMargin'); - const buttons = buttonsRow.querySelectorAll('button'); - const downloadCurrentAnnotation = buttons[3]; - expect(downloadCurrentAnnotation.classList.contains('disabled')).toBe(true); - }); -}); diff --git a/web/client/components/mapcontrols/annotations/__tests__/DropdownFeatureType-test.js b/web/client/components/mapcontrols/annotations/__tests__/DropdownFeatureType-test.js deleted file mode 100644 index ab9aadfa37..0000000000 --- a/web/client/components/mapcontrols/annotations/__tests__/DropdownFeatureType-test.js +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2019, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. -*/ -import expect from 'expect'; - -import React from 'react'; -import ReactDOM from 'react-dom'; -import DropdownFeatureType from '../DropdownFeatureType'; - -const titles = { - marker: "marker", - line: "line", - polygon: "polygon", - circle: "circle", - text: "text" -}; - -const testSpies = (spies, button) => { - expect(button).toExist(); - button.click(); - spies.forEach(spy => { - expect(spy).toHaveBeenCalled(); - }); -}; - -const resetSpies = (spies) => { - spies.forEach(spy => { - spy.restore(); - }); -}; - -describe("test the DropdownFeatureType Panel", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('DropdownFeatureType rendering with defaults', () => { - ReactDOM.render( - , document.getElementById("container") - ); - const items = document.getElementsByTagName("li"); - expect(items).toExist(); - expect(items.length).toBe(5); - const spans = document.getElementsByTagName("span"); - expect(spans).toExist(); - expect(spans.length).toBe(6); - expect(spans[0].className).toBe("glyphicon glyphicon-pencil-add"); - expect(spans[1].className).toBe("glyphicon glyphicon-point"); - expect(spans[2].className).toBe("glyphicon glyphicon-line"); - expect(spans[3].className).toBe("glyphicon glyphicon-polygon"); - expect(spans[4].className).toBe("glyphicon glyphicon-text-colour"); - expect(spans[5].className).toBe("glyphicon glyphicon-1-circle"); - }); - - it('DropdownFeatureType testing the actions', () => { - - const testHandlers = { - onClick: () => {}, - onStartDrawing: () => {}, - onSetStyle: () => {}, - onAddText: () => {} - }; - - const spyOnClick = expect.spyOn(testHandlers, 'onClick'); - const spyOnSetStyle = expect.spyOn(testHandlers, 'onSetStyle'); - const spyOnStartDrawing = expect.spyOn(testHandlers, 'onStartDrawing'); - const spyOnAddText = expect.spyOn(testHandlers, 'onAddText'); - - const spies = [spyOnClick, spyOnSetStyle, spyOnStartDrawing]; - ReactDOM.render( - , document.getElementById("container") - ); - const buttons = document.getElementsByTagName("a"); - - const marker = buttons[0]; - testSpies(spies, marker); - expect(spyOnClick).toHaveBeenCalledWith("Point"); - resetSpies(spies); - - const line = buttons[1]; - testSpies(spies, line); - expect(spyOnClick).toHaveBeenCalledWith("LineString"); - resetSpies(spies); - - const polygon = buttons[2]; - testSpies(spies, polygon); - expect(spyOnClick).toHaveBeenCalledWith("Polygon"); - resetSpies(spies); - - const text = buttons[3]; - testSpies([...spies, spyOnAddText], text); - expect(spyOnClick).toHaveBeenCalledWith("Text"); - resetSpies(spies); - - const circle = buttons[4]; - testSpies(spies, circle); - expect(spyOnClick).toHaveBeenCalledWith("Circle"); - resetSpies(spies); - }); -}); diff --git a/web/client/components/mapcontrols/annotations/__tests__/FeatureList-test.js b/web/client/components/mapcontrols/annotations/__tests__/FeatureList-test.js deleted file mode 100644 index 6ed0274547..0000000000 --- a/web/client/components/mapcontrols/annotations/__tests__/FeatureList-test.js +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright 2020, GeoSolutions Sas. - * All rights reserved. - * - * 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 FeaturesList from '../FeaturesList'; - -import TestUtils from 'react-dom/test-utils'; - -describe("test FeatureList component", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.body); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('test render FeaturesList', () => { - ReactDOM.render(, document.getElementById("container")); - const container = document.getElementById('container'); - expect(container).toBeTruthy(); - }); - - it('test render with default properties', () => { - ReactDOM.render(, document.getElementById("container")); - const container = document.getElementById('container'); - expect(container).toBeTruthy(); - const labels = container.querySelectorAll(".control-label"); - expect(labels[0].innerText).toBe('annotations.geometries'); - const buttons = container.querySelectorAll("button"); - expect(buttons.length).toBe(5); - expect(container.innerText).toContain('annotations.addGeometry'); - }); - - it('test render with measurement annotation properties', () => { - ReactDOM.render(, document.getElementById("container")); - const container = document.getElementById('container'); - expect(container).toBeTruthy(); - const buttons = container.querySelectorAll("button"); - expect(buttons.length).toBe(1); - }); - it('test geometries toolbar', () => { - const editing = { - features: [{ - properties: {id: '1', isValidFeature: true, geometryTitle: 'Polygon'}, - geometry: {type: "Polygon"} - }] - }; - const actions = { - onAddGeometry: () => {}, - onSetStyle: () => {}, - onStyleGeometry: () => {}, - onStartDrawing: () => {}, - onAddText: () => {} - }; - const defaultStyle = {POINT: { - marker: ["Test marker"], - symbol: ["Test symbol"] - }}; - const spyOnAddGeometry = expect.spyOn(actions, "onAddGeometry"); - const spyOnSetStyle = expect.spyOn(actions, "onSetStyle"); - const spyOnStyleGeometry = expect.spyOn(actions, "onStyleGeometry"); - const spyOnStartDrawing = expect.spyOn(actions, "onStartDrawing"); - const spyOnAddText = expect.spyOn(actions, "onAddText"); - ReactDOM.render(, document.getElementById("container")); - const container = document.getElementById('container'); - expect(container).toBeTruthy(); - - const geometriesToolbar = document.querySelector('.geometries-toolbar'); - const buttons = geometriesToolbar.children[1].getElementsByTagName('button'); - [...buttons].forEach((btn, index)=>{ - TestUtils.Simulate.click(btn); - expect(spyOnSetStyle).toHaveBeenCalled(); - if (index === 0) { - const [style] = spyOnSetStyle.calls[0].arguments[0]; - expect(style["0"]).toEqual('Test symbol'); - } - index === 3 && expect(spyOnAddText).toHaveBeenCalled(); - expect(spyOnAddGeometry).toHaveBeenCalled(); - expect(spyOnStartDrawing).toHaveBeenCalled(); - expect(spyOnStyleGeometry).toHaveBeenCalled(); - }); - }); - it('test render with feature card', () => { - const editing = { - features: [{ - properties: {id: '1', isValidFeature: true, geometryTitle: 'Polygon'}, - geometry: {type: "Polygon"} - }] - }; - ReactDOM.render(, document.getElementById("container")); - const container = document.getElementById('container'); - expect(container).toBeTruthy(); - - const cardContainer = document.getElementsByClassName('geometry-card'); - expect(cardContainer).toBeTruthy(); - - const previewIcon = document.querySelector('.glyphicon-polygon'); - expect(previewIcon).toBeTruthy(); - - const cardTitle = document.querySelector('.geometry-card-label'); - expect(cardTitle.innerText).toBe('Polygon'); - - const glyphIcons = document.querySelectorAll('.btn-group .glyphicon'); - expect(glyphIcons.length).toBe(7); - expect(glyphIcons[5].className).toContain('zoom-to'); - expect(glyphIcons[6].className).toContain('trash'); - }); - - it('test actions on feature card', () => { - const editing = { - features: [{ - type: "Feature", - properties: {id: '1', isValidFeature: true, geometryTitle: 'Polygon'}, - geometry: {type: "Polygon", coordinates: [ - [ - [-121.07812513411045, 42.11778385718358], - [-116.2265622317791, 44.72175879125132], - [-115.87499973177908, 40.773885871584866], - [-114.96093589067458, 42.68889580392076], - [-121.07812513411045, 42.11778385718358] - ] - ]} - }] - }; - const testHandlers = { - onSelectFeature: () => {}, - onUnselectFeature: () => {}, - onStyleGeometry: () => {}, - onZoom: () => {}, - onDeleteGeometry: () => {}, - setTabValue: () => {} - }; - const spyOnSelectFeature = expect.spyOn(testHandlers, "onSelectFeature"); - const spyOnZoom = expect.spyOn(testHandlers, "onZoom"); - const spyOnDeleteGeometry = expect.spyOn(testHandlers, "onDeleteGeometry"); - const spyOnStyleGeometry = expect.spyOn(testHandlers, "onStyleGeometry"); - ReactDOM.render( - , document.getElementById("container")); - const container = document.getElementById('container'); - expect(container).toBeTruthy(); - - const featureCard = document.getElementsByClassName('geometry-card'); - expect(featureCard).toBeTruthy(); - - const buttons = document.querySelectorAll('button'); - - // OnSelectFeature - TestUtils.Simulate.click(featureCard[0]); - expect(spyOnSelectFeature).toHaveBeenCalled(); - expect(spyOnSelectFeature.calls[0].arguments[0]).toEqual(editing.features); - expect(spyOnStyleGeometry).toHaveBeenCalled(); - expect(spyOnStyleGeometry.calls[0].arguments[0]).toBe(false); - - // OnZoomGeometry - TestUtils.Simulate.click(buttons[5]); - expect(spyOnZoom).toHaveBeenCalled(); - expect(spyOnZoom.calls[0].arguments[1]).toBe("EPSG:4326"); - - // OnDeleteGeometry - TestUtils.Simulate.click(buttons[6]); - expect(spyOnDeleteGeometry).toHaveBeenCalled(); - expect(spyOnDeleteGeometry.calls[0].arguments[0]).toBe("1"); - }); - - it('test unselect a geometry', () => { - const props = { - editing: { - features: [{ - type: "Feature", - properties: {id: '1', isValidFeature: true, geometryTitle: 'Polygon'}, - geometry: {type: "Polygon"} - }] - }, - selected: {properties: {id: '1'}} - }; - const testHandlers = { - onUnselectFeature: () => {}, - onGeometryHighlight: () => {} - }; - const spyOnUnselectFeature = expect.spyOn(testHandlers, "onUnselectFeature"); - const spyOnGeometryHighlight = expect.spyOn(testHandlers, "onGeometryHighlight"); - ReactDOM.render(, document.getElementById("container")); - const container = document.getElementById('container'); - expect(container).toBeTruthy(); - - const featureCard = document.getElementsByClassName('geometry-card'); - expect(featureCard).toBeTruthy(); - - // OnUnSelectFeature - TestUtils.Simulate.click(featureCard[0]); - expect(spyOnUnselectFeature).toHaveBeenCalled(); - expect(spyOnGeometryHighlight).toHaveBeenCalled(); - expect(spyOnGeometryHighlight.calls[0].arguments[0]).toBe('1'); - }); - - it('test geometry highlight', () => { - let props = { - editing: { - features: [{ - type: "Feature", - properties: {id: '1', isValidFeature: true, geometryTitle: 'Polygon'}, - geometry: {type: "Polygon"} - }] - }, - selected: {properties: {id: '1'}} - }; - const testHandlers = { - onGeometryHighlight: () => {} - }; - const spyOnGeometryHighlight = expect.spyOn(testHandlers, "onGeometryHighlight"); - ReactDOM.render(, document.getElementById("container")); - let container = document.getElementById('container'); - expect(container).toBeTruthy(); - - let featureCard = document.getElementsByClassName('geometry-card'); - expect(featureCard).toBeTruthy(); - - TestUtils.Simulate.mouseEnter(featureCard[0]); - expect(spyOnGeometryHighlight).toNotHaveBeenCalled(); - - // When geometry card is not selected - props = {...props, selected: {...props.selected, properties: {id: 2}}}; - ReactDOM.render(, document.getElementById("container")); - container = document.getElementById('container'); - featureCard = document.getElementsByClassName('geometry-card'); - // OnMouseEnter - TestUtils.Simulate.mouseEnter(featureCard[0]); - expect(spyOnGeometryHighlight).toHaveBeenCalled(); - expect(spyOnGeometryHighlight.calls[0].arguments[0]).toBe('1'); - - // OnMouseLeave - TestUtils.Simulate.mouseLeave(featureCard[0]); - expect(spyOnGeometryHighlight).toHaveBeenCalled(); - expect(spyOnGeometryHighlight.calls[1].arguments[0]).toBe('1'); - expect(spyOnGeometryHighlight.calls[1].arguments[1]).toBe(false); - }); - - it('test geometry highlight limitations', () => { - let props = { - editing: { - features: [{ - type: "Feature", - properties: {id: '1', isValidFeature: false, geometryTitle: 'Polygon'}, - geometry: {type: "Polygon"} - }] - }, - selected: {properties: {id: '2', isValidFeature: false}} - }; - const testHandlers = { - onGeometryHighlight: () => {} - }; - const spyOnGeometryHighlight = expect.spyOn(testHandlers, "onGeometryHighlight"); - ReactDOM.render(, document.getElementById("container")); - let container = document.getElementById('container'); - expect(container).toBeTruthy(); - - let featureCard = document.getElementsByClassName('geometry-card'); - expect(featureCard).toBeTruthy(); - - ReactDOM.render(, document.getElementById("container")); - container = document.getElementById('container'); - featureCard = document.getElementsByClassName('geometry-card'); - // OnMouseEnter - TestUtils.Simulate.mouseEnter(featureCard[0]); - expect(spyOnGeometryHighlight).toNotHaveBeenCalled(); - - // OnMouseLeave - TestUtils.Simulate.mouseLeave(featureCard[0]); - expect(spyOnGeometryHighlight).toNotHaveBeenCalled(); - }); - - it('test render defaults with defaultPointType as symbol', () => { - ReactDOM.render(, document.getElementById("container")); - const container = document.getElementById('container'); - expect(container).toBeTruthy(); - const labels = container.querySelectorAll(".control-label"); - expect(labels[0].innerText).toBe('annotations.geometries'); - const buttons = container.querySelectorAll("button"); - expect(buttons.length).toBe(5); - expect(container.innerText).toContain('annotations.addGeometry'); - }); -}); diff --git a/web/client/components/mapcontrols/annotations/__tests__/SelectAnnotationsFile-test.js b/web/client/components/mapcontrols/annotations/__tests__/SelectAnnotationsFile-test.js deleted file mode 100644 index e4b228d7a2..0000000000 --- a/web/client/components/mapcontrols/annotations/__tests__/SelectAnnotationsFile-test.js +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2018, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ -import expect from 'expect'; - -import React from 'react'; -import ReactDOM from 'react-dom'; -import SelectAnnotationsFile from '../SelectAnnotationsFile'; - - -describe("test the SelectAnnotationsFile modal", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.body); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('test default properties', () => { - const annotations = ReactDOM.render(, document.getElementById("container")); - expect(annotations).toExist(); - const annotationsNode = ReactDOM.findDOMNode(annotations); - expect(annotationsNode).toNotExist(); - }); - it('test file selected', (done) => { - const jsonFile = new File([`{ "coordinates": [ - 4.6142578125, - 45.67548217560647 - ], - "type": "Point" - }` - ], "file.json", { - type: "application/json" - }); - const onFileChoosen = (features, override) => { - expect(features instanceof Array).toBe(true); - expect(features.length).toBe(1); - expect(override).toBe(false); - done(); - }; - const annotations = ReactDOM.render(, document.getElementById("container")); - expect(annotations).toExist(); - const annotationsNode = ReactDOM.findDOMNode(annotations); - expect(annotationsNode).toExist(); - annotations.checkfile([jsonFile]); - }); - - it('test file selected to fail', (done) => { - const jsonFile = new File([`[{ - "geometry": { - "type": "MultiPolygon" - }, - "properties": { - "id": "25cbbbb0-1625-11e8-a091-639e3ca0149f", - "title": "Pino" - }, - "style": { - "highlight": false - }, - "type": "Feature" - }]` - ], "file.txt", { - type: "text/plain" - }); - const annotations = ReactDOM.render(, document.getElementById("container")); - expect(annotations).toExist(); - const annotationsNode = ReactDOM.findDOMNode(annotations); - expect(annotationsNode).toExist(); - annotations.componentDidUpdate = () => { - if (annotations.state.error) { - expect(annotations.state.error).toExist(); - done(); - } - }; - annotations.checkfile([jsonFile]); - }); - -}); diff --git a/web/client/components/style/BandSelector.jsx b/web/client/components/style/BandSelector.jsx deleted file mode 100644 index da5722df1e..0000000000 --- a/web/client/components/style/BandSelector.jsx +++ /dev/null @@ -1,128 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -import PropTypes from 'prop-types'; -import React from 'react'; -import { Col, Grid, Row } from 'react-bootstrap'; -import { Combobox, NumberPicker } from 'react-widgets'; -import numberLocalizer from 'react-widgets/lib/localizers/simple-number'; - -import { getMessageById } from '../../utils/LocaleUtils'; -import Message from '../I18N/Message'; - -numberLocalizer(); - - -class BandSelector extends React.Component { - static propTypes = { - band: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), - bands: PropTypes.array, - min: PropTypes.number, - max: PropTypes.number, - contrast: PropTypes.oneOf(['none', 'Normalize', 'Histogram', 'GammaValue']), - algorithm: PropTypes.oneOf(['none', 'StretchToMinimumMaximum', 'ClipToMinimumMaximum', 'ClipToZero']), - gammaValue: PropTypes.number, - onChange: PropTypes.func, - bandsComboOptions: PropTypes.object - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - band: '1', - contrast: "none", - algorithm: "none", - gammaValue: 1, - min: 0, - max: 255, - bandsComboOptions: {}, - onChange: () => {}, - bands: ['1', '2', '3'] - }; - - render() { - return ( - - - - - {this.props.contrast === "GammaValue" ? : null } - {this.props.contrast === "Normalize" ? : null } - - - - this.props.onChange("band", v)} - {...this.props.bandsComboOptions}/> - - - this.props.onChange("contrast", v.value)}/> - - { this.props.contrast === "GammaValue" ? - this.props.onChange("gammaValue", v)}/> : null} - { this.props.contrast === "Normalize" ? - - this.props.onChange("algorithm", v.value)}/> - - : null} - - {this.props.contrast === "Normalize" && this.props.algorithm !== "none" ? - - - - : null } - {this.props.contrast === "Normalize" && this.props.algorithm !== "none" ? - - - this.props.onChange("min", v)} - /> - - this.props.onChange("max", v)} - /> - : null } - ); - } -} - -export default BandSelector; diff --git a/web/client/components/style/CircleStyler.jsx b/web/client/components/style/CircleStyler.jsx deleted file mode 100644 index bcf6b74aa8..0000000000 --- a/web/client/components/style/CircleStyler.jsx +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2018, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. -*/ - -import PropTypes from 'prop-types'; - -import React from 'react'; -import assign from 'object-assign'; -import { Grid, Row, Col } from 'react-bootstrap'; -import ColorSelector from './ColorSelector'; -import StyleCanvas from './StyleCanvas'; -import Slider from 'react-nouislider'; -import numberLocalizer from 'react-widgets/lib/localizers/simple-number'; -numberLocalizer(); -import { isNil } from 'lodash'; -import Message from '../I18N/Message'; -import tinycolor from 'tinycolor2'; - -class StylePolygon extends React.Component { - static propTypes = { - shapeStyle: PropTypes.object, - width: PropTypes.number, - setStyleParameter: PropTypes.func - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - shapeStyle: {}, - setStyleParameter: () => {} - }; - - render() { - const styleType = "Circle"; - const style = this.props.shapeStyle[styleType] || this.props.shapeStyle; // in case of old version of style. - return ( - - -
- -
- -
- - - - - - { - if (!isNil(c)) { - const fillColor = tinycolor(c).toHexString(); - const fillOpacity = c.a; - const newStyle = assign({}, this.props.shapeStyle, { - [styleType]: assign({}, style, {fillColor, fillOpacity}) - }); - this.props.setStyleParameter(newStyle); - } - }}/> - - - - - - - - { - if (!isNil(c)) { - const color = tinycolor(c).toHexString(); - const opacity = c.a; - const newStyle = assign({}, this.props.shapeStyle, { - [styleType]: assign({}, style, {color, opacity}) - }); - this.props.setStyleParameter(newStyle); - } - }}/> - - - - - - - -
- Math.round(value), - to: value => Math.round(value) + ' px' - }} - range={{min: 1, max: 15}} - onChange={(values) => { - const weight = parseInt(values[0].replace(' px', ''), 10); - const newStyle = assign({}, this.props.shapeStyle, { - [styleType]: assign({}, style, {weight}) - }); - this.props.setStyleParameter(newStyle); - }} - /> -
- -
-
); - } - addOpacityToColor = (color, opacity) => { - return assign({}, color, { - a: opacity - }); - } -} - -export default StylePolygon; diff --git a/web/client/components/style/ColorMapGrid.jsx b/web/client/components/style/ColorMapGrid.jsx deleted file mode 100644 index d9208978c3..0000000000 --- a/web/client/components/style/ColorMapGrid.jsx +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * 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 { isEqual } from 'lodash'; -import { AgGridReact } from 'ag-grid-react'; -import PropTypes from 'prop-types'; -import reactCellRendererFactory from './ColorMapGridComponents/ReactCellRendererFactoryParams'; -import ColorPickerRenderer from './ColorMapGridComponents/ColorPickerRenderer'; -import assign from 'object-assign'; -import NumberRenderer from './ColorMapGridComponents/NumberRenderer'; -import { getMessageById } from '../../utils/LocaleUtils'; -import 'ag-grid-community/dist/styles/ag-grid.css'; -import 'ag-grid-community/dist/styles/ag-theme-blue.css'; - -class ColorMapGrid extends React.Component { - static propTypes = { - entries: PropTypes.array, - style: PropTypes.object, - selectEntry: PropTypes.func, - valueChanged: PropTypes.func - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - entries: [], - style: {height: "200px"}, - selectEntry: () => {}, - valueChanged: () => {} - }; - - shouldComponentUpdate(nextProps) { - return !isEqual(nextProps.entries, this.props.entries); - } - - componentDidUpdate() { - this.api.sizeColumnsToFit(); - } - - onGridReady = (params) => { - this.api = params.api; - this.api.sizeColumnsToFit(); - this.columnApi = params.columnApi; - }; - - render() { - return ( -
- -
); - } - - selectEntry = (row) => { - if (row) { - this.props.selectEntry(row.node.childIndex); - } - }; - - valueChanged = () => { - let newData = []; - this.api.getModel().forEachNode((node) => {newData.push(node.data); }); - this.props.valueChanged(newData); - }; - - changeColor = (node, colorOpacity) => { - let newData = []; - this.api.getModel().forEachNode((n, idx) => { - let data = idx === node.childIndex ? assign({}, n.data, colorOpacity) : n.data; - newData.push(data); - }); - this.props.valueChanged(newData); - }; - - changeQuantity = (node, value) => { - let newData = []; - this.api.getModel().forEachNode((n, idx) => { - let data = idx === node.childIndex ? assign({}, n.data, {quantity: value}) : n.data; - newData.push(data); - }); - this.props.valueChanged(newData); - }; -} - -export default ColorMapGrid; diff --git a/web/client/components/style/ColorMapGridComponents/ColorPickerRenderer.jsx b/web/client/components/style/ColorMapGridComponents/ColorPickerRenderer.jsx deleted file mode 100644 index bc175b5877..0000000000 --- a/web/client/components/style/ColorMapGridComponents/ColorPickerRenderer.jsx +++ /dev/null @@ -1,98 +0,0 @@ -import PropTypes from 'prop-types'; - -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * 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 { SketchPicker } from 'react-color'; -import './colorenderer.css'; -import { getWindowSize } from '../../../utils/AgentUtils'; - -class ColorPickerRenderer extends React.Component { - static propTypes = { - params: PropTypes.object, - onChangeColor: PropTypes.func, - disabled: PropTypes.bool - }; - - static defaultProps = { - disabled: false, - onChangeColor: () => {} - }; - - state = { - displayColorPicker: false - }; - - onChangeColor = () => { - if ( this.state.color) { - let opacity = this.state.color.rgb.a !== 1 ? this.state.color.rgb.a : undefined; - let color = this.state.color.hex.indexOf("#") === 0 ? this.state.color.hex : "#" + this.state.color.hex; - this.props.onChangeColor( this.props.params.node, {color: color, opacity: opacity}); - } - }; - - getBackgroundColor = (data) => { - let color = 'blue'; - if ( data && data.color) { - let rgb = this.hexToRgb(data.color); - let opacity = data.opacity !== undefined ? data.opacity : 1; - color = rgb ? `rgba(${ rgb.r }, ${ rgb.g }, ${ rgb.b }, ${ opacity })` : 'blue'; - } - return color; - }; - - render() { - let data = this.props.params.data; - let colorValue = data && data.color ? this.hexToRgb(data.color) : {r: 0, g: 0, b: 255}; - colorValue.a = data.opacity !== undefined ? data.opacity : 1; - let bkgColor = this.getBackgroundColor(data); - return ( -
-
{ - if (!this.props.disabled) { - this.setState({ - displayColorPicker: !this.state.displayColorPicker, - y: e.pageY - }); - } - }} - /> - { this.state.displayColorPicker ? -
-
{ - this.setState({ displayColorPicker: false}); - this.onChangeColor(); - }}/> - { this.setState({ color: color }); }} /> -
- : null } -
- ); - } - - calculateTop = (y) => { - let h = getWindowSize().maxHeight; - return (y + 300 > h ? h - 305 : y ) - 300; - }; - - hexToRgb = (hex) => { - const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); - return result ? { - r: parseInt(result[1], 16), - g: parseInt(result[2], 16), - b: parseInt(result[3], 16) - } : null; - }; -} - -export default ColorPickerRenderer; diff --git a/web/client/components/style/ColorMapGridComponents/NumberRenderer.jsx b/web/client/components/style/ColorMapGridComponents/NumberRenderer.jsx deleted file mode 100644 index 6573d3e796..0000000000 --- a/web/client/components/style/ColorMapGridComponents/NumberRenderer.jsx +++ /dev/null @@ -1,113 +0,0 @@ -import PropTypes from 'prop-types'; - -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * 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 { findDOMNode } from 'react-dom'; -import { Popover, Label, Overlay } from 'react-bootstrap'; -import numberLocalizer from 'react-widgets/lib/localizers/simple-number'; -numberLocalizer(); -import { NumberPicker } from 'react-widgets'; -import './numberpicker.css'; - -class NumberRenderer extends React.Component { - static propTypes = { - params: PropTypes.object, - onChangeValue: PropTypes.func, - errorMessage: PropTypes.string - }; - - static defaultProps = { - onChangeValue: () => {}, - errorMessage: "Value not valid" - }; - - state = { - displayNumberPicker: false, - showError: false - }; - - componentDidMount() { - this.props.params.api.addEventListener('cellClicked', this.cellClicked); - } - - componentWillUnmount() { - this.props.params.api.removeEventListener('cellClicked', this.cellClicked); - } - - getRange = () => { - let data = []; - this.props.params.api.forEachNode((node) => {data.push(node.data); }); - let idx = this.props.params.node.childIndex; - let min = data[idx - 1] ? data[idx - 1].quantity + 0.01 : -Infinity; - let max = data[idx + 1] ? data[idx + 1].quantity - 0.01 : Infinity; - return {min: min, max: max}; - }; - - render() { - - return ( -
{ - if (!this.state.displayNumberPicker) { - this.setState({displayNumberPicker: !this.state.displayNumberPicker}); - } - } } - > - { this.state.displayNumberPicker ? -
-
-
{e.stopPropagation(); }}> - - findDOMNode(this.refs.colorMapNumberPicker)} - show={this.state.showError} placement="top" > - - - - -
-
: - {this.props.params.value.toFixed ? this.props.params.value.toFixed(2) : this.props.params.value} } -
- ); - } - - cellClicked = (e) => { - if (this.props.params.value !== e.value && this.state.displayNumberPicker) { - this.stopEditing(); - } - }; - - stopEditing = () => { - let range = this.getRange(); - let newValue = this.state.value === undefined ? this.props.params.value : this.state.value; - if (range.min < newValue && newValue < range.max) { - this.setState({ displayNumberPicker: false, showError: false}); - if (newValue !== this.props.params.value) { - this.props.onChangeValue(this.props.params.node, newValue); - } - } else { - this.setState({showError: true}); - } - - }; - - changeNumber = (value) => { - this.setState({value: value, showError: false}); - }; -} - -export default NumberRenderer; diff --git a/web/client/components/style/ColorMapGridComponents/ReactCellRendererFactoryParams.jsx b/web/client/components/style/ColorMapGridComponents/ReactCellRendererFactoryParams.jsx deleted file mode 100644 index c6ab15917f..0000000000 --- a/web/client/components/style/ColorMapGridComponents/ReactCellRendererFactoryParams.jsx +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * 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'; -function reactCellRendererFactoryParams(ReactComponent, compParams) { - return function(params) { - if (params.eParentOfValue.addElementAttachedListener) { - params.eParentOfValue.addElementAttachedListener(function(eCell) { - ReactDOM.render(, eCell); - params.api.addVirtualRowListener('virtualRowRemoved', params.rowIndex, function() { - ReactDOM.unmountComponentAtNode(eCell); - }); - }); - } - // return null to the grid, as we don't want it responsible for rendering - return null; - }; -} -export default reactCellRendererFactoryParams; diff --git a/web/client/components/style/ColorMapGridComponents/colorenderer.css b/web/client/components/style/ColorMapGridComponents/colorenderer.css deleted file mode 100644 index 702fc25e97..0000000000 --- a/web/client/components/style/ColorMapGridComponents/colorenderer.css +++ /dev/null @@ -1,28 +0,0 @@ -.cpr-color - { - box-sizing: border-box; - width: 100%; - min-height: 28px; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - padding: 2px; - -} -.cpe-popover -{ - white-space: normal; - position: fixed; - z-index: 1000; -} -.cpe-cover -{ - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; -} -.cpe-popover > div > div { - position: relative; -} diff --git a/web/client/components/style/ColorMapGridComponents/numberpicker.css b/web/client/components/style/ColorMapGridComponents/numberpicker.css deleted file mode 100644 index 85f3585a0a..0000000000 --- a/web/client/components/style/ColorMapGridComponents/numberpicker.css +++ /dev/null @@ -1,7 +0,0 @@ -.numberpicker { - font-size: small; - -ms-transform: scaleY(0.9) translateY(-2px); /* IE 9 */ - -webkit-transform: scaleY(0.9) translateY(-2px); /* Chrome, Safari, Opera */ - transform: scaleY(0.9) translateY(-2px); - -} \ No newline at end of file diff --git a/web/client/components/style/ColorRampSelector.jsx b/web/client/components/style/ColorRampSelector.jsx deleted file mode 100644 index 10314f00a5..0000000000 --- a/web/client/components/style/ColorRampSelector.jsx +++ /dev/null @@ -1,72 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import colorsSchema from './EqualIntervalComponents/ColorRamp'; -import ColorRampItem from './EqualIntervalComponents/ColorRampItem'; -import colors from './EqualIntervalComponents/ExtendColorBrewer'; -import { Combobox } from 'react-widgets'; - -class ColorRampSelector extends React.Component { - - static propTypes = { - colorsSchema: PropTypes.array, - colors: PropTypes.object, - classes: PropTypes.number, - ramp: PropTypes.string - }; - - static defaultProps = { - colorsSchema, - colors, - classes: 5, - ramp: 'Blues' - }; - - UNSAFE_componentWillMount() { - this.setState({ - ramp: this.props.ramp - }); - } - - getColorsSchema = () => { - return this.props.classes ? - this.props.colorsSchema.filter((c) => { - return c.max >= this.props.classes; - }, this) : this.props.colorsSchema; - }; - - getRampValue = () => { - let ramp = this.state.ramp; - if (!this.props.colors[this.state.ramp][this.props.classes]) { - ramp = this.props.colorsSchema.filter((color) => { return color.max >= this.props.classes; }, this)[0].name; - } - return ramp; - }; - - getRamp = () => { - return this.props.colors[this.state.ramp] ? ( - this.props.colors[this.state.ramp][5].map(c => { - return
; - }) - ) : null; - } - - render() { - return (
-
- {this.getRamp()} -
- { - this.setState({ - ramp: ramp.name - }); - }}/> -
); - } -} - -export default ColorRampSelector; diff --git a/web/client/components/style/ColorRangeSelector.jsx b/web/client/components/style/ColorRangeSelector.jsx deleted file mode 100644 index cab4a35ba4..0000000000 --- a/web/client/components/style/ColorRangeSelector.jsx +++ /dev/null @@ -1,79 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { sameToneRangeColors } from '../../utils/ColorUtils'; -import ColorRampItem from './EqualIntervalComponents/ColorRampItem'; -import { DropdownList } from 'react-widgets'; -import { head } from 'lodash'; - -class ColorRangeSelector extends React.Component { - - static propTypes = { - value: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), - samples: PropTypes.number, - onChange: PropTypes.func, - items: PropTypes.array, - rampFunction: PropTypes.func, - disabled: PropTypes.bool - }; - static contextTypes = { - messages: PropTypes.object - }; - static defaultProps = { - samples: 5, - onChange: () => {}, - items: [{ - name: 'global.colors.blue', - schema: 'sequencial', - options: {base: 190, range: 20} - }, { - name: 'global.colors.red', - schema: 'sequencial', - options: {base: 10, range: 4} - }, { - name: 'global.colors.green', - schema: 'sequencial', - options: {base: 120, range: 4} - }, { - name: 'global.colors.brown', - schema: 'sequencial', - options: {base: 30, range: 4, s: 1, v: 0.5} - }, { - name: 'global.colors.purple', - schema: 'sequencial', - options: {base: 300, range: 4} - }, { - name: 'global.colors.random', - schema: 'qualitative', - options: {base: 190, range: 340, options: {base: 10, range: 360, s: 0.67, v: 0.67}} - }], - disabled: false - }; - getValue = () => { - return head(this.getItems().filter( (i = {}) => i === this.props.value || i.name === (this.props.value && this.props.value.name))); - } - getItems = () => { - return this.props.items.map(({options = {}, ...item}) => ({ - ...item, - options, - ramp: this.props.rampFunction ? this.props.rampFunction(item, options) : (sameToneRangeColors(options.base, options.range, this.props.samples + 1, options.options) || ["#AAA"]).splice(1) - })); - } - - render() { - const items = this.getItems(); - return ( - } - itemComponent={ColorRampItem} - value={this.getValue()} - onChange={(ramp) => { - this.props.onChange(ramp); - }}/> - ); - } -} - -export default ColorRangeSelector; diff --git a/web/client/components/style/EqualInterval.jsx b/web/client/components/style/EqualInterval.jsx deleted file mode 100644 index cda76103f3..0000000000 --- a/web/client/components/style/EqualInterval.jsx +++ /dev/null @@ -1,204 +0,0 @@ - -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -import PropTypes from 'prop-types'; -import React from 'react'; -import { Col, Grid, Label, Overlay, Popover, Row } from 'react-bootstrap'; -import { findDOMNode } from 'react-dom'; -import { Combobox, NumberPicker } from 'react-widgets'; -import numberLocalizer from 'react-widgets/lib/localizers/simple-number'; - -import Message from '../I18N/Message'; -import colorsSchema from './EqualIntervalComponents/ColorRamp'; -import ColorRampItem from './EqualIntervalComponents/ColorRampItem'; -import colors from './EqualIntervalComponents/ExtendColorBrewer'; -import Button from '../misc/Button'; - -numberLocalizer(); - - -class EqualInterval extends React.Component { - static propTypes = { - min: PropTypes.number, - max: PropTypes.number, - classes: PropTypes.number, - onChange: PropTypes.func, - onClassify: PropTypes.func, - ramp: PropTypes.string, - error: PropTypes.object - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - min: 0, - max: 100, - classes: 5, - ramp: "Blues", - onChange: () => {}, - onClassify: () => {}, - error: null - }; - - shouldComponentUpdate() { - return true; - } - - getColorsSchema = () => { - return this.props.classes ? - colorsSchema.filter((c) => { - return c.max >= this.props.classes; - }, this) : colorsSchema; - }; - - getRampValue = () => { - let ramp = this.props.ramp; - if (!colors[this.props.ramp][this.props.classes]) { - ramp = colorsSchema.filter((color) => { return color.max >= this.props.classes; }, this)[0].name; - } - return ramp; - }; - - renderErrorPopOver = () => { - return ( - findDOMNode(this.refs[this.props.error.type])} - show placement="top" > - - - - - ); - }; - - render() { - return ( - - - - - - - - - {this.props.error && this.props.error.type === 'min' ? this.renderErrorPopOver() : null} - - - - - - - - - {this.props.error && this.props.error.type === 'max' ? this.renderErrorPopOver() : null} - - - - - - - - - - - this.props.onChange("classes", number)} - precision={0} min={3} max={12} step={1} - value={this.props.classes} - /> - - - - - - - - - - - this.props.onChange("ramp", value.name)} - textField="name" - itemComponent={ColorRampItem} value={this.getRampValue()}/> - - - - - - - - - - ); - } - - classifyDisabled = () => { - return this.props.error && this.props.error.type ? true : false; - }; - - generateEqualIntervalRamp = () => { - let ramp = colors[this.getRampValue()][this.props.classes]; - let min = this.props.min; - let max = this.props.max; - let step = (max - min) / this.props.classes; - let colorRamp = ramp.map((color, idx) => { - return {color: color, quantity: min + idx * step}; - }); - this.props.onClassify("colorRamp", colorRamp); - }; - - changeMin = (value) => { - if (value < this.props.max) { - if (this.props.error) { - this.props.onChange("error", {}); - } - this.props.onChange("min", value); - } else { - this.props.onChange("error", { - type: "min", - msg: "equalinterval.minerror" - }); - } - - }; - - changeMax = (value) => { - if (value > this.props.min) { - if (this.props.error) { - this.props.onChange("error", {}); - } - this.props.onChange("max", value); - } else { - this.props.onChange("error", { - type: "max", - msg: "equalinterval.maxerror" - }); - } - }; -} - -export default EqualInterval; diff --git a/web/client/components/style/EqualIntervalComponents/ColorRamp.js b/web/client/components/style/EqualIntervalComponents/ColorRamp.js deleted file mode 100644 index 5d04aa786a..0000000000 --- a/web/client/components/style/EqualIntervalComponents/ColorRamp.js +++ /dev/null @@ -1,17 +0,0 @@ -const colorsSchema = [ - {name: "BuGn", schema: "Sequential", max: 9}, {name: "BuPu", schema: "Sequential", max: 9}, {name: "GnBu", schema: "Sequential", max: 9}, - {name: "OrRd", schema: "Sequential", max: 9}, {name: "PuBu", schema: "Sequential", max: 9}, {name: "PuBuGn", schema: "Sequential", max: 9}, - {name: "PuRd", schema: "Sequential", max: 9}, {name: "RdPu", schema: "Sequential", max: 9}, {name: "YlGn", schema: "Sequential", max: 9}, - {name: "YlGnBu", schema: "Sequential", max: 9}, {name: "YlOrBr", schema: "Sequential", max: 9}, {name: "YlOrRd", schema: "Sequential", max: 9}, - {name: "Blues", schema: "Singlehue", max: 9}, {name: "Greens", schema: "Singlehue", max: 9}, {name: "Greys", schema: "Singlehue", max: 9}, - {name: "Oranges", schema: "Singlehue", max: 9}, {name: "Purples", schema: "Singlehue", max: 9}, {name: "Reds", schema: "Singlehue", max: 9}, - {name: "BrBG", schema: "Diverging", max: 11}, {name: "PiYG", schema: "Diverging", max: 11}, {name: "PRGn", schema: "Diverging", max: 11}, - {name: "PuOr", schema: "Diverging", max: 11}, {name: "RdBu", schema: "Diverging", max: 11}, {name: "RdGy", schema: "Diverging", max: 11}, - {name: "RdYlBu", schema: "Diverging", max: 11}, {name: "RdYlGn", schema: "Diverging", max: 11}, {name: "Spectral", schema: "Diverging", max: 11}, - {name: "Accent", schema: "Qualitative", max: 8}, {name: "Dark2", schema: "Qualitative", max: 8}, {name: "Paired", schema: "Qualitative", max: 12}, - {name: "Pastel1", schema: "Qualitative", max: 9}, {name: "Pastel2", schema: "Qualitative", max: 8}, {name: "Set1", schema: "Qualitative", max: 9}, - {name: "Set2", schema: "Qualitative", max: 8}, {name: "Set3", schema: "Qualitative", max: 12}, {name: "Earth", schema: "Dem", max: 12}, - {name: "Land", schema: "Dem", max: 12}, {name: "Water", schema: "Dem", max: 12}, {name: "CDA", schema: "Dem", max: 12}, - {name: "Simple", schema: "Dem", max: 7}]; - -export default colorsSchema; diff --git a/web/client/components/style/EqualIntervalComponents/ColorRampItem.jsx b/web/client/components/style/EqualIntervalComponents/ColorRampItem.jsx deleted file mode 100644 index e7b78d4f7f..0000000000 --- a/web/client/components/style/EqualIntervalComponents/ColorRampItem.jsx +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright 2019, GeoSolutions Sas. - * All rights reserved. - * - * 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 PropTypes from 'prop-types'; -import colors from './ExtendColorBrewer'; -import Message from '../../I18N/Message'; - -/** - * @name ColorRampItem - * @description Simple component to display color label - */ -const ColorRampItem = ({ item }) => { - let ramp = item && (item.ramp || colors[item.name] && colors[item.name][5]) || []; - return ( -
- {ramp.map(cell =>
)} -
- {item && ( item.label || item.name ) - ? - : item} -
-
- ); -}; - -ColorRampItem.propTypes = { - item: PropTypes.oneOfType([PropTypes.string, PropTypes.object]) -}; - -export default ColorRampItem; diff --git a/web/client/components/style/EqualIntervalComponents/ExtendColorBrewer.js b/web/client/components/style/EqualIntervalComponents/ExtendColorBrewer.js deleted file mode 100644 index b539a09ebe..0000000000 --- a/web/client/components/style/EqualIntervalComponents/ExtendColorBrewer.js +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright 2017, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -const extendColorBrewer = { - Earth: { - 3: ["#3e2f8d", "#d3e1b2", "#f1e8dd"], - 4: ["#3e2f8d", "#a4cef4", "#676c52", "#f1e8dd"], - 5: ["#3e2f8d", "#87b2f1", "#d3e1b2", "#615742", "#f1e8dd"], - 6: ["#3e2f8d", "#739cd3", "#cbe1da", "#8e9f79", "#7e6d4f", "#f1e8dd"], - 7: ["#3e2f8d", "#6a8dc7", "#a4cef4", "#d3e1b2", "#676c52", "#89795d", "#f1e8dd"], - 8: ["#3e2f8d", "#6783c7", "#94c0fb", "#e1e9ca", "#a3b990", "#524d3d", "#908169", "#f1e8dd"], - 9: ["#3e2f8d", "#657bc7", "#87b2f1", "#b9dae8", "#d3e1b2", "#7b8965", "#615742", "#948671", "#f1e8dd"], - 10: ["#3e2f8d", "#6375c7", "#7ca6e0", "#a4cef4", "#eceec1", "#afc79c", "#676c52", "#716349", "#988b78", "#f1e8dd"], - 11: ["#3e2f8d", "#6271c7", "#739cd3", "#99c4f9", "#cbe1da", "#d3e1b2", "#8e9f79", "#585743", "#7e6d4f", "#9b8f7e", "#f1e8dd"], - 12: ["#3e2f8d", "#616dc7", "#6c93c7", "#8fbcfe", "#aed6f1", "#f1f0be", "#bbd5a9", "#788562", "#504a3b", "#847252", "#9b8f7e", "#f1e8dd"] - }, - Land: { - 3: ["#c3e2df", "#2f412c", "#e7e9dd"], - 4: ["#c3e2df", "#5d7a65", "#3f3633", "#e7e9dd"], - 5: ["#c3e2df", "#868f65", "#2f412c", "#5c4e4b", "#e7e9dd"], - 6: ["#c3e2df", "#979f72", "#446553", "#302f26", "#6e5d56", "#e7e9dd"], - 7: ["#c3e2df", "#a5ac7d", "#5d7a65", "#2f412c", "#3f3633", "#7b695a", "#e7e9dd"], - 8: ["#c3e2df", "#b0b788", "#768562", "#3c5a46", "#2d3123", "#4f4342", "#84715c", "#e7e9dd"], - 9: ["#c3e2df", "#b8c091", "#868f65", "#4b6e5f", "#2f412c", "#322d28", "#5c4e4b", "#8c775d", "#e7e9dd"], - 10: ["#c3e2df", "#bfc697", "#8f986c", "#5d7a65", "#37553e", "#2b3221", "#3f3633", "#665651", "#917c5e", "#e7e9dd"], - 11: ["#c3e2df", "#c4cc9d", "#979f72", "#6f8263", "#446553", "#2f412c", "#302f26", "#4a3f3d", "#6e5d56", "#96805f", "#e7e9dd"], - 12: ["#c3e2df", "#c8d0a1", "#9ea576", "#7d8861", "#4e7265", "#35513a", "#2a3320", "#352e2a", "#534745", "#756359", "#9d896a", "#e7e9dd"] - }, - Water: { - 3: ["#1f373d", "#4cc1b2", "#dee2b6"], - 4: ["#1f373d", "#309590", "#85dfce", "#dee2b6"], - 5: ["#1f373d", "#2a8180", "#4cc1b2", "#a1f3dc", "#dee2b6"], - 6: ["#1f373d", "#2f6f79", "#30a8a2", "#76d1c6", "#c1fdf6", "#dee2b6"], - 7: ["#1f373d", "#306573", "#309590", "#4cc1b2", "#85dfce", "#c8f3dc", "#dee2b6"], - 8: ["#1f373d", "#305f6b", "#2a8b86", "#2fb2aa", "#6eccbd", "#8deccd", "#c8e6bb", "#dee2b6"], - 9: ["#1f373d", "#2f5b66", "#2a8180", "#32a09a", "#4cc1b2", "#7dd5ce", "#a1f3dc", "#c8dda3", "#dee2b6"], - 10: ["#1f373d", "#2f5862", "#2d777c", "#309590", "#2eb8af", "#69cab8", "#85dfce", "#b3f8eb", "#c8d690", "#dee2b6"], - 11: ["#1f373d", "#2f555f", "#2f6f79", "#2c8e89", "#30a8a2", "#4cc1b2", "#76d1c6", "#8ae8cd", "#c1fdf6", "#c8d181", "#dee2b6"], - 12: ["#1f373d", "#2f535c", "#306977", "#298883", "#329c97", "#30bab1", "#66c8b4", "#80d7cf", "#92efd0", "#c8faf0", "#cad285", "#dee2b6"] - }, - CDA: { - 3: ["#18c6ca", "#fed873", "#ffffff"], - 4: ["#18c6ca", "#fffbc3", "#e3ce9b", "#ffffff"], - 5: ["#18c6ca", "#e9feb4", "#fed873", "#d0c6b0", "#ffffff"], - 6: ["#18c6ca", "#cffea9", "#fef5af", "#efd28b", "#c8c2b6", "#ffffff"], - 7: ["#18c6ca", "#bafea1", "#fffbc3", "#fed873", "#e3ce9b", "#ccc8c1", "#ffffff"], - 8: ["#18c6ca", "#affe9d", "#f0feb8", "#fef3a8", "#f3d486", "#d8c9a8", "#d3d0ca", "#ffffff"], - 9: ["#18c6ca", "#affe9d", "#e9feb4", "#fef7b5", "#fed873", "#e7cf96", "#d0c6b0", "#dad8d2", "#ffffff"], - 10: ["#18c6ca", "#a3fe9a", "#d8feac", "#fffbc3", "#feee9b", "#f7d580", "#e3ce9b", "#ccc4b3", "#dad8d2", "#ffffff"], - 11: ["#18c6ca", "#97fe96", "#cffea9", "#f7febb", "#fef5af", "#fed873", "#efd28b", "#dccaa4", "#c8c2b6", "#e1dfdb", "#ffffff"], - 12: ["#18c6ca", "#97fe96", "#c5fea5", "#f0feb8", "#fef9bc", "#feee9b", "#f7d580", "#e7cf96", "#d8c9a8", "#c4c1b9", "#e1dfdb", "#ffffff"] - }, - Simple: { - 3: ["#000000", "#7fff00", "#bf7f3f"], - 4: ["#000000", "#38ff38", "#ffd400", "#bf7f3f"], - 5: ["#000000", "#7fff7f", "#7fff00", "#ff9f00", "#bf7f3f"], - 6: ["#000000", "#aaffaa", "#00ff00", "#ffff00", "#ff7f00", "#bf7f3f"], - 7: ["#000000", "#8dd48d", "#38ff38", "#7fff00", "#ffd400", "#f47f0a", "#bf7f3f"] - } -}; - -import assign from 'object-assign'; - -export default assign({}, require("colorbrewer"), extendColorBrewer); diff --git a/web/client/components/style/EqualIntervalComponents/__tests__/ColorRampItem-test.jsx b/web/client/components/style/EqualIntervalComponents/__tests__/ColorRampItem-test.jsx deleted file mode 100644 index 2c503c8b91..0000000000 --- a/web/client/components/style/EqualIntervalComponents/__tests__/ColorRampItem-test.jsx +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright 2019, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -import expect from 'expect'; -import React from 'react'; -import ReactDOM from 'react-dom'; - -import ColorRampItem from '../ColorRampItem'; - -describe("Test the ColorRampItem", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('creates colorRamp with defaults', () => { - ReactDOM.render(, document.getElementById("container")); - const container = document.getElementById('container'); - const colorRamp = container.querySelector('.color-ramp-item'); - expect(colorRamp).toExist(); - }); - it('ColorRampItem with string item equal to blue', () => { - ReactDOM.render(, document.getElementById("container")); - const container = document.getElementById('container'); - const colorRamp = container.querySelector('.colorname-cell'); - expect(colorRamp.innerHTML).toEqual('blue'); - }); - it('ColorRampItem with object item contain name', () => { - const color = 'global.colors.blue'; - ReactDOM.render(, document.getElementById("container")); - const container = document.getElementById('container'); - const colorRamp = container.querySelector('span'); - expect(colorRamp.innerHTML).toEqual(color); - }); - it('ColorRampItem with object item contain label', () => { - const name = 'blue'; - const label = 'global.colors.blue'; - ReactDOM.render(, document.getElementById("container")); - const container = document.getElementById('container'); - const colorRamp = container.querySelector('span'); - expect(colorRamp.innerHTML).toEqual(label); - }); -}); diff --git a/web/client/components/style/MarkerPropertyPicker.jsx b/web/client/components/style/MarkerPropertyPicker.jsx deleted file mode 100644 index 109862ab80..0000000000 --- a/web/client/components/style/MarkerPropertyPicker.jsx +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2020, GeoSolutions Sas. - * All rights reserved. - * - * 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 PropTypes from 'prop-types'; -import Popover from '../styleeditor/Popover'; -function MarkerPropertyPicker({ - disabled, - containerNode, - onOpen, - placement, - children, - triggerNode -}) { - - const disabledClassName = disabled ? ' ms-disabled' : ''; - - return ( - onOpen(isOpen)} - content={ -
- {children} -
- } - > -
-
- {triggerNode} -
-
-
- ); -} - -MarkerPropertyPicker.propTypes = { - value: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.shape({r: PropTypes.number, g: PropTypes.number, b: PropTypes.number, a: PropTypes.number}) - ]), - format: PropTypes.string, - onChangeColor: PropTypes.func, - text: PropTypes.string, - line: PropTypes.bool, - disabled: PropTypes.bool, - pickerProps: PropTypes.object, - containerNode: PropTypes.node, - onOpen: PropTypes.function, - placement: PropTypes.string -}; - -MarkerPropertyPicker.defaultProps = { - disabled: false, - line: false, - onChangeColor: () => {}, - pickerProps: {}, - onOpen: () => {} -}; - -export default MarkerPropertyPicker; diff --git a/web/client/components/style/OpacityPicker.jsx b/web/client/components/style/OpacityPicker.jsx deleted file mode 100644 index 3b2538a791..0000000000 --- a/web/client/components/style/OpacityPicker.jsx +++ /dev/null @@ -1,50 +0,0 @@ -import PropTypes from 'prop-types'; - -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * 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 Slider from 'react-nouislider'; -import 'react-nouislider/example/nouislider.css'; -import './opacitypicker.css'; - -class OpacityPicker extends React.Component { - static propTypes = { - opacity: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), - onChange: PropTypes.func, - disabled: PropTypes.bool - }; - - static defaultProps = { - opacity: "1", - onChange: () => {}, - disabled: false - }; - - render() { - return ( -
- this.props.onChange("opacity", (v / 100).toFixed(2))} - connect="lower" - tooltips={[ { - to: function( value ) { - return Math.round(value) + '%'; - } - } - ]} - /> -
); - } -} - -export default OpacityPicker; diff --git a/web/client/components/style/PolygonStyler.jsx b/web/client/components/style/PolygonStyler.jsx deleted file mode 100644 index d16aedaaa7..0000000000 --- a/web/client/components/style/PolygonStyler.jsx +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2018, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. -*/ - -import PropTypes from 'prop-types'; - -import React from 'react'; -import assign from 'object-assign'; -import { Grid, Row, Col } from 'react-bootstrap'; -import ColorSelector from './ColorSelector'; -import StyleCanvas from './StyleCanvas'; -import Slider from 'react-nouislider'; -import numberLocalizer from 'react-widgets/lib/localizers/simple-number'; -numberLocalizer(); -import Message from '../I18N/Message'; -import { isNil } from 'lodash'; -import tinycolor from 'tinycolor2'; - -class StylePolygon extends React.Component { - static propTypes = { - shapeStyle: PropTypes.object, - width: PropTypes.number, - setStyleParameter: PropTypes.func - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - shapeStyle: {}, - setStyleParameter: () => {} - }; - - render() { - const styleType = !!this.props.shapeStyle.MultiPolygon ? "MultiPolygon" : "Polygon"; - const otherStyleType = !this.props.shapeStyle.MultiPolygon ? "MultiPolygon" : "Polygon"; - const style = this.props.shapeStyle[styleType] || this.props.shapeStyle; // in case of old version of style. - return ( - - -
- -
- -
- - - - - - { - if (!isNil(c)) { - const fillColor = tinycolor(c).toHexString(); - const fillOpacity = c.a; - const newStyle = assign({}, this.props.shapeStyle, { - [styleType]: assign({}, style, {fillColor, fillOpacity}), - [otherStyleType]: assign({}, style, {fillColor, fillOpacity}) - }); - this.props.setStyleParameter(newStyle); - } - }}/> - - - - - - - - { - if (!isNil(c)) { - const color = tinycolor(c).toHexString(); - const opacity = c.a; - const newStyle = assign({}, this.props.shapeStyle, { - [styleType]: assign({}, style, {color, opacity}), - [otherStyleType]: assign({}, style, {color, opacity}) - }); - this.props.setStyleParameter(newStyle); - } - }}/> - - - - - - - -
- Math.round(value), - to: value => Math.round(value) + ' px' - }} - range={{min: 1, max: 15}} - onChange={(values) => { - const weight = parseInt(values[0].replace(' px', ''), 10); - const newStyle = assign({}, this.props.shapeStyle, { - [styleType]: assign({}, style, {weight}), - [otherStyleType]: assign({}, style, {weight}) - }); - this.props.setStyleParameter(newStyle); - }} - /> -
- -
-
); - } - addOpacityToColor = (color, opacity) => { - return assign({}, color, { - a: opacity - }); - } -} - -export default StylePolygon; diff --git a/web/client/components/style/PolylineStyler.jsx b/web/client/components/style/PolylineStyler.jsx deleted file mode 100644 index 50e3757ccd..0000000000 --- a/web/client/components/style/PolylineStyler.jsx +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2018, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. -*/ - -import PropTypes from 'prop-types'; - -import React from 'react'; -import { Grid, Row, Col } from 'react-bootstrap'; -import assign from 'object-assign'; -import ColorSelector from './ColorSelector'; -import StyleCanvas from './StyleCanvas'; -import Slider from 'react-nouislider'; -import numberLocalizer from 'react-widgets/lib/localizers/simple-number'; -numberLocalizer(); -import Message from '../I18N/Message'; -import { isNil } from 'lodash'; -import tinycolor from 'tinycolor2'; - -class StylePolyline extends React.Component { - static propTypes = { - width: PropTypes.number, - shapeStyle: PropTypes.object, - setStyleParameter: PropTypes.func - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - shapeStyle: {}, - setStyleParameter: () => {} - }; - - render() { - const styleType = !!this.props.shapeStyle.MultiLineString ? "MultiLineString" : "LineString"; - const otherStyleType = !this.props.shapeStyle.MultiLineString ? "MultiLineString" : "LineString"; - const style = this.props.shapeStyle[styleType]; - return ( - - -
- -
- -
- - - - - - { - if (!isNil(c)) { - const color = tinycolor(c).toHexString(); - const opacity = c.a; - const newStyle = assign({}, this.props.shapeStyle, { - [styleType]: assign({}, style, {color, opacity}), - [otherStyleType]: assign({}, style, {color, opacity}) - }); - this.props.setStyleParameter(newStyle); - } - }}/> - - - - - - - -
- Math.round(value), - to: value => Math.round(value) + ' px' - }} - range={{min: 1, max: 15}} - onChange={(values) => { - const weight = parseInt(values[0].replace(' px', ''), 10); - const newStyle = assign({}, this.props.shapeStyle, { - [styleType]: assign({}, style, {weight}), - [otherStyleType]: assign({}, style, {weight}) - }); - this.props.setStyleParameter(newStyle); - }} - /> -
- -
-
); - } - addOpacityToColor = (color, opacity) => { - return assign({}, color, { - a: opacity - }); - } -} - -export default StylePolyline; diff --git a/web/client/components/style/PseudoColorSettings.jsx b/web/client/components/style/PseudoColorSettings.jsx deleted file mode 100644 index 191b79ef70..0000000000 --- a/web/client/components/style/PseudoColorSettings.jsx +++ /dev/null @@ -1,108 +0,0 @@ - -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -import PropTypes from 'prop-types'; -import React from 'react'; -import { Grid, Row, Col} from 'react-bootstrap'; -import { Combobox } from 'react-widgets'; - -import Button from '../misc/Button'; -import ColorMapGrid from './ColorMapGrid'; -import Message from '../I18N/Message'; - -class PseudoColorSettings extends React.Component { - static propTypes = { - type: PropTypes.oneOf(['ramp', 'intervals', 'values']), - opacity: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), - selected: PropTypes.number, - colorMapEntry: PropTypes.array, - onChange: PropTypes.func, - extended: PropTypes.bool - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - type: 'ramp', - opacity: "1", - selected: null, - colorMapEntry: [], - onChange: () => {}, - extended: false - }; - - render() { - return ( - - - - - - - - this.props.onChange("type", v)} /> - - -    this.props.onChange("extended", e.target.checked)} checked={this.props.extended} /> - - - - - - this.props.onChange("colorMapEntry", colorMap)} - entries={this.props.colorMapEntry}/> - - - - - - - - - - - - - ); - } - - addEntry = () => { - let colorMapEntry = this.props.colorMapEntry ? this.props.colorMapEntry.slice() : []; - let quantity = colorMapEntry.length > 0 ? colorMapEntry[colorMapEntry.length - 1].quantity + 0.01 : 0; - let label = quantity.toFixed ? quantity.toFixed(2) : quantity; - colorMapEntry.push({color: '#AA34FF', quantity: quantity, label: label }); - this.props.onChange("colorMapEntry", colorMapEntry); - }; - - removeEntry = () => { - let colorMapEntry = this.props.colorMapEntry.filter((e, idx) => { - return idx !== this.props.selected; - }); - this.props.onChange("selected", null); - this.props.onChange("colorMapEntry", colorMapEntry); - }; - - selectEntry = (id) => { - if ( id !== this.props.selected) { - this.props.onChange("selected", id); - } - }; -} - -export default PseudoColorSettings; diff --git a/web/client/components/style/RasterStyleTypePicker.jsx b/web/client/components/style/RasterStyleTypePicker.jsx deleted file mode 100644 index 2ab2610588..0000000000 --- a/web/client/components/style/RasterStyleTypePicker.jsx +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * 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 { Combobox } from 'react-widgets'; -import PropTypes from 'prop-types'; -import { getMessageById } from '../../utils/LocaleUtils'; - -class RasterStyleTypePicker extends React.Component { - static propTypes = { - styletype: PropTypes.oneOf(['rgb', 'gray', 'pseudo']), - onChange: PropTypes.func - }; - - static contextTypes = { - messages: PropTypes.object - }; - - render() { - return ( - this.props.onChange("styletype", v.value)} - value={this.props.styletype} /> - ); - } -} - -export default RasterStyleTypePicker; diff --git a/web/client/components/style/ScaleDenominator.jsx b/web/client/components/style/ScaleDenominator.jsx deleted file mode 100644 index 3f59de5317..0000000000 --- a/web/client/components/style/ScaleDenominator.jsx +++ /dev/null @@ -1,98 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * 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 PropTypes from 'prop-types'; -import { getGoogleMercatorScales } from '../../utils/MapUtils'; -import { findDOMNode } from 'react-dom'; -import { DropdownList } from 'react-widgets'; -import { Row, Col, Overlay, Popover, Label } from 'react-bootstrap'; -import { getMessageById } from '../../utils/LocaleUtils'; -import Message from '../I18N/Message'; - -class ScaleDenominator extends React.Component { - static propTypes = { - minValue: PropTypes.number, - maxValue: PropTypes.number, - onChange: PropTypes.func.isRequired - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - minValue: null, - maxValue: null, - onChange: () => null - }; - - state = {error: false}; - - UNSAFE_componentWillMount() { - let scales = getGoogleMercatorScales(0, 21); - this.scales = [{value: null, text: getMessageById(this.context.messages, "scaledenominator.none") || 'None'}, ...scales.map((v) => ({value: v, text: `${v.toFixed(0)}`}))]; - } - - onChange = (t, {value: v}) => { - if (t === 'minDenominator' && this.props.maxValue && v >= this.props.maxValue) { - this.setState({error: {type: t, msg: "scaledenominator.minerror"}}); - } else if (t === 'maxDenominator' && this.props.minValue && v <= this.props.minValue) { - this.setState({error: {type: t, msg: "scaledenominator.maxerror"}}); - } else { - if (this.state.error) { - this.setState({error: false}); - } - this.props.onChange(t, v); - } - }; - - renderErrorPopOver = () => { - return ( - findDOMNode(this.refs[this.state.error.type])} - show placement="top" > - - - - - ); - }; - - render() { - return ( - - - this.onChange("minDenominator", v)} - /> - - - - this.onChange("maxDenominator", v)} - /> - - {(this.state.error) ? this.renderErrorPopOver() : null} - ) - ; - } -} - -export default ScaleDenominator; diff --git a/web/client/components/style/TextStyler.jsx b/web/client/components/style/TextStyler.jsx deleted file mode 100644 index 67bc560ec6..0000000000 --- a/web/client/components/style/TextStyler.jsx +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright 2018, GeoSolutions Sas. - * All rights reserved. - * - * 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 PropTypes from 'prop-types'; -import { Grid, Row, Col } from 'react-bootstrap'; -import { Combobox } from 'react-widgets'; -import assign from 'object-assign'; -import ColorSelector from './ColorSelector'; -import StyleCanvas from './StyleCanvas'; -import numberLocalizer from 'react-widgets/lib/localizers/simple-number'; -numberLocalizer(); -import { getMessageById } from '../../utils/LocaleUtils'; -import { createFont } from '../../utils/LegacyAnnotationsUtils'; -import Message from '../I18N/Message'; -import tinycolor from 'tinycolor2'; -import IntlNumberFormControl from '../I18N/IntlNumberFormControl'; - -class TextStyler extends React.Component { - static propTypes = { - width: PropTypes.number, - uomValues: PropTypes.array, - alignValues: PropTypes.array, - fontStyleValues: PropTypes.array, - fontWeightValues: PropTypes.array, - fontFamilyValues: PropTypes.array, - shapeStyle: PropTypes.object, - setStyleParameter: PropTypes.func, - styleType: PropTypes.String - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - styleType: "Text", - uomValues: [{value: "px"}, {value: "em"}], - fontWeightValues: [{value: "normal"}, {value: "bold"}], - alignValues: [{value: "start", label: "left"}, {value: "center", label: "center"}, {value: "end", label: "right"}], - fontStyleValues: [{value: "normal"}, {value: "italic"}], - fontFamilyValues: [{value: "Arial"}, {value: "Helvetica"}, {value: "sans-serif"}, {value: "Courier"}], - shapeStyle: {}, - setStyleParameter: () => {} - }; - - state = { - fontFamily: "Arial" - }; - - render() { - const messages = { - emptyList: getMessageById(this.context.messages, "queryform.attributefilter.autocomplete.emptyList"), - open: getMessageById(this.context.messages, "queryform.attributefilter.autocomplete.open"), - emptyFilter: getMessageById(this.context.messages, "queryform.attributefilter.autocomplete.emptyFilter") - }; - const {styleType, shapeStyle} = this.props; - const style = shapeStyle[styleType]; - return ( - - -
- {} -
- -
- - - - - - { - const color = tinycolor(c).toHexString(); - const opacity = c.a; - const newStyle = assign({}, shapeStyle, { - [styleType]: assign({}, style, {color, opacity}) - }); - this.props.setStyleParameter(newStyle); - }}/> - - - - - - - - { - let fontFamily = e.value ? e.value : e; - if (fontFamily === "") { - fontFamily = "Arial"; - } - this.setState({fontFamily}); - const font = createFont({...style, fontFamily}); - const newStyle = assign({}, shapeStyle, { - [styleType]: assign({}, style, {fontFamily, font}) - }); - this.props.setStyleParameter(newStyle); - }} - /> - - - - - - - - { - const fontSize = val; - const font = createFont({...style, fontSize}); - const newStyle = assign({}, shapeStyle, { - [styleType]: assign({}, style, {fontSize, font}) - }); - this.props.setStyleParameter(newStyle); - }} - type="number"/> - - - { - let fontSizeUom = e.value ? e.value : e; - if (this.props.uomValues.map(f => f.value).indexOf(fontSizeUom) === -1) { - fontSizeUom = "px"; - } - const font = createFont({...style, fontSizeUom}); - const newStyle = assign({}, shapeStyle, { - [styleType]: assign({}, style, {fontSizeUom, font}) - }); - this.props.setStyleParameter(newStyle); - }} - /> - - - - - - - - { - let textAlign = e.value ? e.value : e; - if (this.props.alignValues.map(f => f.value).indexOf(textAlign) === -1) { - textAlign = "center"; - } - const newStyle = assign({}, shapeStyle, { - [styleType]: assign({}, style, {textAlign}) - }); - this.props.setStyleParameter(newStyle); - }} - /> - - - - - - - - { - let fontStyle = e.value ? e.value : e; - if (this.props.fontStyleValues.map(f => f.value).indexOf(fontStyle) === -1) { - fontStyle = style.fontStyle; - } - const font = createFont({...style, fontStyle}); - const newStyle = assign({}, shapeStyle, { - [styleType]: assign({}, style, {fontStyle, font}) - }); - this.props.setStyleParameter(newStyle); - }} - /> - - - - - - - - { - let fontWeight = e.value ? e.value : e; - if (this.props.fontWeightValues.map(f => f.value).indexOf(fontWeight) === -1) { - fontWeight = style.fontWeight; - } - const font = createFont({...style, fontWeight}); - const newStyle = assign({}, shapeStyle, { - [styleType]: assign({}, style, {fontWeight, font}) - }); - this.props.setStyleParameter(newStyle); - }} - /> - - -
); - } - addOpacityToColor = (color, opacity) => { - return assign({}, color, { - a: opacity - }); - } -} - -export default TextStyler; diff --git a/web/client/components/style/__tests__/BandSelector-test.jsx b/web/client/components/style/__tests__/BandSelector-test.jsx deleted file mode 100644 index f582a69472..0000000000 --- a/web/client/components/style/__tests__/BandSelector-test.jsx +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ -import expect from 'expect'; - -import React from 'react'; -import ReactDOM from 'react-dom'; -import BandSelector from '../BandSelector'; - -describe("Test the BandSelector component", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('creates component with defaults', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - cmp.props.onChange(); - }); - - it('creates component contrast', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - }); - it('creates component algorithm', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - }); - -}); diff --git a/web/client/components/style/__tests__/ColorMapGrid-test.jsx b/web/client/components/style/__tests__/ColorMapGrid-test.jsx deleted file mode 100644 index b7c0adb0a2..0000000000 --- a/web/client/components/style/__tests__/ColorMapGrid-test.jsx +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ -import expect from 'expect'; - -import React from 'react'; -import ReactDOM from 'react-dom'; -import ColorMap from '../ColorMapGrid'; - -describe("Test the ColorMap component", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('creates component with defaults', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - }); - - it('creates component with element', (done) => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - cmp.selectEntry({node: {childIndex: 0}}); - setTimeout(() => { - cmp.valueChanged(); - done(); - }, 0); - }); - -}); diff --git a/web/client/components/style/__tests__/EqualInterval-test.jsx b/web/client/components/style/__tests__/EqualInterval-test.jsx deleted file mode 100644 index 3f92bb353e..0000000000 --- a/web/client/components/style/__tests__/EqualInterval-test.jsx +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ -import expect from 'expect'; - -import React from 'react'; -import ReactDOM from 'react-dom'; -import EqualInterval from '../EqualInterval'; - -describe("Test the EqualInterval component", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('creates component with defaults', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - cmp.generateEqualIntervalRamp(); - cmp.props.onChange(); - }); - -}); diff --git a/web/client/components/style/__tests__/OpacityPicker-test.jsx b/web/client/components/style/__tests__/OpacityPicker-test.jsx deleted file mode 100644 index 293865afb3..0000000000 --- a/web/client/components/style/__tests__/OpacityPicker-test.jsx +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ -import expect from 'expect'; - -import React from 'react'; -import ReactDOM from 'react-dom'; -import OpacityPicker from '../OpacityPicker'; - -describe("Test the OpacityPicker component", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('creates component with defaults', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - }); - -}); diff --git a/web/client/components/style/__tests__/PseudoColorSettings-test.jsx b/web/client/components/style/__tests__/PseudoColorSettings-test.jsx deleted file mode 100644 index 43a7d60bb6..0000000000 --- a/web/client/components/style/__tests__/PseudoColorSettings-test.jsx +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ -import expect from 'expect'; - -import React from 'react'; -import ReactDOM from 'react-dom'; -import PseudoColorSettings from '../PseudoColorSettings'; - -describe("Test the PseudoColorSettings component", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('creates component with defaults', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - }); - - it('creates component add entry', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - cmp.addEntry(); - }); - it('creates component remove entry', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - cmp.removeEntry(); - cmp.selectEntry(2); - }); - -}); diff --git a/web/client/components/style/__tests__/RasterStyleTypePicker-test.jsx b/web/client/components/style/__tests__/RasterStyleTypePicker-test.jsx deleted file mode 100644 index dfaa5f2692..0000000000 --- a/web/client/components/style/__tests__/RasterStyleTypePicker-test.jsx +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ -import expect from 'expect'; - -import React from 'react'; -import ReactDOM from 'react-dom'; -import RasterStyleTypePicker from '../RasterStyleTypePicker'; - -describe("Test the RasterStyleTypePicker component", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('creates component with defaults', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - }); - -}); diff --git a/web/client/components/style/__tests__/ScaleDenominator-test.jsx b/web/client/components/style/__tests__/ScaleDenominator-test.jsx deleted file mode 100644 index 3bcc501149..0000000000 --- a/web/client/components/style/__tests__/ScaleDenominator-test.jsx +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ -import expect from 'expect'; - -import React from 'react'; -import ReactDOM from 'react-dom'; -import ScaleDenominator from '../ScaleDenominator'; - -describe('ScaleDenominator', () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - it('create component with defaults', () => { - const sb = ReactDOM.render(, document.getElementById("container")); - expect(sb).toExist(); - const domNode = ReactDOM.findDOMNode(sb); - expect(domNode).toExist(); - - const comboItems = sb.scales; - expect(comboItems.length).toBe(23); - sb.onChange("minDenominator", {value: 1000}); - sb.onChange("minDenominator", {value: 100000}); - sb.onChange("maxDenominator", {value: 100}); - }); -}); diff --git a/web/client/components/style/opacitypicker.css b/web/client/components/style/opacitypicker.css deleted file mode 100644 index eeda0d82a0..0000000000 --- a/web/client/components/style/opacitypicker.css +++ /dev/null @@ -1,22 +0,0 @@ -.opacity-picker .noUi-tooltip { - display: block; - position: absolute; - border: 1px solid #D9D9D9; - border-radius: 3px; - background: #fff; - padding: 5px; - left: -1px; - text-align: center; - width: 34px; - font-style: normal; - font-variant: normal; - font-weight: 700; - font-stretch: normal; - font-size: 10px; - line-height: 12px; - font-family: Arial; - } - -.opacity-picker .noUi-handle-lower .noUi-tooltip { - top: 28px; -} diff --git a/web/client/components/style/thumbGeoms/CircleThumb.jsx b/web/client/components/style/thumbGeoms/CircleThumb.jsx deleted file mode 100644 index 43f3e55c85..0000000000 --- a/web/client/components/style/thumbGeoms/CircleThumb.jsx +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2018, GeoSolutions Sas. - * All rights reserved. - * - * 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 PropTypes from 'prop-types'; - -class CircleThumb extends React.Component { - - static propTypes = { - linecap: PropTypes.string, - linejoin: PropTypes.string, - stroke: PropTypes.string, - fillColor: PropTypes.string, - strokeWidth: PropTypes.number, - styleRect: PropTypes.object - }; - - static defaultProps = { - styleRect: {}, - linecap: 'round', // butt round square - linejoin: 'round', // miter round bevel - strokeWidth: 3, - stroke: '#ffcc33', - fillColor: '#FFFFFF' - }; - - render() { - const {color, weight, fillColor} = this.props.styleRect; - return ( -
- - - - - /* - */ -
- ); - } -} - -export default CircleThumb; diff --git a/web/client/components/style/thumbGeoms/LineThumb.jsx b/web/client/components/style/thumbGeoms/LineThumb.jsx deleted file mode 100644 index 57a004c907..0000000000 --- a/web/client/components/style/thumbGeoms/LineThumb.jsx +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2018, GeoSolutions Sas. - * All rights reserved. - * - * 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 PropTypes from 'prop-types'; - -class LineThumb extends React.Component { - - static propTypes = { - linecap: PropTypes.string, - linejoin: PropTypes.string, - stroke: PropTypes.string, - fillColor: PropTypes.string, - strokeWidth: PropTypes.number, - style: PropTypes.object - }; - - static defaultProps = { - style: {}, - linecap: 'round', // butt round square - linejoin: 'round', // miter round bevel - strokeWidth: 3, - stroke: '#ffcc33', - fillColor: '#FFFFFF' - }; - - render() { - const {color, weight, fillColor} = this.props.style; - return ( -
- - - -
- ); - } -} - -export default LineThumb; diff --git a/web/client/components/style/thumbGeoms/MultiGeomThumb.jsx b/web/client/components/style/thumbGeoms/MultiGeomThumb.jsx deleted file mode 100644 index 08ca532679..0000000000 --- a/web/client/components/style/thumbGeoms/MultiGeomThumb.jsx +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2018, GeoSolutions Sas. - * All rights reserved. - * - * 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 PropTypes from 'prop-types'; -import markerIcon from '../../map/openlayers/img/marker-icon.png'; - -class MultiGeomThumb extends React.Component { - - static propTypes = { - linecap: PropTypes.string, - linejoin: PropTypes.string, - stroke: PropTypes.string, - strokeWidth: PropTypes.number, - styleMultiGeom: PropTypes.object, - geometry: PropTypes.object, - properties: PropTypes.object - }; - - static defaultProps = { - linecap: 'round', // butt round square - linejoin: 'round', // miter round bevel - stroke: '#ffcc33', - strokeWidth: 3, - styleMultiGeom: {}, - geometry: { - features: [] - }, - properties: {} - }; - - getGeoms() { - return this.props.geometry && this.props.geometry.features.reduce((p, c) => { - if (c.properties && c.properties.isCircle) { - return {...p, "Circle": true}; - } - if (c.properties && c.properties.isText) { - return {...p, "Text": true}; - } - return {...p, [c.geometry.type]: true}; - }, {"Circle": false, "Text": false}); - } - render() { - let geoms = this.getGeoms(); - const stroke = {color: "#ffcc33", opacity: 1, weight: 2 }; - const fill = {fillColor: "#FFFFFF", fillOpacity: 0 }; - let textPresent = geoms.Text; - let circlePresent = geoms.Circle; - let polygonPresent = geoms.Polygon || geoms.MultiPolygon; - let lineStringPresent = geoms.LineString || geoms.MultiLineString; - let pointPresent = geoms.Point || geoms.MultiPoint; // this can be a symbol tho.. - - let styleLine = {...stroke}; - let stylePolygon = {...stroke, ...fill}; - let styleCircle = {...stroke, ...fill}; - let styleText = textPresent ? { - fontStyle: 'normal', - fontSize: '14', - fontSizeUom: 'px', - fontFamily: 'Arial', - fontWeight: 'normal', - font: "14px Arial", - textAlign: 'center', - ...stroke, ...fill} : {}; - return ( -
- - {styleLine && lineStringPresent && () - } - {stylePolygon && polygonPresent && () } - {textPresent && T} - {circlePresent && } - - {pointPresent && } -
- ); - } -} - -export default MultiGeomThumb; diff --git a/web/client/components/style/thumbGeoms/PolygonThumb.jsx b/web/client/components/style/thumbGeoms/PolygonThumb.jsx deleted file mode 100644 index 085d10df15..0000000000 --- a/web/client/components/style/thumbGeoms/PolygonThumb.jsx +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2018, GeoSolutions Sas. - * All rights reserved. - * - * 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 PropTypes from 'prop-types'; - -class PolygonThumb extends React.Component { - - static propTypes = { - stroke: PropTypes.string, - fill: PropTypes.string, - fillOpacity: PropTypes.number, - strokeWidth: PropTypes.number, - opacity: PropTypes.number, - styleRect: PropTypes.object, - viewBox: PropTypes.string, - rectParams: PropTypes.object - }; - - static defaultProps = { - stroke: '#ffcc33', - fill: '#FFFFFF', - fillOpacity: 0.2, - strokeWidth: 3, - opacity: 1, - styleRect: {}, - viewBox: "0 0 100 100", - rectParams: { - height: "50", - width: "50", - x: "25", - y: "25" - } - }; - - render() { - const {color, weight, fillColor, fillOpacity, opacity} = this.props.styleRect; - const {height, width, x, y} = this.props.rectParams; - return ( -
- - - -
- ); - } -} - -export default PolygonThumb; diff --git a/web/client/components/style/thumbGeoms/__tests__/LineThumb-test.js b/web/client/components/style/thumbGeoms/__tests__/LineThumb-test.js deleted file mode 100644 index 77011584ee..0000000000 --- a/web/client/components/style/thumbGeoms/__tests__/LineThumb-test.js +++ /dev/null @@ -1,40 +0,0 @@ -import expect from 'expect'; -import React from 'react'; -import ReactDOM from 'react-dom'; -import TestUtils from 'react-dom/test-utils'; - -import {DEFAULT_ANNOTATIONS_STYLES} from '../../../../plugins/Annotations/utils/AnnotationsUtils'; -import LineThumb from '../LineThumb'; - -describe("Test the LineThumb component", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('create component with default', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - }); - it('create component with default style from annotation utils', () => { - const style = DEFAULT_ANNOTATIONS_STYLES.LineString; - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - const path = TestUtils.findRenderedDOMComponentWithTag(cmp, 'path'); - expect(path).toExist(); - expect(path.attributes.d.value).toBe("M25 75 L50 50 L75 75 L100 75"); - expect(path.attributes["stroke-linecap"].value).toBe("round"); - expect(path.attributes["stroke-linejoin"].value).toBe("round"); - expect(path.attributes["stroke-width"].value).toBe(style.weight.toString()); - expect(path.attributes.stroke.value).toBe(style.color.toString()); - - }); - - -}); diff --git a/web/client/components/style/thumbGeoms/__tests__/MultiGeomThumb-test.js b/web/client/components/style/thumbGeoms/__tests__/MultiGeomThumb-test.js deleted file mode 100644 index 15dfba7b1a..0000000000 --- a/web/client/components/style/thumbGeoms/__tests__/MultiGeomThumb-test.js +++ /dev/null @@ -1,81 +0,0 @@ -import expect from 'expect'; -import React from 'react'; -import ReactDOM from 'react-dom'; -import TestUtils from 'react-dom/test-utils'; - -import {DEFAULT_ANNOTATIONS_STYLES} from '../../../../utils/LegacyAnnotationsUtils'; -import MultiGeomThumb from '../MultiGeomThumb'; - -describe("Test the MultiGeomThumb component", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('create component with default', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - }); - it('create component with only Polygon', () => { - const style = DEFAULT_ANNOTATIONS_STYLES; - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - const rect = TestUtils.findRenderedDOMComponentWithTag(cmp, 'rect'); - const svg = TestUtils.findRenderedDOMComponentWithTag(cmp, 'svg'); - expect(rect).toExist(); - const path = TestUtils.scryRenderedDOMComponentsWithTag(cmp, 'path'); - expect(path.length).toBe(0); - expect(rect.attributes.width.value).toBe("50"); - expect(rect.attributes.height.value).toBe("50"); - expect(rect.attributes.x.value).toBe("20"); - expect(rect.attributes.y.value).toBe("15"); - expect(svg.attributes.xmlns.value).toBe("http://www.w3.org/2000/svg"); - expect(svg.attributes.viewBox.value).toBe("0 0 100 100"); - - }); - it('create component with only MultiPolygon LineString', () => { - - const stroke = {color: "#ffcc33", opacity: 1, weight: 2 }; - const fill = {fillColor: "#FFFFFF", fillOpacity: 0 }; - const style = {...stroke, ...fill}; - - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - const rect = TestUtils.findRenderedDOMComponentWithTag(cmp, 'rect'); - - const svg = TestUtils.findRenderedDOMComponentWithTag(cmp, 'svg'); - expect(rect).toExist(); - expect(rect.attributes.width.value).toBe("50"); - expect(rect.attributes.height.value).toBe("50"); - expect(rect.attributes.x.value).toBe("40"); - expect(rect.attributes.y.value).toBe("15"); - expect(svg.attributes.xmlns.value).toBe("http://www.w3.org/2000/svg"); - expect(svg.attributes.viewBox.value).toBe("0 0 100 100"); - - }); - it('create component with only Circle', () => { - const style = DEFAULT_ANNOTATIONS_STYLES; - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - const circle = TestUtils.findRenderedDOMComponentWithTag(cmp, 'circle'); - - expect(circle).toExist(); - expect(circle.attributes.cx.value).toBe("50"); - expect(circle.attributes.cy.value).toBe("50"); - expect(circle.attributes.r.value).toBe("25"); - expect(circle.attributes.stroke.value).toBe("#ffcc33"); - expect(circle.attributes.fill.value).toBe("#FFFFFF"); - expect(circle.attributes.opacity.value).toBe("1"); - expect(circle.attributes["stroke-width"].value).toBe("2"); - expect(circle.attributes["fill-opacity"].value).toBe("0"); - - }); - - -}); diff --git a/web/client/components/style/thumbGeoms/__tests__/PolygonThumb-test.js b/web/client/components/style/thumbGeoms/__tests__/PolygonThumb-test.js deleted file mode 100644 index 93691d931f..0000000000 --- a/web/client/components/style/thumbGeoms/__tests__/PolygonThumb-test.js +++ /dev/null @@ -1,43 +0,0 @@ -import expect from 'expect'; -import React from 'react'; -import ReactDOM from 'react-dom'; -import TestUtils from 'react-dom/test-utils'; - -import {DEFAULT_ANNOTATIONS_STYLES} from '../../../../plugins/Annotations/utils/AnnotationsUtils'; -import PolygonThumb from '../PolygonThumb'; - -describe("Test the PolygonThumb component", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('create component with default', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - }); - it('create component with default style from annotation utils', () => { - const style = DEFAULT_ANNOTATIONS_STYLES; - const featureType = "MultiPolygon"; - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - const rect = TestUtils.findRenderedDOMComponentWithTag(cmp, 'rect'); - const svg = TestUtils.findRenderedDOMComponentWithTag(cmp, 'svg'); - expect(rect).toExist(); - expect(rect.attributes.width.value).toBe("50"); - expect(rect.attributes.height.value).toBe("50"); - expect(rect.attributes.x.value).toBe("25"); - expect(rect.attributes.y.value).toBe("25"); - expect(svg.attributes.xmlns.value).toBe("http://www.w3.org/2000/svg"); - expect(svg.attributes.viewBox.value).toBe("0 0 100 100"); - - }); - - -}); diff --git a/web/client/components/style/vector/Fill.jsx b/web/client/components/style/vector/Fill.jsx deleted file mode 100644 index 917114d6d4..0000000000 --- a/web/client/components/style/vector/Fill.jsx +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2018, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. -*/ - -import PropTypes from 'prop-types'; - -import React from 'react'; -import { Row, Col } from 'react-bootstrap'; -import { isNil } from 'lodash'; -import tinycolor from 'tinycolor2'; - -// number localizer? -import numberLocalizer from 'react-widgets/lib/localizers/simple-number'; - -// not sure this is needed, TODO check! -numberLocalizer(); - -import Message from '../../I18N/Message'; -import OpacitySlider from '../../../plugins/TOC/components/OpacitySlider'; -import ColorSelector from '../ColorSelector'; -import { addOpacityToColor } from '../../../utils/VectorStyleUtils'; - -/** - * Styler for the stroke properties of a vector style -*/ -class Fill extends React.Component { - static propTypes = { - style: PropTypes.object, - defaultColor: PropTypes.string, - onChange: PropTypes.func, - width: PropTypes.number - }; - - static defaultProps = { - style: {}, - onChange: () => {} - }; - - render() { - const {style} = this.props; - return (
- - - - - - - - - - - { - if (!isNil(c)) { - const fillColor = tinycolor(c).toHexString(); - const fillOpacity = c.a; - this.props.onChange(style.id, {fillColor, fillOpacity}); - } - }}/> - - - - - - - - { - this.props.onChange(style.id, {fillOpacity}); - }}/> - - -
); - } -} - -export default Fill; diff --git a/web/client/components/style/vector/Manager.jsx b/web/client/components/style/vector/Manager.jsx deleted file mode 100644 index 1e072d1224..0000000000 --- a/web/client/components/style/vector/Manager.jsx +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright 2018, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. -*/ - -import axios from 'axios'; -import { castArray, filter, find, findIndex, isNil } from 'lodash'; -import assign from 'object-assign'; -import PropTypes from 'prop-types'; -import React from 'react'; -import { Grid } from 'react-bootstrap'; -import tinycolor from 'tinycolor2'; -import uuidv1 from 'uuid/v1'; - -import { DEFAULT_PATH, DEFAULT_SHAPE, checkSymbolsError } from '../../../utils/LegacyAnnotationsUtils'; -import { arrayUpdate } from '../../../utils/ImmutableUtils'; -import { - addOpacityToColor, - createSvgUrl, - fetchStyle, - getStylerTitle, - hashAndStringify, - isFillStyle, - isMarkerStyle, - isStrokeStyle, - isSymbolStyle, - isTextStyle, - registerStyle -} from '../../../utils/VectorStyleUtils'; -import SwitchPanel from '../../misc/switch/SwitchPanel'; -import StyleCanvas from '../StyleCanvas'; -import Fill from './Fill'; -import MarkerGlyph from './marker/MarkerGlyph'; -import MarkerType from './marker/MarkerType'; -import SymbolLayout from './marker/SymbolLayout'; -import Stroke from './Stroke'; -import Text from './Text'; - -class Manager extends React.Component { - static propTypes = { - style: PropTypes.object, - switchPanelOptions: PropTypes.array, - lineDashOptions: PropTypes.array, - onChangeStyle: PropTypes.func, - pointType: PropTypes.string, - onUpdateSymbols: PropTypes.func, - onSetErrorSymbol: PropTypes.func, - width: PropTypes.number, - symbolsPath: PropTypes.string, - defaultShape: PropTypes.string, - defaultShapeSize: PropTypes.number, - defaultShapeFillColor: PropTypes.string, - defaultShapeStrokeColor: PropTypes.string, - defaultStyles: PropTypes.object, - symbolList: PropTypes.array, - symbolErrors: PropTypes.array, - defaultSymbol: PropTypes.object, - defaultMarker: PropTypes.object, - markersOptions: PropTypes.object, - textRotationStep: PropTypes.number - }; - - static defaultProps = { - style: {}, - defaultShape: DEFAULT_SHAPE, - symbolsPath: DEFAULT_PATH, - defaultShapeSize: 64, - defaultShapeFillColor: '#000000', - defaultShapeStrokeColor: '#000000', - symbolErrors: [], - onChangeStyle: () => {}, - onUpdateSymbols: () => {}, - defaultStyles: {}, - switchPanelOptions: [] - }; - - state = {} - - - UNSAFE_componentWillMount() { - // we assume that the default symbols shape is correctly configured - - const styles = castArray(this.props.style); - const expanded = styles.map((s, i) => i === 0 || s.filtering ); - const locked = styles.map((s, i) => i === 0 ); - this.setState({expanded, locked}); - styles.filter(({type}) => type === 'Point').forEach(style => { - this.checkSymbolUrl({...this.props, style}); - }); - } - - /** - * it renders a switch panel styler - * @prop {object} style - * @prop {object} switchPanelOptions - */ - renderPanelStyle = (style = {}, switchPanelOptions = {}, i) => { - - const stylerProps = { - style, - onChange: this.change, - width: this.props.width - }; - - /* getting pieces to render in the styler - // only for marker there is no preview - // TODO move into separate functions the checks for showing the various pieces of styler - */ - const isTextOrSymbol = isTextStyle(style) || isSymbolStyle(style); - const preview = !(isMarkerStyle(style) || isSymbolStyle(style) && (checkSymbolsError(this.props.symbolErrors) || - checkSymbolsError(this.props.symbolErrors, "loading_symbol" + style.shape))) && (
- -
); - // TODO improve conditions to show the stroke and fill - const stroke = isStrokeStyle(style) && isSymbolStyle(style) && - (checkSymbolsError(this.props.symbolErrors) || - checkSymbolsError(this.props.symbolErrors, "loading_symbol" + style.shape)) - ? null : isStrokeStyle(style) ? : null; - const fill = isFillStyle(style) && isSymbolStyle(style) && - (checkSymbolsError(this.props.symbolErrors) || - checkSymbolsError(this.props.symbolErrors, "loading_symbol" + style.shape)) - ? null : isFillStyle(style) && || null; - const text = isTextStyle(style) && || null; - const markerType = (isMarkerStyle(style) || isSymbolStyle(style)) && || null; - const markerGlyph = isMarkerStyle(style) && || null; - const symbolLayout = isSymbolStyle(style) && ( - { - this.props.onUpdateSymbols(symbols); - }} - options={this.props.symbolList} - symbolErrors={this.props.symbolErrors} - onLoadingError={this.props.onSetErrorSymbol}/>) || null; - const separator =
; - - const sections = [markerType, preview, symbolLayout, markerGlyph, text, fill, stroke]; - - return ( - - { - /* adding the separator between sections */ - sections.reduce((prev, curr, k) => [prev, prev && curr && {separator}, curr]) - } - - ); - } - - render() { - const styles = castArray(this.props.style); - return (
{styles.map((style, i) => this.renderPanelStyle( - {...style, id: style.id || uuidv1()}, - { - expanded: this.state.expanded[i], - locked: this.state.locked[i], - onSwitch: () => { - this.setState(() => { - const expanded = this.state.expanded.map((e, k) => i === k ? !this.state.expanded[i] : this.state.expanded[k]); - return {expanded}; - }); - let newStyles = styles.map((s, k) => k === i ? {...s, "filtering": !this.state.expanded[i]} : s); - this.props.onChangeStyle(newStyles); - }, - title: style.title || getStylerTitle(style) + " Style"}, - i))}
); - } - change = (id, values) => { - const styles = castArray(this.props.style); - let styleChanged = {...find(styles, { 'id': id }), ...values}; - - if (isSymbolStyle(styleChanged)) { - if (!fetchStyle(hashAndStringify(styleChanged))) { - createSvgUrl(styleChanged, styleChanged.symbolUrl) - .then(symbolUrlCustomized => { - this.updateStyles(id, {...styleChanged, symbolUrlCustomized}, styles, true); - }); - } else { - this.updateStyles(id, fetchStyle(hashAndStringify(styleChanged)), styles, true); - } - } else { - this.updateStyles(id, styleChanged, styles, true); - } - } - updateStyles = (id, style, styles, register = true) => { - if (register) { - registerStyle(hashAndStringify(style), style); - } - let newStyles = arrayUpdate(false, style, { 'id': id }, styles ); - this.props.onChangeStyle(newStyles); - } - changeSymbolType = (id, pointType) => { - this.updateStylesAndType(id, pointType, this.props.defaultStyles.POINT?.[pointType]); - } - - updateStylesAndType = (id, pointType, pointStyle) => { - const styles = castArray(this.props.style); - const styleChangedIndex = findIndex(styles, { 'id': id}); - if (styleChangedIndex !== -1) { - let newStyles = styles.map((s, k) => k === styleChangedIndex ? {...pointStyle, id: s.id, title: s.title, geometry: s.geometry, filtering: s.filtering} : s); - this.props.onChangeStyle(newStyles); - } - } - checkSymbolUrl = ({style, symbolErrors, onLoadingError = this.props.onSetErrorSymbol}) => { - axios.get(style.symbolUrl) - .then(() => { - if (!checkSymbolsError(this.props.symbolErrors, "loading_symbol" + style.shape )) { - const errors = filter(symbolErrors, s => s !== "loading_symbol" + style.shape); - onLoadingError(errors); - } - }) - .catch(() => { - if (!checkSymbolsError(this.props.symbolErrors, "loading_symbol" + style.shape )) { - onLoadingError(symbolErrors.concat(["loading_symbol" + style.shape])); - } - }); - } -} - -export default Manager; diff --git a/web/client/components/style/vector/Stroke.jsx b/web/client/components/style/vector/Stroke.jsx deleted file mode 100644 index dab70b50ab..0000000000 --- a/web/client/components/style/vector/Stroke.jsx +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2018, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. -*/ - -import PropTypes from 'prop-types'; - -import React from 'react'; -import { Row, Col } from 'react-bootstrap'; -import { isNil, isEqual } from 'lodash'; -import tinycolor from 'tinycolor2'; -import Slider from 'react-nouislider'; - -// number localizer? -import numberLocalizer from 'react-widgets/lib/localizers/simple-number'; - -// not sure this is needed, TODO check! -numberLocalizer(); -import Message from '../../I18N/Message'; -import OpacitySlider from '../../../plugins/TOC/components/OpacitySlider'; -import ColorSelector from '../ColorSelector'; -import DashArray from './DashArray'; -import { addOpacityToColor } from '../../../utils/VectorStyleUtils'; - -/** - * Styler for the stroke properties of a vector style -*/ -class Stroke extends React.Component { - static propTypes = { - style: PropTypes.object, - defaultColor: PropTypes.string, - lineDashOptions: PropTypes.array, - onChange: PropTypes.func, - width: PropTypes.number, - constraints: PropTypes.object - }; - - static defaultProps = { - style: {}, - constraints: { - maxWidth: 15, - minWidth: 1 - }, - onChange: () => {} - }; - - shouldComponentUpdate(nextProps) { - return !isEqual(this.props.style, nextProps.style) - || !isEqual(this.props.lineDashOptions, nextProps.lineDashOptions); - } - render() { - const {style} = this.props; - return (
- - - - - - - - - - - { - this.props.onChange(style.id, {dashArray}); - }} - /> - - - - - - - - { - if (!isNil(c)) { - const color = tinycolor(c).toHexString(); - const opacity = c.a; - this.props.onChange(style.id, {color, opacity}); - } - }}/> - - - - - - - - { - this.props.onChange(style.id, {opacity}); - }}/> - - - - - - - -
- Math.round(value), - to: value => Math.round(value) + ' px' - }} - range={{ - min: isNil(this.props.constraints && this.props.constraints.minWidth) ? 1 : this.props.constraints.maxWidth, - max: this.props.constraints && this.props.constraints.maxWidth || 15 - }} - onChange={(values) => { - const weight = parseInt(values[0].replace(' px', ''), 10); - this.props.onChange(style.id, {weight}); - }} - /> -
- -
-
); - } -} - -export default Stroke; diff --git a/web/client/components/style/vector/Text.jsx b/web/client/components/style/vector/Text.jsx deleted file mode 100644 index d131df60d6..0000000000 --- a/web/client/components/style/vector/Text.jsx +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2018, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. -*/ - -import PropTypes from 'prop-types'; - -import React from 'react'; -import { Combobox } from 'react-widgets'; -import Slider from 'react-nouislider'; -import IntlNumberFormControl from '../../I18N/IntlNumberFormControl'; -import numberLocalizer from 'react-widgets/lib/localizers/simple-number'; -// not sure this is needed, TODO check! -numberLocalizer(); - -import Message from '../../I18N/Message'; -import { getMessageById } from '../../../utils/LocaleUtils'; -import { createFont } from '../../../utils/LegacyAnnotationsUtils'; - -/** - * Styler for the stroke properties of a vector style -*/ -class Text extends React.Component { - static propTypes = { - style: PropTypes.object, - onChange: PropTypes.func, - addOpacityToColor: PropTypes.func, - width: PropTypes.number, - uomValues: PropTypes.array, - alignValues: PropTypes.array, - fontStyleValues: PropTypes.array, - fontWeightValues: PropTypes.array, - fontFamilyValues: PropTypes.array, - shapeStyle: PropTypes.object, - rotationStep: PropTypes.number - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - style: {}, - onChange: () => {}, - uomValues: [{value: "px"}, {value: "em"}], - fontWeightValues: [{value: "normal"}, {value: "bold"}], - alignValues: [{value: "start", label: "left"}, {value: "center", label: "center"}, {value: "end", label: "right"}], - fontStyleValues: [{value: "normal"}, {value: "italic"}], - fontFamilyValues: [{value: "Arial"}, {value: "Helvetica"}, {value: "sans-serif"}, {value: "Courier"}], - shapeStyle: {}, - rotationStep: 5 - }; - - state = { - fontFamily: "Arial" - }; - - render() { - const messages = { - emptyList: getMessageById(this.context.messages, "queryform.attributefilter.autocomplete.emptyList"), - open: getMessageById(this.context.messages, "queryform.attributefilter.autocomplete.open"), - emptyFilter: getMessageById(this.context.messages, "queryform.attributefilter.autocomplete.emptyFilter") - }; - const {style} = this.props; - return (
-
- -
-
-
- -
-
- { - let fontFamily = e.value ? e.value : e; - if (fontFamily === "") { - fontFamily = "Arial"; - } - this.setState({fontFamily}); - const font = createFont({...style, fontFamily}); - this.props.onChange(style.id, {fontFamily, font}); - }} - /> -
-
-
-
- -
-
-
- { - const fontSize = val || 14; - const font = createFont({...style, fontSize}); - this.props.onChange(style.id, {fontSize, font}); - }} - type="number"/> -
- { - let fontSizeUom = e.value ? e.value : e; - if (this.props.uomValues.map(f => f.value).indexOf(fontSizeUom) === -1) { - fontSizeUom = "px"; - } - const font = createFont({...style, fontSizeUom}); - this.props.onChange(style.id, {fontSizeUom, font}); - }} - /> -
-
-
-
- -
-
- { - let fontStyle = e.value ? e.value : e; - if (this.props.fontStyleValues.map(f => f.value).indexOf(fontStyle) === -1) { - fontStyle = style.fontStyle; - } - const font = createFont({...style, fontStyle}); - this.props.onChange(style.id, {fontStyle, font}); - }} - /> -
-
-
-
- -
-
- { - let fontWeight = e.value ? e.value : e; - if (this.props.fontWeightValues.map(f => f.value).indexOf(fontWeight) === -1) { - fontWeight = style.fontWeight; - } - const font = createFont({...style, fontWeight}); - this.props.onChange(style.id, {fontWeight, font}); - }} - /> -
-
-
-
- -
-
-
-
- -
-
- { - let textAlign = e.value ? e.value : e; - if (this.props.alignValues.map(f => f.value).indexOf(textAlign) === -1) { - textAlign = "center"; - } - this.props.onChange(style.id, {textAlign}); - }} - /> -
-
-
-
- -
-
-
- Math.round(parseFloat(value)), - to: value => Math.round(value) + ' °' - }} - range={{ - min: 0, - max: 359 - }} - onChange={(values) => { - const rotationDeg = parseInt(values[0].replace(' °', ''), 10); - this.props.onChange(style.id, {textRotationDeg: rotationDeg}); - }} - /> -
-
-
-
); - } -} - -export default Text; diff --git a/web/client/components/style/vector/marker/MarkerGlyph.jsx b/web/client/components/style/vector/marker/MarkerGlyph.jsx deleted file mode 100644 index ba268bfc45..0000000000 --- a/web/client/components/style/vector/marker/MarkerGlyph.jsx +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2018, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. -*/ - -import PropTypes from 'prop-types'; - -import React from 'react'; -import Filter from '../../../misc/Filter'; -import MarkerPropertyPicker from '../../MarkerPropertyPicker'; -import Message from '../../../I18N/Message'; - -/** - * Styler for the glyph, color and shape -*/ -class MarkerGlyph extends React.Component { - static propTypes = { - style: PropTypes.object, - markersOptions: PropTypes.object, - onChange: PropTypes.func, - width: PropTypes.number - }; - - static defaultProps = { - style: {}, - onChange: () => {} - }; - - // eslint-disable-next-line no-unused-vars - renderMarkers = (markers, prefix = '') => { - return markers.map((marker) => { - if (marker.markers) { - return this.renderMarkers(marker.markers, marker.name + '-'); - } - return ( -
this.selectStyle(marker)} - className={this.isCurrentStyle(marker) ? 'ms-marker-selected' : ''} - style={{ - ...marker.thumbnailStyle - }} - />); - }); - }; - - render() { - const selectedMarker = this.props.markersOptions.markers.reduce((acc, { markers }) => [...acc, ...markers], []).find((marker) => this.isCurrentStyle(marker)) || {}; - return ( -
-
-
- -
-
- - -
- }> -
-
- -
-
- {this.props.markersOptions.glyphs.map(glyph => { - if (this.filterMarkerGlyph(glyph)) { - return ( -
{ - this.props.onChange(this.props.style.id, {iconGlyph: glyph}); - }}> - -
- ); - } - return null; - })} -
-
- -
-
- -
-
- -
-
- - }> -
- {this.renderMarkers(this.props.markersOptions.markers)} -
-
-
-
-
- ); - } - - isCurrentStyle = (m) => { - // TODO change this - return this.props.markersOptions.markersConfig.matches(this.props.style, m.style); - } - - selectStyle = (marker) => { - return this.props.onChange(this.props.style.id, {...this.props.markersOptions.markersConfig.getStyle(marker.style)}); - }; - - filterMarkerGlyph = (marker) =>{ - return marker && marker.toLowerCase().indexOf(this.props.markersOptions?.filter?.toLowerCase() || '') !== -1; - }; -} - -export default MarkerGlyph; diff --git a/web/client/components/style/vector/marker/MarkerType.jsx b/web/client/components/style/vector/marker/MarkerType.jsx deleted file mode 100644 index 0e2591ab94..0000000000 --- a/web/client/components/style/vector/marker/MarkerType.jsx +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2018, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. -*/ - -import PropTypes from 'prop-types'; - -import React from 'react'; -import { Row, Col } from 'react-bootstrap'; -import Select from 'react-select'; -import Message from '../../../I18N/Message'; - -/** - * Styler for the gliph, color and shape -*/ -class MarkerType extends React.Component { - static propTypes = { - style: PropTypes.object, - pointType: PropTypes.string, - options: PropTypes.array, - onChangeType: PropTypes.func, - width: PropTypes.number - }; - - static defaultProps = { - style: {}, - options: [{ - label: 'Marker', - value: 'marker' - }, { - label: 'Symbol', - value: 'symbol' - }], - pointType: "marker", - onChangeType: () => {} - }; - - render() { - return ( -
- - - - - - list - const iconRenderer = (option) => { - return (
- - {option.label}
); - }; - // checking if default shape exists - const shapeDefault = this.props.options && this.props.options.length ? find(this.props.options, (s) => s.value === this.props.defaultShape) && this.props.defaultShape : DEFAULT_SHAPE; - return ( -
- - - - - - { // managing misconfigruation of symbols.json (symbolsPath) - checkSymbolsError(this.props.symbolErrors) ? ( - - - - - - - - - - - ) : ( -
- - - - - - - - - - - - - - ); - }; - - renderAvancedRule = () => { - return ()} eventKey="3"> - - - - ); - }; - - renderSelector = () => { - return ( - - {!this.props.hideLayerSelector ? ( - - this.props.selectLayer(value)} - valueField={"id"} - textField={"title"} /> - ) : null} - {this.props.layer ? ( - - this.props.selectRule(value.id)} - valueField={"id"} - textField={"name"} /> ) : null} - {this.props.rule ? ( - - - this.props.setRuleParameter('name', ev.target.value)} value={this.props.rule.name}/> - ) : null} - - ); - }; - - renderVectorStyler = () => { - return this.props.layer ? - - - {this.props.rule ? this.renderSymbolStyler() : null} - {this.props.rule ? this.renderAvancedRule() : null} - - : null; - }; - - renderApplyBtn = () => { - let disabled = !this.props.rule; - return ( - - - - - - - - ); - }; - - renderBody = () => { - - return ( - {this.renderError()} - {this.renderSelector()} - {this.renderVectorStyler()} - {this.props.layer ? this.renderApplyBtn() : null} - ); - }; - - render() { - if (this.props.forceOpen || this.props.open) { - return this.props.withContainer ? - }> - {this.renderBody()} - : this.renderBody(); - } - return null; - } - - apply = () => { - let style = vecStyleToSLD({rules: this.props.rules, layer: this.props.layer}); - this.props.changeLayerProperties(this.props.layer.id, { params: assign({}, this.props.layer.params, {SLD_BODY: style})}); - }; -} - -const selector = createSelector([ - (state) => state.controls.toolbar && state.controls.toolbar.active === 'vectorstyler', - ruleselctor, - (state) => state.vectorstyler && state.vectorstyler.rules, - (state) => state.vectorstyler && state.vectorstyler.layer, - layersSelector -], (open, rule, rules, layer, layers) => ({ - open, - rule, - rules, - layer, - layers: layers.filter((l) => { return l.group !== 'background'; }) -})); - -const VectorStylerPlugin = connect(selector, { - setVectorStyleParameter: setVectorStyleParameter, - selectLayer: setVectorLayer, - addRule: newVectorRule, - removeRule: removeVectorRule, - selectRule: selectVectorRule, - changeLayerProperties: changeLayerProperties, - setRuleParameter: setVectorRuleParameter -})(VectorStyler); - -export default { - VectorStylerPlugin: assign( VectorStylerPlugin, - { - Toolbar: { - name: 'vectorstyler', - help: , - tooltip: "vectorstyler.tooltip", - icon: , - position: 9, - panel: true, - exclusive: true - } - }), - reducers: { - vectorstyler: vectorstylerReducers - } -}; diff --git a/web/client/plugins/omnibar/OmniBarMenu.jsx b/web/client/plugins/omnibar/OmniBarMenu.jsx deleted file mode 100644 index b8b697a828..0000000000 --- a/web/client/plugins/omnibar/OmniBarMenu.jsx +++ /dev/null @@ -1,58 +0,0 @@ - -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * 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 PropTypes from 'prop-types'; - -import { NavDropdown, Glyphicon, MenuItem } from 'react-bootstrap'; -import { connect } from 'react-redux'; -import { partial } from 'lodash'; -import Message from '../locale/Message'; -import Button from '../../components/misc/Button'; - -class OmniBarMenu extends React.Component { - static propTypes = { - dispatch: PropTypes.func, - items: PropTypes.array, - title: PropTypes.node, - onItemClick: PropTypes.func - }; - - static contextTypes = { - messages: PropTypes.object, - router: PropTypes.object - }; - - static defaultProps = { - items: [], - onItemClick: () => {}, - title: - }; - - renderNavItem = (tool) => { - return ( { - e.preventDefault(); - if (tool.action) { - this.props.dispatch(partial(tool.action, this.context)); - } else { - this.props.onItemClick(tool); - } - }}>{tool.icon} {tool.text}); - }; - - render() { - return (} > - {this.props.title} - {this.props.items.sort((a, b) => a.position - b.position).map(this.renderNavItem)} - ) - ; - } -} - -export default connect()(OmniBarMenu); diff --git a/web/client/plugins/rasterstyler/index.js b/web/client/plugins/rasterstyler/index.js deleted file mode 100644 index 2bb17c9d37..0000000000 --- a/web/client/plugins/rasterstyler/index.js +++ /dev/null @@ -1,72 +0,0 @@ -/** -* Copyright 2016, GeoSolutions Sas. -* All rights reserved. -* -* This source code is licensed under the BSD-style license found in the -* LICENSE file in the root directory of this source tree. -*/ - -import { connect } from 'react-redux'; - -import { setRasterStyleParameter } from '../../actions/rasterstyler'; -import BandSelectorComp from '../../components/style/BandSelector'; -import EqualIntervalComp from '../../components/style/EqualInterval'; -import OpacityPickerComp from '../../components/style/OpacityPicker'; -import PseudoColorSettingsComp from '../../components/style/PseudoColorSettings'; -import RasterStyleTypePickerComp from '../../components/style/RasterStyleTypePicker'; - -export const RedBandSelector = connect((state) => { return state.rasterstyler.redband || {}; }, - { - onChange: setRasterStyleParameter.bind(null, 'redband') - })(BandSelectorComp); - -export const BlueBandSelector = connect((state) => { return state.rasterstyler.blueband || {}; }, - { - onChange: setRasterStyleParameter.bind(null, 'blueband') - })(BandSelectorComp); - -export const GreenBandSelector = connect((state) => { return state.rasterstyler.greenband || {}; }, - { - onChange: setRasterStyleParameter.bind(null, 'greenband') - })(BandSelectorComp); - -export const GrayBandSelector = connect((state) => { return state.rasterstyler.grayband || {}; }, - { - onChange: setRasterStyleParameter.bind(null, 'grayband') - })(BandSelectorComp); -export const PseudoBandSelector = connect((state) => { return state.rasterstyler.pseudoband || {}; }, - { - onChange: setRasterStyleParameter.bind(null, 'pseudoband') - })(BandSelectorComp); - -export const RasterStyleTypePicker = connect((state) => { return state.rasterstyler.typepicker || {}; }, - { - onChange: setRasterStyleParameter.bind(null, 'typepicker') - })(RasterStyleTypePickerComp); - -export const OpacityPicker = connect((state) => { return state.rasterstyler.opacitypicker || {}; }, - { - onChange: setRasterStyleParameter.bind(null, 'opacitypicker') - })(OpacityPickerComp); - -export const EqualInterval = connect((state) => { return state.rasterstyler.equalinterval || {}; }, - { - onChange: setRasterStyleParameter.bind(null, 'equalinterval') - })(EqualIntervalComp); - -export const PseudoColor = connect((state) => { return state.rasterstyler.pseudocolor || {}; }, - { - onChange: setRasterStyleParameter.bind(null, 'pseudocolor') - })(PseudoColorSettingsComp); - -export default { - RedBandSelector, - BlueBandSelector, - GreenBandSelector, - GrayBandSelector, - PseudoBandSelector, - RasterStyleTypePicker, - EqualInterval, - PseudoColor, - OpacityPicker -}; diff --git a/web/client/plugins/rasterstyler/rasterstyler.css b/web/client/plugins/rasterstyler/rasterstyler.css deleted file mode 100644 index 106a0c5b89..0000000000 --- a/web/client/plugins/rasterstyler/rasterstyler.css +++ /dev/null @@ -1,7 +0,0 @@ -.mapstore-rasterstyler-panel { - width: 600px; - position: absolute; - top: 10px; - right: 60px; - z-index: 1000; -} \ No newline at end of file diff --git a/web/client/plugins/styler/styler.css b/web/client/plugins/styler/styler.css deleted file mode 100644 index 3509847bc4..0000000000 --- a/web/client/plugins/styler/styler.css +++ /dev/null @@ -1,29 +0,0 @@ -.mapstore-styler-panel { - width: 600px; - position: absolute; - top: 10px; - right: 60px; - z-index: 1000; -} -.mapstore-styler-panel button{ - font-size:14px !important; - border-radius: 4px; - height: 30px; - padding-bottom: 5px; -} -.mapstore-styler-panel button:disabled{ - color:white; -} -.mapstore-styler-panel .panel-heading{ - background-color: #078AA3 !important; - color:white !important; -} - -.mapstore-styler-panel .form-control{ - height: 32px !important; - -} - -.mapstore-styler-panel, .panel, .panel-default{ - overflow: visible !important; -} diff --git a/web/client/plugins/vectorstyler/index.js b/web/client/plugins/vectorstyler/index.js deleted file mode 100644 index 0895c29230..0000000000 --- a/web/client/plugins/vectorstyler/index.js +++ /dev/null @@ -1,36 +0,0 @@ -/** -* Copyright 2016, GeoSolutions Sas. -* All rights reserved. -* -* This source code is licensed under the BSD-style license found in the -* LICENSE file in the root directory of this source tree. -*/ - -import { connect } from 'react-redux'; - -import { setVectorStyleParameter } from '../../actions/vectorstyler'; -import ScaleDenominatorComp from '../../components/style/ScaleDenominator'; -import StylePointComp from '../../components/style/StylePoint'; -import StylePolygonComp from '../../components/style/StylePolygon'; -import StylePolylineComp from '../../components/style/StylePolyline'; -import { symbolselector } from '../../selectors/vectorstyler'; - -export const StylePolygon = connect(symbolselector, { - setStyleParameter: setVectorStyleParameter.bind(null, 'symbol') -})(StylePolygonComp); - -export const StylePoint = connect(symbolselector, { - setStyleParameter: setVectorStyleParameter.bind(null, 'symbol') -})(StylePointComp); - -export const StylePolyline = connect(symbolselector, { - setStyleParameter: setVectorStyleParameter.bind(null, 'symbol') -})(StylePolylineComp); -export const ScaleDenominator = ScaleDenominatorComp; - -export default { - StylePolygon, - StylePolyline, - StylePoint, - ScaleDenominator -}; diff --git a/web/client/plugins/vectorstyler/vectorstyler.css b/web/client/plugins/vectorstyler/vectorstyler.css deleted file mode 100644 index 83d8cfd50e..0000000000 --- a/web/client/plugins/vectorstyler/vectorstyler.css +++ /dev/null @@ -1,7 +0,0 @@ -.mapstore-vectorstyler-panel { - width: 600px; - position: absolute; - top: 10px; - right: 60px; - z-index: 1000; -} \ No newline at end of file diff --git a/web/client/product/assets/img/rasterstyler.jpg b/web/client/product/assets/img/rasterstyler.jpg deleted file mode 100644 index 65f7b1184a..0000000000 Binary files a/web/client/product/assets/img/rasterstyler.jpg and /dev/null differ diff --git a/web/client/reducers/__tests__/rasterstyler-test.js b/web/client/reducers/__tests__/rasterstyler-test.js deleted file mode 100644 index 258fba70af..0000000000 --- a/web/client/reducers/__tests__/rasterstyler-test.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ -import expect from 'expect'; - -import rasterstyler from '../rasterstyler'; -import { SET_RASTERSTYLE_PARAMETER, SET_RASTER_LAYER } from '../../actions/rasterstyler'; - -describe('Test the rasterstyler reducer', () => { - it('set a rasterstyle parameter', () => { - const state = rasterstyler(undefined, { - type: SET_RASTERSTYLE_PARAMETER, - component: 'testComponent', - property: 'testProperty', - value: 'testValue' - }); - expect(state.testComponent).toExist(); - expect(state.testComponent.testProperty).toExist(); - expect(state.testComponent.testProperty).toBe('testValue'); - }); - - it('set a rasterstyle layer', () => { - const state = rasterstyler(undefined, { - type: SET_RASTER_LAYER, - layer: 'testLayer' - }); - expect(state.layer).toBe('testLayer'); - }); - -}); diff --git a/web/client/reducers/rasterstyler.js b/web/client/reducers/rasterstyler.js deleted file mode 100644 index 2f0fc27a15..0000000000 --- a/web/client/reducers/rasterstyler.js +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -import { SET_RASTERSTYLE_PARAMETER, SET_RASTER_LAYER } from '../actions/rasterstyler'; - -import assign from 'object-assign'; -import { STYLER_RESET } from '../actions/styler'; - -const initialSpec = { - pseudoband: {band: '1', contrast: 'none', algorithm: "none", gammaValue: 1, min: 1, max: 255}, - redband: {band: '1', contrast: 'none', algorithm: "none", gammaValue: 1, min: 1, max: 255}, - blueband: {band: '3', contrast: 'none', algorithm: "none", gammaValue: 1, min: 1, max: 255}, - greenband: {band: '2', contrast: 'none', algorithm: "none", gammaValue: 1, min: 1, max: 255}, - grayband: {band: '1', contrast: 'none', algorithm: "none", gammaValue: 1, min: 1, max: 255}, - pseudocolor: {colorMapEntry: [], type: 'ramp', selected: null, opacity: '1.00', activepanel: "1"}, - equalinterval: {classes: 6, max: 255, min: 0, ramp: "Blues"} -}; - -function setBaseOptions(describe = {}) { - let newInit = {}; - Object.keys(initialSpec).reduce((pr, next) => { - pr[next] = assign({}, initialSpec[next]); - return pr; - }, newInit); - if (describe.bands && describe.bands.length > 0) { - newInit.pseudoband.band = describe.bands[0]; - newInit.redband.band = describe.bands[0]; - newInit.greenband.band = describe.bands.length > 1 ? describe.bands[1] : describe.bands[0]; - newInit.blueband.band = describe.bands.length > 2 ? describe.bands[2] : describe.bands[0]; - newInit.grayband.band = describe.bands[0]; - } - if (describe.range) { - newInit.equalinterval.min = describe.range.min; - newInit.equalinterval.max = describe.range.max; - } - return newInit; -} - -function rasterstyler(state = initialSpec, action) { - switch (action.type) { - case SET_RASTERSTYLE_PARAMETER: { - return assign({}, state, { - [action.component]: assign({}, state[action.component], { - [action.property]: action.value - }) - }); - } - case SET_RASTER_LAYER: { - - return assign({}, setBaseOptions(action.layer.describeLayer), { layer: action.layer}); - } - case STYLER_RESET: { - return initialSpec; - } - default: - return state; - } -} - -export default rasterstyler; diff --git a/web/client/reducers/styler.js b/web/client/reducers/styler.js deleted file mode 100644 index c96f2b4bbe..0000000000 --- a/web/client/reducers/styler.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -import { SET_VECTOR_LAYER } from '../actions/vectorstyler'; - -import { SET_RASTER_LAYER } from '../actions/rasterstyler'; -import { SET_STYLER_LAYER, STYLER_RESET } from '../actions/styler'; -function styler(state = {}, action) { - switch (action.type) { - case SET_VECTOR_LAYER: { - return {...state, layer: action.layer, type: "vector"}; - } - case SET_RASTER_LAYER: { - return {...state, layer: action.layer, type: "raster"}; - } - case STYLER_RESET: { - return {}; - } - case SET_STYLER_LAYER: { - return {...state, layer: action.layer}; - } - default: - return state; - } -} - -export default styler; diff --git a/web/client/reducers/vectorstyler.js b/web/client/reducers/vectorstyler.js deleted file mode 100644 index f99e78a72f..0000000000 --- a/web/client/reducers/vectorstyler.js +++ /dev/null @@ -1,136 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -import { - NEW_VECTOR_RULE, - SELECT_VECTOR_RULE, - REMOVE_VECTOR_RULE, - SET_VECTORSTYLE_PARAMETER, - SET_VECTOR_LAYER, - SET_VECTOR_RULE_PARAMETER -} from '../actions/vectorstyler'; - -import { STYLER_RESET } from '../actions/styler'; -import assign from 'object-assign'; -import { isObject, findIndex } from 'lodash'; -const baseStyle = { - Point: { - type: "Point", - color: { r: 0, g: 0, b: 255, a: 1 }, - width: 3, - fill: { r: 0, g: 0, b: 255, a: 0.1 }, - radius: 10, - marker: false, - markName: "circle" - }, - Line: { - type: "Line", - color: { r: 0, g: 0, b: 255, a: 1 }, - width: 3 - }, - Polygon: { - type: "Polygon", - color: { r: 0, g: 0, b: 255, a: 1 }, - width: 3, - fill: { r: 0, g: 0, b: 255, a: 0.1 } - } - -}; - -const initialSpec = { - rules: [] -}; -function getType(layer) { - switch (layer.describeLayer.geometryType) { - case 'Polygon': - case 'MultiPolygon': { - return "Polygon"; - } - case 'MultiLineString': - case 'LineString': { - return "Line"; - } - case 'Point': - case 'MultiPoint': { - return "Point"; - } - default: { - return "Polygon"; - } - } -} - -function getBaseSymbol(type = "Polygon") { - let newSymbol = {}; - let symbol = baseStyle[type]; - Object.keys(symbol).reduce((pr, next) => { - pr[next] = isObject(symbol[next]) ? assign({}, symbol[next]) : symbol[next]; - return pr; - }, newSymbol); - return newSymbol; -} - -function getRuleIdx(rules, id) { - return findIndex(rules, (r) => {return r.id === id; }); -} - -function vectorstyler(state = initialSpec, action) { - switch (action.type) { - case NEW_VECTOR_RULE: { - const newRule = { - id: action.id, - symbol: getBaseSymbol(getType(state.layer)), - name: 'New Rule' - }; - - return assign({}, state, {rule: newRule.id, rules: state.rules ? [...state.rules, newRule] : [newRule]}); - - } - case SELECT_VECTOR_RULE: { - return assign({}, state, {rule: action.id}); - - } - case REMOVE_VECTOR_RULE: { - const idx = getRuleIdx(state.rules, action.id); - let newSelected = state.rules[idx - 1] ? state.rules[idx - 1].id : undefined; - if (newSelected === undefined) { - newSelected = state.rules[idx + 1] ? state.rules[idx + 1].id : undefined; - } - return assign({}, state, {rule: newSelected, rules: state.rules.filter((rule) => rule.id !== action.id)}); - } - case SET_VECTOR_RULE_PARAMETER: { - let newRules = state.rules.slice(); - const ruleIdx = getRuleIdx(newRules, state.rule); - const activeRule = newRules[ruleIdx]; - newRules[ruleIdx] = assign({}, activeRule, {[action.property]: action.value}); - return assign({}, state, {rules: newRules}); - } - case SET_VECTORSTYLE_PARAMETER: { - let newRules = state.rules.slice(); - const ruleIdx = getRuleIdx(newRules, state.rule); - const activeRule = newRules[ruleIdx]; - newRules[ruleIdx] = assign( {}, activeRule, { - [action.component]: assign({}, activeRule[action.component], { - [action.property]: action.value - }) - }); - return assign({}, state, {rules: newRules}); - - } - case SET_VECTOR_LAYER: { - return assign({}, initialSpec, { layer: action.layer}); - } - case STYLER_RESET: { - return initialSpec; - } - default: - return state; - } -} - -export default vectorstyler; diff --git a/web/client/selectors/vectorstyler.js b/web/client/selectors/vectorstyler.js deleted file mode 100644 index 0d1ea3f60f..0000000000 --- a/web/client/selectors/vectorstyler.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -import { createSelector } from 'reselect'; - -import { head } from 'lodash'; - -export const ruleselctor = (state) => state.vectorstyler && state.vectorstyler.rule && head(state.vectorstyler.rules.filter((r) => {return r.id === state.vectorstyler.rule; })); - -export const symbolselector = createSelector([ruleselctor], - (rule) => ({ - shapeStyle: rule && rule.symbol || {} - })); diff --git a/web/client/utils/LegacyAnnotationsUtils.js b/web/client/utils/LegacyAnnotationsUtils.js deleted file mode 100644 index c9509717d6..0000000000 --- a/web/client/utils/LegacyAnnotationsUtils.js +++ /dev/null @@ -1,739 +0,0 @@ -/* - * Copyright 2018, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. -*/ - -import uuidv1 from 'uuid/v1'; - -import {getMessageById} from './LocaleUtils'; -import MarkerUtils from './MarkerUtils'; -import { geometryFunctions, fetchStyle, hashAndStringify } from './VectorStyleUtils'; -import { set } from './ImmutableUtils'; -import { values, isNil, slice, head, castArray, last, isArray, findIndex, isString, get, includes } from 'lodash'; -import uuid from 'uuid'; -import turfCenter from '@turf/center'; -import assign from 'object-assign'; -let AnnotationsUtils = {}; - -export const STYLE_CIRCLE = { - color: '#ffcc33', - opacity: 1, - weight: 3, - fillColor: '#ffffff', - fillOpacity: 0.2 -}; -export const STYLE_POINT_MARKER = { - iconGlyph: 'comment', - iconShape: 'square', - iconColor: 'blue' -}; -export const STYLE_POINT_SYMBOL = { - iconAnchor: [0.5, 0.5], - anchorXUnits: 'fraction', - anchorYUnits: 'fraction', - color: "#000000", - fillColor: "#000000", - opacity: 1, - size: 64, - fillOpacity: 1 -}; -export const STYLE_TEXT = { - fontStyle: 'normal', - fontSize: '14', - fontSizeUom: 'px', - fontFamily: 'Arial', - fontWeight: 'normal', - font: "14px Arial", - textAlign: 'center', - color: '#000000', - opacity: 1, - fillColor: '#000000', - fillOpacity: 1 -}; -export const STYLE_LINE = { - color: '#ffcc33', - opacity: 1, - weight: 3, - editing: { - fill: 1 - } -}; -export const STYLE_POLYGON = { - color: '#ffcc33', - opacity: 1, - weight: 3, - fillColor: '#ffffff', - fillOpacity: 0.2, - editing: { - fill: 1 - } -}; -/** - * some defaults for the style -*/ -export const DEFAULT_ANNOTATIONS_STYLES = { - "Text": STYLE_TEXT, - "Point": STYLE_POINT_MARKER, - "Circle": STYLE_CIRCLE, - "MultiPoint": STYLE_POINT_MARKER, - "LineString": STYLE_LINE, - "MultiLineString": STYLE_LINE, - "Polygon": STYLE_POLYGON, - "MultiPolygon": STYLE_POLYGON -}; -/** - * The constant for annotation type - */ -export const ANNOTATION_TYPE = "ms2-annotations"; - -/** - * The constant for annotations - */ -export const ANNOTATIONS = "annotations"; - -/** - * return two styles object for start and end point. - * usually added to a LineString - * @return {object[]} the two styles -*/ -export const getStartEndPointsForLinestring = () => { - return [{...DEFAULT_ANNOTATIONS_STYLES.Point, highlight: true, iconAnchor: [0.5, 0.5], type: "Point", title: "StartPoint Style", geometry: "startPoint", filtering: false, id: uuidv1()}, - {...DEFAULT_ANNOTATIONS_STYLES.Point, highlight: true, iconAnchor: [0.5, 0.5], type: "Point", title: "EndPoint Style", geometry: "endPoint", filtering: false, id: uuidv1()}]; -}; - -export const rgbaTorgb = (rgba = "") => { - return rgba.indexOf("rgba") !== -1 ? `rgb${rgba.slice(rgba.indexOf("("), rgba.lastIndexOf(","))})` : rgba; -}; - -export const textAlignTolabelAlign = (a) => (a === "start" && "lm") || (a === "end" && "rm") || "cm"; - -export const getStylesObject = ({type = "Point", features = []} = {}) => { - return type === "FeatureCollection" ? features.reduce((p, c) => { - p[c.geometry.type] = DEFAULT_ANNOTATIONS_STYLES[c.geometry.type]; - return p; - }, {type: "FeatureCollection"}) : {...DEFAULT_ANNOTATIONS_STYLES[type]}; -}; -export const getProperties = (props = {}, messages = {}) => ({title: getMessageById(messages, "annotations.defaulttitle") !== "annotations.defaulttitle" ? getMessageById(messages, "annotations.defaulttitle") : "Default title", id: uuidv1(), ...props}); - -export const getDashArrayFromStyle = dashArray => { - return isString(dashArray) && dashArray || isArray(dashArray) && dashArray.join(" "); -}; - -export const hasOutline = (style) => { - return style.color && style.opacity && style.weight; -}; - -export const annStyleToOlStyle = (type, tempStyle, label = "") => { - let style = tempStyle && tempStyle[type] ? tempStyle[type] : tempStyle; - const s = style ?? {}; - const dashArray = s.dashArray ? getDashArrayFromStyle(s.dashArray) : "solid"; - switch (type) { - case "MultiPolygon": - case "Polygon": - case "Circle": - return { - "strokeColor": rgbaTorgb(s.color), - "strokeOpacity": s.opacity, - "strokeWidth": s.weight, - "fillColor": rgbaTorgb(s.fillColor), - "fillOpacity": s.fillOpacity, - "strokeDashstyle": dashArray - }; - case "LineString": - case "MultiLineString": - return { - "strokeColor": rgbaTorgb(s.color), - "strokeOpacity": s.opacity, - "strokeWidth": s.weight, - "strokeDashstyle": dashArray - }; - case "Text": - const outline = hasOutline(s) ? { - "labelOutlineColor": rgbaTorgb(s.color), - "labelOutlineOpacity": s.opacity, - "labelOutlineWidth": s.weight - } : {}; - return { - "fontStyle": s.fontStyle, - "fontSize": s.fontSize, // in mapfish is in px - "fontFamily": s.fontFamily, - "fontWeight": s.fontWeight, - "labelAlign": textAlignTolabelAlign(s.textAlign), - "fontColor": rgbaTorgb(s.fillColor), - "fontOpacity": s.fillOpacity, - "label": label, - "stroke": true, - "strokeColor": rgbaTorgb(s.color), - "strokeOpacity": s.opacity, - "strokeWidth": s.weight, - "strokeDashstyle": dashArray, - ...outline - }; - case "Point": - case "MultiPoint": { - // TODO TEST THIS - const externalGraphic = s.symbolUrl && fetchStyle(hashAndStringify(s), "base64") || MarkerUtils.extraMarkers.markerToDataUrl(s); - let graphicXOffset = -18; - let graphicYOffset = -46; - if (s.iconAnchor && isArray(s.iconAnchor) && s.size) { - if (s.anchorXUnits === "pixels") { - graphicXOffset = -1 * s.iconAnchor[0]; - } else { - graphicXOffset = -1 * s.size * s.iconAnchor[0]; - } - if (s.anchorYUnits === "pixels") { - graphicYOffset = -1 * s.iconAnchor[1]; - } else { - graphicYOffset = -1 * s.size * s.iconAnchor[1]; - } - } - return externalGraphic ? { - "graphicWidth": s.size || 36, - "graphicHeight": s.size || 46, - externalGraphic, - graphicXOffset, - graphicYOffset, - "display": s.filtering === false && "none" - } : { - "fillColor": "#0000AE", - "fillOpacity": 0.5, - "strokeColor": "#0000FF", - "pointRadius": 10, - "strokeOpacity": 1, - "strokeWidth": 1, - "display": s.filtering === false && "none" - }; - } - default: - return { - "fillColor": "#FF0000", - "fillOpacity": 0, - "strokeColor": "#FF0000", - "pointRadius": 5, - "strokeOpacity": 1, - "strokeDashstyle": dashArray, - "strokeWidth": 1 - }; - } -}; - -/** - * function used to convert a geojson into a internal model. - * if it finds some textValues in the properties it will return this as Text - * otherwise it will return the original geometry type. - * @return {object} a transformed geojson with only geometry types -*/ -export const convertGeoJSONToInternalModel = ({type = "Point", geometries = [], features = []}, textValues = [], circles = []) => { - switch (type) { - case "Point": case "MultiPoint": { - return {type: textValues.length === 1 ? "Text" : type}; - } - case "Polygon": { - return {type: circles.length === 1 ? "Circle" : type}; - } - case "GeometryCollection": { - const onlyPoints = geometries.filter(g => g.type === "Point" || g.type === "MultiPoint"); - const onlyMultiPolygons = geometries.filter(g => g.type === "Polygon"); - let t = 0; - let p = 0; - return {type: "GeometryCollection", geometries: geometries.map(g => { - if (g.type === "Point" || g.type === "MultiPoint") { - if (onlyPoints.length === textValues.length) { - return {type: "Text"}; - } - if (textValues.length === 0) { - return {type: g.type}; - } - if (t === 0) { - t++; - return {type: "Text" }; - } - } - if (g.type === "Polygon") { - if (onlyMultiPolygons.length === circles.length) { - return {type: "Circle"}; - } - if (circles.length === 0) { - return {type: g.type}; - } - if (p === 0) { - p++; - return {type: "Circle" }; - } - } - return {type: g.type}; - })}; - } - case "FeatureCollection" : { - const featuresTypes = features.map(f => { - if (f.properties && f.properties.isCircle) { - return {type: "Circle"}; - } - if (f.properties && f.properties.isText) { - return {type: "Text"}; - } - return {type: f.geometry.type}; - }); - return {type: "FeatureCollection", features: featuresTypes}; - } - default: return {type}; - } -}; -/** - * Retrieves a non duplicated list of stylers - * @return {string[]} it returns the array of available styler from geometry of a feature -*/ -export const getAvailableStyler = ({type = "Point", geometries = [], features = []} = {}) => { - switch (type) { - case "Point": case "MultiPoint": { - return [AnnotationsUtils.getRelativeStyler(type)]; - } - case "Symbol": { - return [AnnotationsUtils.getRelativeStyler(type)]; - } - case "LineString": case "MultiLineString": { - return [AnnotationsUtils.getRelativeStyler(type)]; - } - case "Polygon": case "MultiPolygon": { - return [AnnotationsUtils.getRelativeStyler(type)]; - } - case "Text": { - return [AnnotationsUtils.getRelativeStyler(type)]; - } - case "Circle": { - return [AnnotationsUtils.getRelativeStyler(type)]; - } - case "GeometryCollection": { - return geometries.reduce((p, c) => { - return (p.indexOf(AnnotationsUtils.getRelativeStyler(c.type)) !== -1) ? p : p.concat(AnnotationsUtils.getAvailableStyler(c)); - }, []); - } - case "FeatureCollection": { - return features.reduce((p, c) => { - return (p.indexOf(AnnotationsUtils.getRelativeStyler(c.type)) !== -1) ? p : p.concat(AnnotationsUtils.getAvailableStyler(c)); - }, []); - } - default: return []; - } -}; -/** - * it converts a geometryType to a stylertype - * @return {string} a stylertype -*/ -export const getRelativeStyler = (type) => { - switch (type) { - case "Point": case "MultiPoint": { - return "marker"; - } - case "Symbol": { - return "symbol"; - } - case "Circle": { - return "circle"; - } - case "LineString": case "MultiLineString": { - return "lineString"; - } - case "Polygon": case "MultiPolygon": { - return "polygon"; - } - case "Text": { - return "text"; - } - default: return ""; - } -}; -/** - * it converts some props of a CSS-font into a shorhand form - * @return {string} a CSS-font -*/ -export const createFont = ({fontSize = "14", fontSizeUom = "px", fontFamily = "Arial", fontStyle = "normal", fontWeight = "normal"} = {}) => { - return `${fontStyle} ${fontWeight} ${fontSize}${fontSizeUom} ${fontFamily}`; -}; - -/** - * Converts any feature to a geometry type - * @param {object} feature - * @return {string} a geometry type - */ -export const getGeometryType = (feature) => { - if (feature?.properties?.isCircle) { - return 'Circle'; - } - if (feature?.properties?.isText) { - return 'Text'; - } - return feature?.geometry?.type; -}; -/** - * Converts any geometry type to a glyph - * @param {string} type of geometry - * @return {object} a glyph name and label - */ -export const getGeometryGlyphInfo = (type = 'Point') => { - const glyphs = { - Point: {glyph: 'point', label: 'Point'}, - MultiPoint: {glyph: 'point', label: 'Point'}, - LineString: {glyph: 'polyline', label: 'Line'}, - MultiLineString: {glyph: 'polyline', label: 'Line'}, - Polygon: {glyph: 'polygon', label: 'Polygon'}, - MultiPolygon: {glyph: 'polygon', label: 'Polygon'}, - Text: {glyph: 'font', label: 'Text'}, - Circle: {glyph: '1-circle', label: 'Circle'} - }; - return glyphs[type]; -}; -/** -* it converts any geoJSONObject to an annotation -* Mandatory elements: MUST be a geoJSON type Feature => properties with an ID and a title -* annotation style. -*/ -export const normalizeAnnotation = (ann = {}, messages = {}) => { - const annotation = ann.type === "FeatureCollection" ? {...ann} : {type: "Feature", geometry: ann}; - const style = getStylesObject(annotation); - const properties = getProperties(annotation.properties, messages); - return {style, properties, ...annotation}; -}; -export const removeDuplicate = (annotations) => values(annotations.reduce((p, c) => ({...p, [c.properties.id]: c}), {})); -/** -* Compress circle in a single MultiPolygon feature with style -* @param {object} geometry -* @param {object} properties -* @param {object} style -* @return {object} feature -*/ -export const circlesToMultiPolygon = ({geometries = []}, {circles = []}, style = STYLE_CIRCLE) => { - const coordinates = circles.reduce((coords, cIdx) => coords.concat([geometries[cIdx].coordinates]), []); - return {type: "Feature", geometry: {type: "MultiPolygon", coordinates}, properties: {id: uuidv1(), ms_style: annStyleToOlStyle("Circle", style)}}; -}; -/** -* Transform circle in a single Polygon feature with style -* @param {object} geometry -* @param {object} properties -* @param {object} style -* @return {object} feature -*/ -export const fromCircleToPolygon = (geometry, properties, style = STYLE_CIRCLE) => { - return {type: "Feature", geometry: properties.polygonGeom || geometry, properties: {id: properties.id || uuidv1(), ms_style: annStyleToOlStyle("Circle", style)}}; -}; -/** -* Transform text point to single point with style -* @param {object} geometry -* @param {object} properties -* @param {object} style -* @return {object} feature -*/ -export const fromTextToPoint = (geometry, properties, style = STYLE_TEXT) => { - return {type: "Feature", geometry, properties: {id: properties.id || uuidv1(), ms_style: annStyleToOlStyle("Text", style, properties.valueText)}}; -}; -/** -* Transform LineString to geodesic LineString (with more points) -* @param {object} geometry -* @param {object} properties -* @param {object} style -* @return {object} feature -*/ -export const fromLineStringToGeodesicLineString = (properties, style = STYLE_LINE) => { - return {type: "Feature", geometry: properties.geometryGeodesic, properties: {id: properties.id || uuidv1(), ms_style: annStyleToOlStyle(properties.geometryGeodesic.type, style)}}; -}; -/** -* Flatten text point to single point with style -* @param {object} geometry -* @param {object} properties -* @param {object} style -* @return {object[]} features -*/ -export const textToPoint = ({geometries = []}, {textGeometriesIndexes = [], textValues = []}, style = STYLE_TEXT) => { - return textGeometriesIndexes.map((tIdx, cIdx) => { - return {type: "Feature", geometry: geometries[tIdx], properties: {id: uuidv1(), ms_style: annStyleToOlStyle("Text", style, textValues[cIdx])}}; - }); -}; -/** -* Flatten geometry collection -* @param {object} GeometryCollection An annotation of type geometrycollection -* @return {object[]} an array of features -*/ -export const flattenGeometryCollection = ({geometry, properties, style}) => { - const circles = properties.circles && AnnotationsUtils.circlesToMultiPolygon(geometry, properties, style.Circle) || []; - const texts = properties.textGeometriesIndexes && AnnotationsUtils.textToPoint(geometry, properties, style.Text) || []; - const skeep = (properties.circles || []).concat(properties.textGeometriesIndexes || []); - const features = geometry.geometries.filter((el, idx) => skeep.indexOf(idx) === -1) - .map((geom) => ({ - type: "Feature", - geometry: geom, - properties: {id: uuidv1(), ms_style: annStyleToOlStyle(geom.type, style[geom.type])} - })); - return features.concat(circles, texts); -}; -// for the moment is used with ol functions -export const createGeometryFromGeomFunction = (ft) => { - let type = geometryFunctions[ft.style.geometry] && geometryFunctions[ft.style.geometry].type || ft.geometry.type; - let coordinates = ft.geometry.coordinates || []; - switch (ft.style.geometry ) { - case "startPoint": coordinates = head(coordinates); break; - case "endPoint": coordinates = last(coordinates); break; - case "centerPoint": coordinates = turfCenter(ft).geometry.coordinates; break; - default: break; - } - return {type, coordinates}; -}; -/** -* transform an annotation Feature into a simple geojson feature -* @param {object} feature coming from a ftcoll -* @return {object} a transformed feature -*/ -export const fromAnnotationToGeoJson = ({geometry: ftGeom, properties = {}, style = {}} = {}) => { - let geometry = style.geometry ? AnnotationsUtils.createGeometryFromGeomFunction({geometry: ftGeom, properties, style, type: "Feature"}) : ftGeom; - if (properties.isCircle && geometry.type === "Polygon") { - return AnnotationsUtils.fromCircleToPolygon(geometry, properties, style); - } - if (properties.isText) { - return AnnotationsUtils.fromTextToPoint(geometry, properties, style); - } - if (geometry.type === "LineString" && properties.useGeodesicLines && style.filtering) { - return AnnotationsUtils.fromLineStringToGeodesicLineString(properties, style); - } - return { - type: "Feature", - geometry, - properties: {id: properties.id || uuidv1(), ms_style: annStyleToOlStyle(geometry.type, style)} - }; -}; -/** -* Adapt annotation features to print pdf -* @param {object[]} features -* @param {object} style -* @return {object[]} features -*/ -export const annotationsToPrint = (features = []) => { - return features.reduce((coll, f) => { - if (f.type === "FeatureCollection") { - // takes the style from the feature coll if it is missing from the feature - return coll.concat(f.features.map(ft => { - return castArray(ft.style || f.style || {}).filter(s => isNil(s.filtering) ? true : s.filtering).map(style => AnnotationsUtils.fromAnnotationToGeoJson({...ft, style})); - }).reduce((p, c) => p.concat(c), [])); - } - return f.geometry && f.geometry.type === "GeometryCollection" ? coll.concat(AnnotationsUtils.flattenGeometryCollection(f)) - : coll.concat({type: "Feature", geometry: f.geometry, properties: {...f.properties, ms_style: annStyleToOlStyle(f.geometry.type, f.style)}}); - }, []); -}; -export const formatCoordinates = (coords = [[]]) => { - return coords.map(c => ({lat: c && c[1], lon: c && c[0]})); -}; -export const getBaseCoord = (type) => { - switch (type) { - case "Polygon": case "LineString": case "MultiPoint": return []; - default: return [[{lat: "", lon: ""}]]; - } -}; -export const getComponents = (geometry) => { - const coordinates = get(geometry, 'coordinates', []); - switch (geometry?.type) { - case "Polygon": { - return AnnotationsUtils.isCompletePolygon(coordinates) ? AnnotationsUtils.formatCoordinates(slice(coordinates[0], 0, coordinates[0].length - 1)) : AnnotationsUtils.formatCoordinates(coordinates[0]); - } - case "LineString": case "MultiPoint": { - return AnnotationsUtils.formatCoordinates(coordinates); - } - default: return AnnotationsUtils.formatCoordinates([coordinates]); - } -}; -export const addIds = (features) => { - return features.map(f => { - if (f.properties && f.properties.id) { - return f; - } - return set("properties.id", uuid.v1(), f); - }); -}; -export const COMPONENTS_VALIDATION = { - "Point": {min: 1, add: false, remove: false, validation: "validateCoordinates", notValid: "Add a valid coordinate to complete the Point"}, - "MultiPoint": {min: 2, add: true, remove: true, validation: "validateCoordinates", notValid: "Add 2 valid coordinates to complete the Polyline"}, - "Polygon": {min: 3, add: true, remove: true, validation: "validateCoordinates", notValid: "Add 3 valid coordinates to complete the Polygon"}, - "LineString": {min: 2, add: true, remove: true, validation: "validateCoordinates", notValid: "Add 2 valid coordinates to complete the Polyline"}, - "Circle": {add: false, remove: false, validation: "validateCircle", notValid: "Add a valid coordinate and a radius (m) to complete the Circle"}, - "Text": {add: false, remove: false, validation: "validateText", notValid: "Add a valid coordinate and a Text value"} -}; -export const validateCoords = ({lat, lon} = {}) => !isNaN(parseFloat(lat)) && !isNaN(parseFloat(lon)); -export const validateCoordsArray = ([lon, lat] = []) => !isNaN(parseFloat(lat)) && !isNaN(parseFloat(lon)); -export const validateCoord = (c) => !isNaN(parseFloat(c)); -export const coordToArray = (c = {}) => [c.lon, c.lat]; -export const validateCoordinates = ({components = [], remove = false, type } = {}) => { - if (components && components.length) { - const validComponents = components.filter(AnnotationsUtils.validateCoords); - if (remove) { - return validComponents.length > AnnotationsUtils.COMPONENTS_VALIDATION[type].min && validComponents.length === components.length; - } - return validComponents.length >= AnnotationsUtils.COMPONENTS_VALIDATION[type].min && validComponents.length === components.length; - } - return false; -}; -export const validateCircle = ({components = [], properties = {radius: 0}} = {}) => { - if (components && components.length) { - const cmp = head(components); - return !isNaN(parseFloat(properties.radius)) && AnnotationsUtils.validateCoords(cmp); - } - return false; -}; -export const validateText = ({components = [], properties = {valueText: ""}} = {}) => { - if (components && components.length) { - const cmp = head(components); - return properties && !!properties.valueText && AnnotationsUtils.validateCoords(cmp); - } - return false; -}; -export const validateFeature = ({components = [[]], type, remove = false, properties = {}} = {}) => { - if (isNil(type)) { - return false; - } - if (type === "Text") { - return AnnotationsUtils.validateText({components, properties}); - } - if (type === "Circle") { - return AnnotationsUtils.validateCircle({components, properties}); - } - return AnnotationsUtils.validateCoordinates({components, remove, type}); -}; -export const updateAllStyles = (ftColl = {}, newStyle = {}) => { - if (ftColl.features && ftColl.features.length) { - return { - ...ftColl, - features: ftColl.features.map(f => assign({}, f, { - style: castArray(f.style).map(s => assign({}, s, newStyle))} - ))}; - } - return ftColl; -}; -export const DEFAULT_SHAPE = "triangle"; -export const DEFAULT_PATH = "product/assets/symbols/"; -export const checkSymbolsError = (symbolErrors, error = "loading_symbols_path") => { - return symbolErrors.length && findIndex(symbolErrors, (s) => s === error) !== -1; -}; -export const isAMissingSymbol = (style) => { - return style.symbolUrlCustomized === require('../product/assets/symbols/symbolMissing.svg'); -}; -/** - * it tells if the filtered list of the coordinates is a geojson polygon, - * with the first point = to the last - * @param {number[[[]]]} coords the coordinates of the polygon - * @return {boolean} true if it is a valid polygon, false otherwise -*/ -export const isCompletePolygon = (coords = [[[]]]) => { - if (coords && coords[0]) { - const validCoords = coords[0].filter(AnnotationsUtils.validateCoordsArray); - return validCoords.length > 3 && head(validCoords)[0] === last(validCoords)[0] && head(validCoords)[1] === last(validCoords)[1]; - } - return false; -}; -/** - * utility to check if the GeoJSON has the annotation model structure i.e. {"type": "ms2-annotations", "features": [list of FeatureCollection]} - * or the imported annotation object's name is of "Annotations" - * @param {object} json GeoJSON/plain object - * @returns {boolean} if the GeoJSON passes is a ms2-annotation or if the name property of the object passed is Annotations - */ -export const isAnnotation = (json) => json?.type === ANNOTATION_TYPE || json?.name === "Annotations"; - -/** - * utility to validate and fix coordinates for selected feature and update corresponding entry in editingFeatures object - * @param selectedFeature - * @param editingFeatures - * @returns {{feature, selected: null}|{feature, selected: ({properties}|*)}} - */ -export const modifySelectedInEdited = (selectedFeature, editingFeatures) => { - if (isNil(selectedFeature)) return { selected: selectedFeature, editing: editingFeatures }; - - const featureTypes = ["LineString", "MultiPoint", "Polygon", "Point"]; - let selected = selectedFeature; - let editing = editingFeatures; - let nullGeometryModifier = false; - switch (selected.geometry.type) { - case "Polygon": { - selected = set("geometry.coordinates", [selected.geometry.coordinates[0].filter(validateCoordsArray)], selected); - break; - } - case "LineString": case "MultiPoint": { - selected = set("geometry.coordinates", selected.geometry.coordinates.filter(validateCoordsArray), selected); - break; - } - // point - default: { - selected = set("geometry.coordinates", [selected.geometry.coordinates].filter(validateCoordsArray)[0] || [], selected); - if (!selected.geometry.coordinates.length) nullGeometryModifier = true; - } - } - - if (selected.properties && selected.properties.isCircle) { - selected = set("geometry", selected.properties.polygonGeom, selected); - } - - let selectedIndex = findIndex(editing.features, (f) => f.properties.id === selected.properties.id); - if (selected.properties.isValidFeature || includes(featureTypes, selected.geometry.type)) { - const tempSelected = nullGeometryModifier ? set('geometry', null, selected) : selected; - if (selectedIndex === -1) { - editing = set(`features`, editing.features.concat([tempSelected]), editing); - } else { - editing = set(`features[${selectedIndex}]`, tempSelected, editing); - } - } - if (selectedIndex !== -1 && !selected.properties.isValidFeature && !includes(featureTypes, selected.geometry.type)) { - editing = set(`features`, editing.features.filter((f, i) => i !== selectedIndex ), editing); - } - - return { selected, editing }; -}; - -AnnotationsUtils = { - ANNOTATION_TYPE, - convertGeoJSONToInternalModel, - getAvailableStyler, - getRelativeStyler, - createFont, - DEFAULT_ANNOTATIONS_STYLES, - STYLE_CIRCLE, - STYLE_POINT_MARKER, - STYLE_POINT_SYMBOL, - STYLE_TEXT, - STYLE_LINE, - STYLE_POLYGON, - getGeometryType, - getGeometryGlyphInfo, - normalizeAnnotation, - removeDuplicate, - circlesToMultiPolygon, - fromCircleToPolygon, - fromTextToPoint, - fromLineStringToGeodesicLineString, - textToPoint, - flattenGeometryCollection, - createGeometryFromGeomFunction, - fromAnnotationToGeoJson, - annotationsToPrint, - formatCoordinates, - getBaseCoord, - getComponents, - addIds, - COMPONENTS_VALIDATION, - validateCoords, - validateCoordsArray, - validateCoord, - coordToArray, - validateCoordinates, - validateCircle, - validateText, - validateFeature, - updateAllStyles, - getStartEndPointsForLinestring, - DEFAULT_SHAPE, - DEFAULT_PATH, - checkSymbolsError, - isAMissingSymbol, - isCompletePolygon, - getDashArrayFromStyle, - isAnnotation, - modifySelectedInEdited -}; - -export default AnnotationsUtils; diff --git a/web/client/utils/SLDUtils.js b/web/client/utils/SLDUtils.js deleted file mode 100644 index 54c0310f96..0000000000 --- a/web/client/utils/SLDUtils.js +++ /dev/null @@ -1,244 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ -import assign from 'object-assign'; - -/* eslint-disable */ -import { XLink_1_0 } from 'w3c-schemas'; - -import { - WMS_1_3_0, - SMIL_2_0_Language, - SMIL_2_0, - GML_2_1_2, - GML_3_1_1, - OWS_1_0_0, - Filter_1_1_0, - Filter_1_0_0, - SE_1_1_0, -} from 'ogc-schemas'; - -import { SLD_1_0_0 } from 'ogc-schemas/lib/SLD_1_0_0_GeoServer'; -// Normalize miss vendorOption definition in SLD_1_0_Geoserver ogc schema -SLD_1_0_0.tis[4].ps= [ { - n: 'vendorOption', - mno: 0, - col: true, - en: 'VendorOption', - ti: '.VendorOption'}]; -import { Jsonix } from 'jsonix'; - -const context = new Jsonix.Context([ - XLink_1_0, - WMS_1_3_0, - OWS_1_0_0, - SMIL_2_0_Language, - SMIL_2_0, - GML_2_1_2, - GML_3_1_1, - Filter_1_1_0, - Filter_1_0_0, - SE_1_1_0, - SLD_1_0_0], - { - namespacePrefixes: { - "http://www.opengis.net/ogc": 'ogc', - "http://www.opengis.net/gml": "gml", - "http://www.opengis.net/sld": "sld" - }, - mappingStyle: 'simplified' -}); -/* eslint-enable */ - -const marshall = context.createMarshaller(); - -const rgbToHex = function({r, g, b}) { - return `#${r < 16 ? 0 : ''}${r.toString(16)}${g < 16 ? 0 : ''}${g.toString(16)}${b < 16 ? 0 : ''}${b.toString(16)}`; -}; - -const convertOpacity = function(opacity) { - return {TYPE_NAME: "SLD_1_0_0.ParameterValueType", content: [opacity]}; -}; -const convertColorMapEntry = function(colorMapEntry) { - return colorMapEntry.map((entry) => { - return assign({TYPE_NAME: "SLD_1_0_0.ColorMapEntry"}, entry); - }); -}; -const convertColorMap = function(type, extended, colorMapEntry) { - - return {TYPE_NAME: "SLD_1_0_0.ColorMap", type: type, extended: extended, colorMapEntry: convertColorMapEntry(colorMapEntry)}; -}; -const convertChannel = function(channel) { - return {TYPE_NAME: "SLD_1_0_0.SelectedChannelType", - sourceChannelName: channel}; -}; -const convertVendorOption = function(name, value) { - - return {TYPE_NAME: "SLD_1_0_0.VendorOption", name: name, value: "" + value}; -}; -const convertAlgorithm = function(bandConfig) { - return [ - convertVendorOption("algorithm", bandConfig.algorithm), - convertVendorOption("minValue", bandConfig.min), - convertVendorOption("maxValue", bandConfig.max) - ]; -}; -const convertContrast = function(bandConfig) { - let c = {TYPE_NAME: "SLD_1_0_0.ContrastEnhancement"}; - switch (bandConfig.contrast) { - case 'Normalize': { - c.normalize = {TYPE_NAME: "SLD_1_0_0.Normalize"}; - if (bandConfig.algorithm !== 'none') { - c.normalize.vendorOption = convertAlgorithm(bandConfig); - } - break; - } - case 'Histogram': { - c.histogram = {TYPE_NAME: "SLD_1_0_0.Histogram"}; - break; - } - case 'GammaValue': { - c.gammaValue = bandConfig.gammaValue; - break; - } - default: { - break; - } - } - return c; -}; -const convertOneBandChannel = function(bandConfig, channelType) { - let cs = {TYPE_NAME: "SLD_1_0_0.ChannelSelection"}; - let channel = convertChannel(bandConfig.band); - if (bandConfig.contrast !== 'none') { - channel.contrastEnhancement = convertContrast(bandConfig); - } - cs[channelType] = channel; - return cs; -}; -const convertRGBBandChannel = function(redBand, greenBand, blueBand) { - let red = convertOneBandChannel(redBand, "redChannel"); - let green = convertOneBandChannel(greenBand, "greenChannel"); - let blue = convertOneBandChannel(blueBand, "blueChannel"); - assign(red, green, blue); - return red; -}; - -const getSLDObjc = function(layer, rasterSymbolizer) { - return { - "sld:StyledLayerDescriptor": {"TYPE_NAME": "SLD_1_0_0.StyledLayerDescriptor", "version": "1.0.0", - "namedLayerOrUserLayer": [{"TYPE_NAME": "SLD_1_0_0.NamedLayer", "name": layer.name, - "namedStyleOrUserStyle": [{"TYPE_NAME": "SLD_1_0_0.UserStyle", - "featureTypeStyle": [{"TYPE_NAME": "SLD_1_0_0.FeatureTypeStyle", - "rule": [{"TYPE_NAME": "SLD_1_0_0.Rule", "symbolizer": [{"sld:RasterSymbolizer": rasterSymbolizer}]}]}]}]}]}}; - -}; -export const jsonToSLD = function({styletype, opacity = "1.0", state, layer} = {}) { - - let rasterSymbolizer = {TYPE_NAME: "SLD_1_0_0.RasterSymbolizer"}; - rasterSymbolizer.opacity = convertOpacity(opacity); - switch (styletype) { - case 'pseudo': { - rasterSymbolizer.colorMap = convertColorMap(state.pseudocolor.type, state.pseudocolor.extended, state.pseudocolor.colorMapEntry); - if (state.pseudoband.band !== 'none') { - rasterSymbolizer.channelSelection = convertOneBandChannel(state.pseudoband, "grayChannel"); - } - break; - } - case 'gray': { - rasterSymbolizer.channelSelection = convertOneBandChannel(state.grayband, "grayChannel"); - break; - } - case 'rgb': { - rasterSymbolizer.channelSelection = convertRGBBandChannel(state.redband, state.greenband, state.blueband); - break; - } - default: { - break; - } - } - return marshall.marshalString(getSLDObjc(layer, rasterSymbolizer)); -}; -const getStroke = function({a = 1, r = 0, g = 0, b = 255, width = 1} = {}) { - return {cssParameter: [ - {"TYPE_NAME": "SLD_1_0_0.CssParameter", content: [rgbToHex({r, g, b})], name: "stroke"}, - {"TYPE_NAME": "SLD_1_0_0.CssParameter", content: [`${a}`], name: "stroke-opacity"}, - {"TYPE_NAME": "SLD_1_0_0.CssParameter", content: [`${width}`], name: "stroke-width"} - - ] - }; -}; -const getFill = function({a = 1, r = 0, g = 0, b = 255} = {}) { - return {cssParameter: [ - {"TYPE_NAME": "SLD_1_0_0.CssParameter", content: [rgbToHex({r, g, b})], name: "fill"}, - {"TYPE_NAME": "SLD_1_0_0.CssParameter", content: [`${a}`], name: "fill-opacity"} - ] - }; - -}; -const getSize = function(size) { - return {"TYPE_NAME": "SLD_1_0_0.ParameterValueType", content: [`${size}`]}; -}; -const getWellKnownName = function(markName) { - return {"TYPE_NAME": "SLD_1_0_0.WellKnownName", content: [markName]}; -}; -const getMark = function(symbolyzer) { - return {"TYPE_NAME": "SLD_1_0_0.Mark", fill: getFill(symbolyzer.fill), stroke: getStroke({...symbolyzer.color, width: symbolyzer.width}), wellKnownName: getWellKnownName(symbolyzer.markName)}; -}; -const getGraphic = function(symbolyzer) { - return {"TYPE_NAME": "SLD_1_0_0.Graphic", externalGraphicOrMark: [getMark(symbolyzer)], size: getSize(symbolyzer.radius)}; -}; -const getPolygonSymbolyzer = function(symbolyzer) { - return {"TYPE_NAME": "SLD_1_0_0.PolygonSymbolizer", fill: getFill(symbolyzer.fill), stroke: getStroke({...symbolyzer.color, width: symbolyzer.width})}; -}; -const getLineSymbolyzer = function(symbolyzer) { - return {"TYPE_NAME": "SLD_1_0_0.LineSymbolizer", stroke: getStroke({...symbolyzer.color, width: symbolyzer.width})}; -}; -const getPointSymbolyzer = function(symbolyzer) { - return {"TYPE_NAME": "SLD_1_0_0.PointSymbolizer", graphic: getGraphic(symbolyzer)}; -}; - -const getSymbolyzer = function(symbolyzer) { - switch (symbolyzer.type) { - case "Point": - return {"PointSymbolizer": getPointSymbolyzer(symbolyzer)}; - case "Line": - return {"LineSymbolizer": getLineSymbolyzer(symbolyzer)}; - case "Polygon": - return {"PolygonSymbolizer": getPolygonSymbolyzer(symbolyzer)}; - default: - return getPolygonSymbolyzer(symbolyzer); - } -}; - -const getRules = function(rules) { - return rules.map((rule) => { - let den = {}; - if (rule.maxDenominator) { - den.maxScaleDenominator = rule.maxDenominator; - } - if (rule.minDenominator) { - den.minScaleDenominator = rule.minDenominator; - } - return { - "TYPE_NAME": "SLD_1_0_0.Rule", - "symbolizer": [getSymbolyzer(rule.symbol)], - ...den - }; - } - ); -}; - -export const vecStyleToSLD = function({rules = [], layer = {}} = {}) { - return marshall.marshalString({ - "sld:StyledLayerDescriptor": {"TYPE_NAME": "SLD_1_0_0.StyledLayerDescriptor", "version": "1.0.0", - "namedLayerOrUserLayer": [{"TYPE_NAME": "SLD_1_0_0.NamedLayer", "name": layer.name, - "namedStyleOrUserStyle": [{"TYPE_NAME": "SLD_1_0_0.UserStyle", - "featureTypeStyle": [{"TYPE_NAME": "SLD_1_0_0.FeatureTypeStyle", - "rule": getRules(rules)}]}]}]}} - ); -}; diff --git a/web/client/utils/__tests__/LegacyAnnotationsUtils-test.js b/web/client/utils/__tests__/LegacyAnnotationsUtils-test.js deleted file mode 100644 index ab2ffc6c0e..0000000000 --- a/web/client/utils/__tests__/LegacyAnnotationsUtils-test.js +++ /dev/null @@ -1,1010 +0,0 @@ -/* - * Copyright 2018, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. -*/ -import expect from 'expect'; - -import feature from '../../test-resources/Annotation_geomColl.json'; -import MarkerUtils from '../MarkerUtils'; - - -import { - getAvailableStyler, - getRelativeStyler, - convertGeoJSONToInternalModel, - DEFAULT_ANNOTATIONS_STYLES, - createFont, - circlesToMultiPolygon, - textToPoint, - flattenGeometryCollection, - normalizeAnnotation, - removeDuplicate, - formatCoordinates, - getComponents, - addIds, - validateCoords, - validateCoordsArray, - validateCoord, - getBaseCoord, - validateText, - validateCircle, - validateCoordinates, - coordToArray, - validateFeature, - fromTextToPoint, - fromCircleToPolygon, - fromAnnotationToGeoJson, - annotationsToPrint, - getStartEndPointsForLinestring, - createGeometryFromGeomFunction, - updateAllStyles, - fromLineStringToGeodesicLineString, - isCompletePolygon, - getDashArrayFromStyle, - getGeometryType, - getGeometryGlyphInfo, - modifySelectedInEdited -} from '../LegacyAnnotationsUtils'; - -const featureCollection = { - features: [{ - type: "Feature", - geometry: { - type: "Point", - coordinates: [1, 1] - }, - properties: { - id: 1 - } - }, - { - type: "Feature", - geometry: { - type: "LineString", - coordinates: [[1, 1], [2, 2]] - }, - properties: { - id: 2 - } - }, - { - type: "Feature", - geometry: { - type: "Polygon", - coordinates: [ - [ - [1, 45], - [2, 45], - [2, 44], - [1, 44], - [1, 45] - ] - ] - }, - properties: { - id: 3 - } - } - ], - type: "FeatureCollection" -}; -const circle1 = { - type: "Feature", - geometry: { - type: "Polygon", - coordinates: [[[1, 1], [2, 2], [3, 3], [1, 1]]] - }, - properties: { - isCircle: true, - radius: 200, - id: "circle1" - } -}; -const circle2 = { - type: "Feature", - geometry: { - type: "Point", - coordinates: [1, 1] - }, - properties: { - polygonGeom: { - type: "Polygon", - coordinates: [[[1, 1], [2, 2], [3, 3], [1, 1]]] - }, - isCircle: true, - radius: 200, - id: "circle1" - } -}; -const textFeature = { - geometry: { - type: "Point", - coordinates: [1, 2] - }, - type: "Feature", - properties: {isText: true, valueText: "pino"} -}; -const geodesicLineString = { - geometry: { - type: "LineString", - coordinates: [[1, 2], [2, 2]] - }, - type: "Feature", - properties: { - useGeodesicLines: true, - id: "geodesic.line", - geometryGeodesic: { - type: "LineString", - coordinates: [[]] - } - } -}; - -describe('Test the AnnotationsUtils', () => { - let old = MarkerUtils.extraMarkers.images[1]; - beforeEach((done) => { - // prevent issues with lazy load in karma by faking image and preloading - MarkerUtils.extraMarkers.images[1] = new Image(); - MarkerUtils.extraMarkers.images[1].onload = () => { - done(); - }; - MarkerUtils.extraMarkers.images[1].src = MarkerUtils.extraMarkers.images[0].src; - }); - afterEach(() => { - MarkerUtils.extraMarkers.images[1] = old; - }); - it('getAvailableStyler for point or MultiPoint', () => { - let stylers = getAvailableStyler({type: "Point"}); - expect(stylers.length).toBe(1); - expect(stylers[0]).toBe("marker"); - - stylers = getAvailableStyler({type: "MultiPoint"}); - expect(stylers.length).toBe(1); - expect(stylers[0]).toBe("marker"); - }); - it('getAvailableStyler for LineString or MultiLineString', () => { - let stylers = getAvailableStyler({type: "LineString"}); - expect(stylers.length).toBe(1); - expect(stylers[0]).toBe("lineString"); - - stylers = getAvailableStyler({type: "MultiLineString"}); - expect(stylers.length).toBe(1); - expect(stylers[0]).toBe("lineString"); - }); - it('getAvailableStyler for Polygon or MultiPolygon', () => { - let stylers = getAvailableStyler({type: "Polygon"}); - expect(stylers.length).toBe(1); - expect(stylers[0]).toBe("polygon"); - - stylers = getAvailableStyler({type: "MultiPolygon"}); - expect(stylers.length).toBe(1); - expect(stylers[0]).toBe("polygon"); - }); - it('getAvailableStyler for GeometryCollection', () => { - let stylers = getAvailableStyler({type: "GeometryCollection", geometries: - [{type: "MultiPolygon"}, {type: "MultiPoint"}]}); - expect(stylers.length).toBe(2); - expect(stylers[0]).toBe("polygon"); - expect(stylers[1]).toBe("marker"); - - stylers = getAvailableStyler({type: "GeometryCollection", geometries: - [{type: "MultiLineString"}, {type: "MultiPoint"}, {type: "MultiPolygon"}]}); - expect(stylers.length).toBe(3); - expect(stylers[0]).toBe("lineString"); - expect(stylers[1]).toBe("marker"); - expect(stylers[2]).toBe("polygon"); - }); - it('getRelativeStyler for simple Geoms and Text', () => { - let styler = getRelativeStyler("Polygon"); - expect(styler).toBe("polygon"); - styler = getRelativeStyler("MultiPolygon"); - expect(styler).toBe("polygon"); - - styler = getRelativeStyler("MultiPoint"); - expect(styler).toBe("marker"); - styler = getRelativeStyler("Point"); - expect(styler).toBe("marker"); - - styler = getRelativeStyler("MultiLineString"); - expect(styler).toBe("lineString"); - styler = getRelativeStyler("LineString"); - expect(styler).toBe("lineString"); - - styler = getRelativeStyler("Text"); - expect(styler).toBe("text"); - }); - it('default styles text', () => { - const numStyles = Object.keys(DEFAULT_ANNOTATIONS_STYLES); - expect(numStyles.length).toBe(8); - - const textParams = Object.keys(DEFAULT_ANNOTATIONS_STYLES.Text); - expect(textParams.length).toBe(11); - - const {font, color, opacity, fontStyle, fontSize, fontSizeUom, textAlign, fontFamily, fontWeight, fillColor, fillOpacity} = DEFAULT_ANNOTATIONS_STYLES.Text; - expect(font).toBe("14px Arial"); - expect(fontStyle).toBe("normal"); - expect(fontWeight).toBe("normal"); - expect(fontSize).toBe("14"); - expect(fontFamily).toBe("Arial"); - expect(fontSizeUom).toBe("px"); - expect(textAlign).toBe("center"); - - expect(color).toBe("#000000"); - expect(opacity).toBe(1); - expect(fillColor).toBe("#000000"); - expect(fillOpacity).toBe(1); - }); - it('default styles Point', () => { - let {iconGlyph, iconShape, iconColor} = DEFAULT_ANNOTATIONS_STYLES.Point; - expect(iconGlyph).toBe("comment"); - expect(iconShape).toBe("square"); - expect(iconColor).toBe("blue"); - }); - it('default styles MultiPoint', () => { - let {iconGlyph, iconShape, iconColor} = DEFAULT_ANNOTATIONS_STYLES.MultiPoint; - expect(iconGlyph).toBe("comment"); - expect(iconShape).toBe("square"); - expect(iconColor).toBe("blue"); - }); - it('default styles LineString', () => { - let {color, opacity, weight} = DEFAULT_ANNOTATIONS_STYLES.LineString; - expect(color).toBe("#ffcc33"); - expect(opacity).toBe(1); - expect(weight).toBe(3); - }); - it('default styles Circle', () => { - let {color, opacity, weight, fillColor, fillOpacity} = DEFAULT_ANNOTATIONS_STYLES.Circle; - expect(color).toBe("#ffcc33"); - expect(opacity).toBe(1); - expect(weight).toBe(3); - expect(fillColor).toBe("#ffffff"); - expect(fillOpacity).toBe(0.2); - }); - it('default styles MultiLineString', () => { - let {color, opacity, weight} = DEFAULT_ANNOTATIONS_STYLES.MultiLineString; - expect(color).toBe("#ffcc33"); - expect(opacity).toBe(1); - expect(weight).toBe(3); - }); - it('default styles Polygon', () => { - let {color, opacity, weight, fillColor, fillOpacity} = DEFAULT_ANNOTATIONS_STYLES.Polygon; - expect(color).toBe("#ffcc33"); - expect(opacity).toBe(1); - expect(weight).toBe(3); - expect(fillColor).toBe("#ffffff"); - expect(fillOpacity).toBe(0.2); - }); - it('default styles MultiPolygon', () => { - let {color, opacity, weight, fillColor, fillOpacity} = DEFAULT_ANNOTATIONS_STYLES.MultiPolygon; - expect(color).toBe("#ffcc33"); - expect(opacity).toBe(1); - expect(weight).toBe(3); - expect(fillColor).toBe("#ffffff"); - expect(fillOpacity).toBe(0.2); - }); - it('convertGeoJSONToInternalModel simple geoms', () => { - let newGeom = convertGeoJSONToInternalModel({type: "MultiPoint"}, []); - expect(newGeom.type).toBe("MultiPoint"); - newGeom = convertGeoJSONToInternalModel({type: "MultiPoint"}, ["someval"]); - expect(newGeom.type).toBe("Text"); - newGeom = convertGeoJSONToInternalModel({type: "MultiLineString"}, []); - expect(newGeom.type).toBe("MultiLineString"); - newGeom = convertGeoJSONToInternalModel({type: "LineString"}, []); - expect(newGeom.type).toBe("LineString"); - newGeom = convertGeoJSONToInternalModel({type: "MultiPolygon"}, []); - expect(newGeom.type).toBe("MultiPolygon"); - newGeom = convertGeoJSONToInternalModel({type: "Polygon"}, []); - expect(newGeom.type).toBe("Polygon"); - }); - it('convertGeoJSONToInternalModel multi geoms', () => { - let geometries = [{type: "MultiPolygon"}, {type: "MultiPoint"}]; - let newGeom = convertGeoJSONToInternalModel({type: "GeometryCollection", geometries}, []); - newGeom.geometries.forEach((g, i) => { - expect(g.type).toBe(geometries[i].type); - }); - geometries = [{type: "MultiPolygon"}, {type: "MultiPoint"}]; - - let convertedGeometries = [{type: "MultiPolygon"}, {type: "Text"}]; - newGeom = convertGeoJSONToInternalModel({type: "GeometryCollection", geometries}, ["some va"]); - newGeom.geometries.forEach((g, i) => { - expect(g.type).toBe(convertedGeometries[i].type); - }); - geometries = [{type: "MultiPoint"}, {type: "MultiPoint"}]; - convertedGeometries = [{type: "Text"}, {type: "MultiPoint"}]; - newGeom = convertGeoJSONToInternalModel({type: "GeometryCollection", geometries}, ["some va"]); - newGeom.geometries.forEach((g, i) => { - expect(g.type).toBe(convertedGeometries[i].type); - }); - geometries = [{type: "Polygon"}, {type: "MultiPoint"}]; - convertedGeometries = [{type: "Circle"}, {type: "MultiPoint"}]; - newGeom = convertGeoJSONToInternalModel({type: "GeometryCollection", geometries}, [], ["some va"]); - newGeom.geometries.forEach((g, i) => { - expect(g.type).toBe(convertedGeometries[i].type); - }); - geometries = [{type: "MultiPoint"}, {type: "MultiLineString"}, {type: "MultiPoint"}]; - convertedGeometries = [{type: "Text"}, {type: "MultiLineString"}, {type: "MultiPoint"}]; - newGeom = convertGeoJSONToInternalModel({type: "GeometryCollection", geometries}, ["some va"]); - newGeom.geometries.forEach((g, i) => { - expect(g.type).toBe(convertedGeometries[i].type); - }); - }); - it('create font with values', () => { - // with defaults - expect(createFont({})).toBe("normal normal 14px Arial"); - // with values - expect(createFont({fontFamily: "Courier"})).toBe("normal normal 14px Courier"); - expect(createFont({fontSize: "30"})).toBe("normal normal 30px Arial"); - expect(createFont({fontSizeUom: "em"})).toBe("normal normal 14em Arial"); - expect(createFont({fontStyle: "italic"})).toBe("italic normal 14px Arial"); - expect(createFont({fontWeight: "bold"})).toBe("normal bold 14px Arial"); - }); - it('circlesToMultiPolygon', () => { - const {geometry, properties, style} = feature; - const f = circlesToMultiPolygon(geometry, properties, style.Circle); - expect(f).toExist(); - expect(f.type).toBe("Feature"); - expect(f.geometry.type).toBe("MultiPolygon"); - expect(f.properties).toExist(); - expect(f.properties.ms_style).toExist(); - expect(f.properties.ms_style.strokeColor).toBe(style.Circle.color); - }); - it('fromCircleToPolygon', () => { - const {geometry, properties} = circle1; - const {style} = feature; - const ft = fromCircleToPolygon(geometry, properties, style.Circle); - expect(ft).toExist(); - expect(ft.type).toBe("Feature"); - expect(ft.geometry.type).toBe("Polygon"); - expect(ft.properties).toExist(); - expect(ft.properties.ms_style).toExist(); - expect(ft.properties.isCircle).toBe(undefined); - const {geometry: geometry2, properties: properties2} = circle2; - - const ft2 = fromCircleToPolygon(geometry2, properties2, style.Circle); - expect(ft2.geometry.type).toBe("Polygon"); - expect(ft2.properties.isCircle).toBe(undefined); - }); - it('textToPoint', () => { - const {geometry, properties, style} = feature; - const fts = textToPoint(geometry, properties, style.Text); - expect(fts).toExist(); - expect(fts.length).toBe(2); - expect(fts[0].type).toBe("Feature"); - expect(fts[0].geometry.type).toBe("MultiPoint"); - expect(fts[0].properties).toExist(); - expect(fts[0].properties.ms_style).toExist(); - expect(fts[0].properties.ms_style.label).toBe("pino"); - - }); - it('fromTextToPoint', () => { - const {geometry, properties} = textFeature; - const {style} = feature; - const ft = fromTextToPoint(geometry, properties, style.Text); - expect(ft).toExist(); - expect(ft.type).toBe("Feature"); - expect(ft.geometry.type).toBe("Point"); - expect(ft.properties).toExist(); - expect(ft.properties.ms_style).toExist(); - expect(ft.properties.ms_style.label).toBe("pino"); - - }); - it('fromAnnotationToGeoJson with a circle', () => { - const ft = fromAnnotationToGeoJson(circle1); - expect(ft.type).toBe("Feature"); - expect(ft.geometry.type).toBe("Polygon"); - expect(ft.properties).toExist(); - expect(ft.properties.ms_style).toExist(); - expect(ft.properties.isCircle).toBe(undefined); - }); - it('fromAnnotationToGeoJson with a geodesic LineString', () => { - const ft = fromAnnotationToGeoJson(geodesicLineString); - expect(ft.type).toBe("Feature"); - expect(ft.geometry.type).toBe("LineString"); - expect(ft.properties).toExist(); - expect(ft.properties.ms_style).toExist(); - expect(ft.properties.geometryGeodesic).toBe(undefined); - }); - it('fromAnnotationToGeoJson with a text', () => { - const ft = fromAnnotationToGeoJson(textFeature); - expect(ft.type).toBe("Feature"); - expect(ft.geometry.type).toBe("Point"); - expect(ft.properties).toExist(); - expect(ft.properties.ms_style).toExist(); - expect(ft.properties.isText).toBe(undefined); - }); - it('fromAnnotationToGeoJson with a point', () => { - const ft = fromAnnotationToGeoJson(featureCollection.features[0]); - expect(ft.type).toBe("Feature"); - expect(ft.geometry.type).toBe("Point"); - expect(ft.properties).toExist(); - expect(ft.properties.ms_style).toExist(); - }); - it('fromAnnotationToGeoJson with a LineString in origin, but with a style of a startPoint', () => { - const f = { - type: "Feature", - geometry: { - type: "LineString", - coordinates: [[0, 0], [1, 1], [3, 3], [5, 5]] - }, - style: getStartEndPointsForLinestring()[0] - }; - const ft = fromAnnotationToGeoJson(f); - expect(ft.type).toBe("Feature"); - expect(ft.geometry.type).toBe("Point"); - expect(ft.geometry.coordinates[0]).toBe(0); - expect(ft.geometry.coordinates[1]).toBe(0); - expect(ft.properties).toExist(); - expect(ft.properties.ms_style).toExist(); - }); - it('fromAnnotationToGeoJson with a LineString with dashArray', () => { - const f = { - type: "Feature", - geometry: { - type: "LineString", - coordinates: [[0, 0], [1, 1], [3, 3], [5, 5]] - }, - style: { - dashArray: [1, 3] - } - }; - const ft = fromAnnotationToGeoJson(f); - expect(ft.type).toBe("Feature"); - expect(ft.properties).toExist(); - expect(ft.properties.ms_style).toExist(); - expect(ft.properties.ms_style.strokeDashstyle).toEqual("1 3"); - }); - it('flattenGeometryCollection', () => { - const fts = flattenGeometryCollection(feature); - expect(fts).toExist(); - expect(fts.length).toBe(9); - expect(fts[6].type).toBe("Feature"); - expect(fts[6].geometry.type).toBe("MultiPolygon"); - expect(fts[6].properties.ms_style).toExist(); - expect(fts[6].properties.ms_style.strokeColor).toBe(feature.style.Circle.color); - expect(fts[6].properties).toExist(); - expect(fts[7].type).toBe("Feature"); - expect(fts[7].geometry.type).toBe("MultiPoint"); - expect(fts[7].properties.ms_style).toExist(); - expect(fts[7].properties.ms_style.label).toBe("pino"); - expect(fts[7].properties).toExist(); - }); - - it('test normalizeAnnotation defaults', () => { - let annotation = normalizeAnnotation(); - expect(annotation.geometry.coordinates).toBe(undefined); - expect(annotation.geometry.type).toBe(undefined); - expect(annotation.properties.title).toBe("Default title"); - }); - it('test normalizeAnnotation with Annotation', () => { - let annotation = normalizeAnnotation(featureCollection); - expect(annotation.type).toBe("FeatureCollection"); - expect(annotation.features[0].geometry.type).toBe("Point"); - expect(annotation.features[1].geometry.type).toBe("LineString"); - - }); - it('test removeDuplicate', () => { - const annotations = [{properties: {id: "id1"}}, {properties: {id: "id2"}}, {properties: {id: "id2"}}]; - expect(removeDuplicate(annotations).length).toBe(2); - }); - it('test formatCoordinates defaults and with data', () => { - expect(formatCoordinates().length).toBe(1); - expect(formatCoordinates()[0].lon).toBe(undefined); - expect(formatCoordinates()[0].lat).toBe(undefined); - - const coords = [[1, 2], [3, 4]]; - expect(formatCoordinates(coords).length).toBe(2); - expect(formatCoordinates(coords)[0].lon).toBe(1); - expect(formatCoordinates(coords)[0].lat).toBe(2); - - const coords2 = [[1, undefined]]; - expect(formatCoordinates(coords2).length).toBe(1); - expect(formatCoordinates(coords2)[0].lon).toBe(1); - expect(formatCoordinates(coords2)[0].lat).toBe(undefined); - }); - - it('test getComponents defaults', () => { - const polygonCoords3 = [[[1, 1], [2, 2], [3, 3], [1, 1]]]; - - let polygonGeom = { - type: "Polygon", - coordinates: polygonCoords3 - }; - expect(getComponents(polygonGeom).length).toBe(3); - - const polygonCoords2 = [[[1, 1], [2, undefined], [3, 3]]]; - let polygonGeom2 = { - type: "Polygon", - coordinates: polygonCoords2 - }; - expect(getComponents(polygonGeom2).length).toBe(3); - - let lineString = { - type: "LineString", - coordinates: polygonCoords2[0] - }; - expect(getComponents(lineString).length).toBe(3); - - let point = { - type: "Point", - coordinates: polygonCoords2[0][0] - }; - expect(getComponents(point).length).toBe(1); - expect(getComponents(point)[0].lon).toBe(1); - expect(getComponents(point)[0].lat).toBe(1); - expect(getComponents(null)[0].lat).toBe(undefined); - expect(getComponents(null)[0].lon).toBe(undefined); - }); - it('test addIds defaults', () => { - const features = [{properties: {id: "some id"}}, {properties: {}}]; - expect(addIds(features).length).toBe(2); - expect(addIds(features).map(f => f.properties.id)[0]).toBe("some id"); - }); - it('test validateCoords ', () => { - expect(validateCoords({lat: undefined, lon: 2})).toBe(false); - expect(validateCoords({lat: 4, lon: 2})).toBe(true); - }); - it('test validateCoordsArray', () => { - expect(validateCoordsArray([undefined, 2])).toBe(false); - expect(validateCoordsArray([4, 2])).toBe(true); - }); - it('test validateCoord', () => { - expect(validateCoord(undefined)).toBe(false); - expect(validateCoord(2)).toBe(true); - }); - it('test coordToArray', () => { - expect(coordToArray()[0]).toBe(undefined); - expect(coordToArray()[1]).toBe(undefined); - expect(coordToArray({lon: 2})[0]).toBe(2); - expect(coordToArray({lon: 2})[1]).toBe(undefined); - expect(coordToArray({lon: 2, lat: 1})[0]).toBe(2); - expect(coordToArray({lon: 2, lat: 1})[1]).toBe(1); - }); - it('test getBaseCoord', () => { - expect(getBaseCoord().length).toBe(1); - expect(getBaseCoord()[0].length).toBe(1); - expect(getBaseCoord("Polygon").length).toBe(0); - expect(getBaseCoord("LineString").length).toBe(0); - expect(getBaseCoord("MultiPoint").length).toBe(0); - }); - it('test validateText defaults', () => { - let components = [{lat: 4, lon: 4}]; - let textAnnot = { - components, - properties: { - valueText: "valid" - } - }; - expect(validateText(textAnnot)).toBe(true); - - textAnnot.properties.valueText = ""; - expect(validateText(textAnnot)).toBe(false); - - textAnnot.properties.valueText = "asdgf"; - textAnnot.components = [undefined, 4]; - expect(validateText(textAnnot)).toBe(false); - - textAnnot.components = [undefined, 4]; - expect(validateText(textAnnot)).toBe(false); - }); - it('test validateCircle defaults', () => { - let components = [{lat: 4, lon: 4}]; - let textAnnot = { - components, - properties: { - radius: 5 - } - }; - expect(validateCircle({})).toBe(false); - expect(validateCircle(textAnnot)).toBe(true); - - textAnnot.properties.radius = ""; - expect(validateCircle(textAnnot)).toBe(false); - - textAnnot.properties.radius = 50; - textAnnot.components = [undefined, 4]; - expect(validateCircle(textAnnot)).toBe(false); - - textAnnot.components = [undefined, 4]; - expect(validateCircle(textAnnot)).toBe(false); - }); - it('test getGeometryType', ()=>{ - let geomFeature = {}; - expect(getGeometryType(geomFeature)).toBeFalsy(); - - geomFeature = {...geomFeature, properties: {isCircle: true}}; - expect(getGeometryType(geomFeature)).toBe('Circle'); - - geomFeature = {properties: {isText: true}}; - expect(getGeometryType(geomFeature)).toBe('Text'); - - geomFeature = {geometry: {type: "Polygon"}}; - expect(getGeometryType(geomFeature)).toBe('Polygon'); - }); - it('test getGeometryGlyphInfo', ()=>{ - let point = ''; - expect(getGeometryGlyphInfo().glyph).toBe('point'); - - point = 'LineString'; - expect(getGeometryGlyphInfo(point).glyph).toBe('polyline'); - - point = 'Text'; - expect(getGeometryGlyphInfo(point).glyph).toBe('font'); - - point = 'Circle'; - expect(getGeometryGlyphInfo(point).glyph).toBe('1-circle'); - }); - it('test validateCoordinates defaults', () => { - let components = [{lat: 4, lon: 4}]; - let textAnnot = { - components, - type: "Point" - }; - expect(validateCoordinates({})).toBe(false); - expect(validateCoordinates(textAnnot)).toBe(true); - textAnnot.components = [[undefined, 4]]; - expect(validateCoordinates(textAnnot)).toBe(false); - textAnnot.components = [{lat: 4, lon: 4}]; - expect(validateCoordinates(textAnnot)).toBe(true); - textAnnot.components = [[undefined, 4]]; - expect(validateCoordinates(textAnnot)).toBe(false); - }); - it('test validateFeature defaults', () => { - let components = [{lat: 4, lon: 4}]; - let textAnnot = { - components, - type: "Point" - }; - expect(validateFeature({})).toBe(false); - expect(validateFeature(textAnnot)).toBe(true); - }); - it('test annotationsToPrint from featureCollection', () => { - let fts = annotationsToPrint([featureCollection]); - expect(fts).toExist(); - expect(fts.length).toBe(3); - expect(fts[0].geometry.type).toBe("Point"); - expect(fts[1].geometry.type).toBe("LineString"); - expect(fts[2].geometry.type).toBe("Polygon"); - }); - it('test annotationsToPrint from array of geometryCollection', () => { - let fts = annotationsToPrint([feature]); - expect(fts).toExist(); - expect(fts.length).toBe(9); - expect(fts[0].geometry.type).toBe("MultiPolygon"); - expect(fts[1].geometry.type).toBe("MultiLineString"); - expect(fts[2].geometry.type).toBe("MultiPoint"); - expect(fts[3].geometry.type).toBe("MultiPoint"); - expect(fts[4].geometry.type).toBe("MultiPoint"); - expect(fts[5].geometry.type).toBe("MultiPoint"); - expect(fts[6].geometry.type).toBe("MultiPolygon"); - expect(fts[7].geometry.type).toBe("MultiPoint"); - expect(fts[8].geometry.type).toBe("MultiPoint"); - }); - it('test annotationsToPrint from a lineString', () => { - const f = { - type: "FeatureCollection", - features: [{ - type: "Feature", - geometry: { - type: "LineString", - coordinates: [[0, 0], [1, 1], [3, 3], [5, 5]] - }, - style: [{ - color: "#FF0000" - }].concat(getStartEndPointsForLinestring()) - }] - }; - let fts = annotationsToPrint([f]); - expect(fts).toExist(); - expect(fts.length).toBe(1); // filter the style not applied - }); - it('getStartEndPointsForLinestring, defaults', () => { - const styles = getStartEndPointsForLinestring(); - expect(styles.length).toBe(2); - expect(styles[0].iconShape).toBe("square"); - expect(styles[0].iconGlyph).toBe("comment"); - expect(styles[0].iconColor).toBe("blue"); - expect(typeof styles[0].id).toBe("string"); - expect(styles[0].geometry).toBe("startPoint"); - expect(styles[0].filtering).toBe(false); - expect(styles[0].highlight).toBe(true); - expect(styles[0].iconAnchor.length).toBe(2); - expect(styles[0].iconAnchor[0]).toBe(0.5); - expect(styles[0].iconAnchor[1]).toBe(0.5); - expect(styles[0].type).toBe("Point"); - expect(styles[0].title).toBe("StartPoint Style"); - - expect(styles[1].iconShape).toBe("square"); - expect(styles[1].iconGlyph).toBe("comment"); - expect(styles[1].iconColor).toBe("blue"); - expect(typeof styles[1].id).toBe("string"); - expect(styles[1].geometry).toBe("endPoint"); - expect(styles[1].filtering).toBe(false); - expect(styles[1].highlight).toBe(true); - expect(styles[1].iconAnchor.length).toBe(2); - expect(styles[1].iconAnchor[0]).toBe(0.5); - expect(styles[1].iconAnchor[1]).toBe(0.5); - expect(styles[1].type).toBe("Point"); - expect(styles[1].title).toBe("EndPoint Style"); - }); - it('createGeometryFromGeomFunction startPoint', () => { - // feature with start point style but with a linestring ad geom - const f = { - type: "Feature", - geometry: { - type: "LineString", - coordinates: [[0, 0], [1, 1], [3, 3], [5, 5]] - }, - style: getStartEndPointsForLinestring()[0] - }; - const newGeom = createGeometryFromGeomFunction(f); - expect(newGeom.type).toBe("Point"); - expect(newGeom.coordinates[0]).toBe(0); - expect(newGeom.coordinates[0]).toBe(0); - }); - it('createGeometryFromGeomFunction startPoint', () => { - // feature with end point style but with a linestring ad geom - const f = { - type: "Feature", - geometry: { - type: "LineString", - coordinates: [[0, 0], [1, 1], [3, 3], [5, 5]] - }, - style: getStartEndPointsForLinestring()[1] - }; - const newGeom = createGeometryFromGeomFunction(f); - expect(newGeom.type).toBe("Point"); - expect(newGeom.coordinates[0]).toBe(5); - expect(newGeom.coordinates[0]).toBe(5); - }); - it('createGeometryFromGeomFunction centerPoint', () => { - // feature with end point style but with a linestring ad geom - const f = { - type: "Feature", - geometry: { - type: "LineString", - coordinates: [[0, 0], [5, 5]] - }, - style: {...getStartEndPointsForLinestring()[1], geometry: "centerPoint"} - }; - const newGeom = createGeometryFromGeomFunction(f); - expect(newGeom.type).toBe("Point"); - expect(newGeom.coordinates[0]).toBe(2.5); - expect(newGeom.coordinates[0]).toBe(2.5); - }); - it('createGeometryFromGeomFunction lineString', () => { - // feature with end point style but with a linestring ad geom - const f = { - type: "Feature", - geometry: { - type: "LineString", - coordinates: [[0, 0], [1, 1], [3, 3], [5, 5]] - }, - style: { - color: "#FF0000" - } - }; - const newGeom = createGeometryFromGeomFunction(f); - expect(newGeom.type).toBe("LineString"); - expect(newGeom.coordinates[0][0]).toBe(0); - expect(newGeom.coordinates[0][1]).toBe(0); - expect(newGeom.coordinates[3][0]).toBe(5); - expect(newGeom.coordinates[3][1]).toBe(5); - }); - it('updateAllStyles, defaults', () => { - const f = { - type: "FeatureCollection", - features: [] - }; - const newFcoll = updateAllStyles(f); - expect(newFcoll.features.length).toBe(0); - }); - it('updateAllStyles, with new props', () => { - const f = { - type: "FeatureCollection", - features: [{ - type: "Feature", - geometry: { - type: "LineString", - coordinates: [[0, 0], [1, 1], [3, 3], [5, 5]] - }, - style: [{ - color: "#FF0000" - }].concat(getStartEndPointsForLinestring()) - }] - }; - const newFcoll = updateAllStyles(f, {highlight: true}); - expect(newFcoll.features.length).toBe(1); - newFcoll.features.map(ft => { - ft.style.map(s => { - expect(s.highlight).toBe(true); - }); - }); - }); - it('fromLineStringToGeodesicLineString', () => { - const geometryGeodesic = { - type: "LineString", - coordinates: [[1, 1], [2, 2]] - }; - const properties = { - geometryGeodesic, - id: "VR46" - }; - const f = fromLineStringToGeodesicLineString(properties, {color: "#12233"}); - expect(f.geometry).toEqual(geometryGeodesic); - expect(f.type).toEqual("Feature"); - expect(f.properties.id).toEqual("VR46"); - expect(f.properties.ms_style).toExist(); - }); - - it('test isCompletePolygon defaults', () => { - const polygonCoords0 = []; - const polygonCoords1 = [[[1, 1]]]; - const polygonCoords2 = [[[1, 1], [2, 2]]]; - const polygonCoords3 = [[[1, 1], [2, 2], [1, 1]]]; - const polygonCoords4 = [[[1, 1], [2, 2], [3, 3], [1, 1]]]; - const polygonCoords5 = [[[1, 1], [2, undefined], [3, 3], [1, 1]]]; - expect(isCompletePolygon()).toBe(false); - expect(isCompletePolygon(polygonCoords0)).toBe(false); - expect(isCompletePolygon(polygonCoords1)).toBe(false); - expect(isCompletePolygon(polygonCoords2)).toBe(false); - expect(isCompletePolygon(polygonCoords3)).toBe(false); - expect(isCompletePolygon(polygonCoords4)).toBe(true); - expect(isCompletePolygon(polygonCoords5)).toBe(false); - }); - it('test getDashArrayFromStyle', () => { - // default - expect(getDashArrayFromStyle()).toEqual(""); - expect(getDashArrayFromStyle("3 4 5")).toEqual("3 4 5"); - expect(getDashArrayFromStyle(["3", "4", "5"])).toEqual("3 4 5"); - }); - it('test annotationsToPrint strokeDashstyle defaults to solid', () => { - const f = { - type: "FeatureCollection", - features: [{ - type: "Feature", - geometry: { - type: "LineString", - coordinates: [[0, 0], [1, 1], [3, 3], [5, 5]] - }, - style: [{ - color: "#FF0000" - }].concat(getStartEndPointsForLinestring()) - }] - }; - let fts = annotationsToPrint([f]); - expect(fts).toExist(); - expect(fts.length).toBe(1); - expect(fts[0].properties.ms_style).toExist(); - expect(fts[0].properties.ms_style.strokeDashstyle).toBe('solid'); - }); - - it('test annotationsToPrint text without outline', () => { - const f = { - type: "FeatureCollection", - features: [{ - type: "Feature", - geometry: { - type: "Point", - coordinates: [0, 0] - }, - style: { - color: "#000000", - fillColor: "#000000", - fillOpacity: 1, - font: "14px Arial", - fontFamily: "Arial", - fontSize: "14", - fontSizeUom: "px", - fontStyle: "normal", - fontWeight: "normal", - highlight: false, - label: "test", - opacity: 1, - textAlign: "center", - title: "Text Style", - type: "Text" - } - }] - }; - let fts = annotationsToPrint([f]); - expect(fts).toExist(); - expect(fts.length).toBe(1); - expect(fts[0].properties.ms_style).toExist(); - expect(fts[0].properties.ms_style.labelOutlineColor).toNotExist(); - }); - - it('test annotationsToPrint text with outline', () => { - const f = { - type: "FeatureCollection", - features: [{ - type: "Feature", - geometry: { - type: "Point", - coordinates: [0, 0] - }, - style: { - color: "#000000", - fillColor: "#000000", - fillOpacity: 1, - font: "14px Arial", - fontFamily: "Arial", - fontSize: "14", - fontSizeUom: "px", - fontStyle: "normal", - fontWeight: "normal", - highlight: false, - label: "test", - opacity: 1, - textAlign: "center", - title: "Text Style", - type: "Text", - weight: 2.0 - }, - properties: { - isText: true - } - }] - }; - let fts = annotationsToPrint([f]); - expect(fts).toExist(); - expect(fts.length).toBe(1); - expect(fts[0].properties.ms_style).toExist(); - expect(fts[0].properties.ms_style.labelOutlineColor).toExist(); - }); - - it('test modifySelectedInEdited', () => { - const selectedPoint = { - type: "Feature", - geometry: { - type: "Point", - coordinates: ['', 1] - }, - properties: { - id: 1 - } - }; - const selectedPolygon = { - type: "Feature", - geometry: { - type: "Polygon", - coordinates: [ - [ - [1, 45], - ['', 45], - [2, 44], - [1, 44], - [1, 45] - ] - ] - }, - properties: { - id: 3 - } - }; - - const { selected: pointSelected, editing: editingWithPoint } = modifySelectedInEdited(selectedPoint, featureCollection); - const { selected: nullSelected, editing: editingWithNull } = modifySelectedInEdited(null, featureCollection); - const { selected: polygonSelected, editing: editingWithPolygon } = modifySelectedInEdited(selectedPolygon, featureCollection); - - expect(Array.isArray(pointSelected.geometry.coordinates)).toBe(true); - expect(pointSelected.geometry.coordinates.length).toBe(0); - expect(editingWithPoint.features[0].geometry).toBe(null); - expect(editingWithPoint.features[0].properties.id).toBe(1); - expect(editingWithPoint.features[1].geometry.coordinates.length).toBe(2); - expect(editingWithPoint.features[2].geometry.coordinates[0].length).toBe(5); - - expect(nullSelected).toBe(null); - expect(editingWithNull.features[0].geometry.coordinates.length).toBe(2); - expect(editingWithNull.features[1].geometry.coordinates.length).toBe(2); - expect(editingWithNull.features[2].geometry.coordinates[0].length).toBe(5); - - expect(polygonSelected.geometry.coordinates[0].length).toBe(4); - expect(editingWithPolygon.features[2].geometry.coordinates[0].length).toBe(4); - expect(editingWithPolygon.features[0].geometry.coordinates.length).toBe(2); - expect(editingWithPolygon.features[1].geometry.coordinates.length).toBe(2); - - }); -}); diff --git a/web/client/utils/__tests__/SLDUtils-test.js b/web/client/utils/__tests__/SLDUtils-test.js deleted file mode 100644 index 3afe7d27bb..0000000000 --- a/web/client/utils/__tests__/SLDUtils-test.js +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Copyright 2016, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ -import expect from 'expect'; - -import { jsonToSLD, vecStyleToSLD } from '../SLDUtils'; - -const rasterstylerstate = { - redband: {band: '1', contrast: 'GammaValue', algorithm: "none", gammaValue: 1, min: 1, max: 255}, - blueband: {band: '3', contrast: 'none', algorithm: "none", gammaValue: 1, min: 1, max: 255}, - greenband: {band: '2', contrast: 'none', algorithm: "none", gammaValue: 1, min: 1, max: 255}, - grayband: {band: '1', contrast: 'none', algorithm: "none", gammaValue: 1, min: 1, max: 255}, - pseudocolor: {colorMapEntry: [{color: "#eff3ff", quantity: 0, label: "0.00"}], type: "ramp", opacity: "1.00"}, - pseudoband: {band: "1", contrast: "Normalize", algorithm: "ClipToMinimumMaximum", min: 1, max: 255} -}; -const layer = {name: "sde:HYP_HR_SR_OB_DR"}; - - -describe('SLDUtils', () => { - - it('convert rasterlayer state to sld strings', () => { - let pseudo = jsonToSLD({ - styletype: "pseudo", - opacity: "0.50", - state: rasterstylerstate, - layer: layer}); - expect(pseudo).toExist(); - let rgb = jsonToSLD( - { - styletype: "rgb", - opacity: "0.50", - state: rasterstylerstate, - layer: layer - }); - expect(rgb).toExist(); - let gray = jsonToSLD({ - styletype: "gray", - opacity: "0.50", - state: rasterstylerstate, - layer: layer - }); - expect(gray).toExist(); - }); - it('test vectorlayer state to sld strings', () => { - let rules = [ - { - "id": "bd8587a0-543a-11e6-a812-3f41916af8df", - "symbol": { - "type": "Point", - "color": {"r": 0, "g": 0, "b": 255, "a": 1}, - "width": 3, - "fill": {"r": 0, "g": 0, "b": 255, "a": 0.1}, - "radius": 10, - "marker": false, - "markName": "circle" - }, - "name": "Test Name"}, - { - "id": "dfcce690-543b-11e6-a812-3f41916af8df", - "symbol": { - "type": "Polygon", - "color": {"r": 0, "g": 0, "b": 255, "a": 1}, - "width": 3, - "fill": {"r": 0, "g": 0, "b": 255, "a": 0.1} - }, - "name": "Test Name"}, - { - "id": "406d88b0-543c-11e6-a812-3f41916af8df", - "symbol": { - "type": "Line", - "color": {"r": 0, "g": 0, "b": 255, "a": 1}, - "width": 3 - }, - "name": "Test Name", - "minDenominator": 73957338.86364141, - "maxDenominator": 295829355.45456564} - ]; - let result = `sde:HYP_HR_SR_OB_DRcircle#0000ff0.1#0000ff1310#0000ff0.1#0000ff1373957338.86364141295829355.45456564#0000ff13`; - let sld = vecStyleToSLD({ - rules, - layer}); - expect(sld).toExist(); - expect(sld).toEqual(result); - }); -});