diff --git a/dist/mapboxgl/include-mapboxgl.js b/dist/mapboxgl/include-mapboxgl.js index d57cd65d78..32628db0a9 100644 --- a/dist/mapboxgl/include-mapboxgl.js +++ b/dist/mapboxgl/include-mapboxgl.js @@ -118,9 +118,9 @@ inputScript(libsurl + '/ant-design-vue/1.7.8/antd.min.js'); } if (inArray(includes, 'antd')) { - inputCSS(libsurl + '/antd/3.25.3/antd.min.css'); + inputCSS(libsurl + '/antd/3.26.20/antd.min.css'); inputScript(libsurl + '/moment/2.29.4/moment.min.js'); - inputScript(libsurl + '/antd/3.25.3/antd.min.js'); + inputScript(libsurl + '/antd/3.26.20/antd.min.js'); } if (inArray(includes, 'deck')) { inputScript(libsurl + '/deck.gl/5.1.3/deck.gl.min.js'); diff --git a/dist/maplibregl/include-maplibregl.js b/dist/maplibregl/include-maplibregl.js index 4703136c22..c90c019eb2 100644 --- a/dist/maplibregl/include-maplibregl.js +++ b/dist/maplibregl/include-maplibregl.js @@ -111,9 +111,9 @@ inputScript(libsurl + '/ant-design-vue/1.7.8/antd.min.js'); } if (inArray(includes, 'antd')) { - inputCSS(libsurl + '/antd/3.25.3/antd.min.css'); + inputCSS(libsurl + '/antd/3.26.20/antd.min.css'); inputScript(libsurl + '/moment/2.29.4/moment.min.js'); - inputScript(libsurl + '/antd/3.25.3/antd.min.js'); + inputScript(libsurl + '/antd/3.26.20/antd.min.js'); } if (inArray(includes, 'deck')) { inputScript(libsurl + '/deck.gl/5.1.3/deck.gl.min.js'); diff --git a/examples/css/sidebariconfont/iconfont.css b/examples/css/sidebariconfont/iconfont.css index 304c2a7306..55c8e54cba 100644 --- a/examples/css/sidebariconfont/iconfont.css +++ b/examples/css/sidebariconfont/iconfont.css @@ -1,8 +1,8 @@ @font-face { font-family: "iconfont"; /* Project id 4848754 */ - src: url('iconfont.woff2?t=1741260044249') format('woff2'), - url('iconfont.woff?t=1741260044249') format('woff'), - url('iconfont.ttf?t=1741260044249') format('truetype'); + src: url('iconfont.woff2?t=1757901504792') format('woff2'), + url('iconfont.woff?t=1757901504792') format('woff'), + url('iconfont.ttf?t=1757901504792') format('truetype'); } .iconfont { @@ -14,90 +14,90 @@ } .icon-control:before { - content: "\e61f"; + content: "\e161f"; } .icon-components:before { - content: "\e626"; + content: "\e1626"; } .icon-Online:before { - content: "\e625"; + content: "\e1625"; } .icon-OGC:before { - content: "\e624"; + content: "\e1624"; } .icon-analysis:before { - content: "\e620"; + content: "\e1620"; } .icon-Elasticsearch:before { - content: "\e621"; + content: "\e1621"; } .icon-multiCoordSys:before { - content: "\e618"; + content: "\e1618"; } .icon-mapping:before { - content: "\e619"; + content: "\e1619"; } .icon-MapboxGL:before { - content: "\e61a"; + content: "\e161a"; } .icon-map:before { - content: "\e61b"; + content: "\e161b"; } .icon-dynamicPlot:before { - content: "\e61c"; + content: "\e161c"; } .icon-others:before { - content: "\e61d"; + content: "\e161d"; } .icon-iServer:before { - content: "\e61e"; + content: "\e161e"; } .icon-clientSpatialAnalyst:before { - content: "\e622"; + content: "\e1622"; } .icon-overlay:before { - content: "\e60f"; + content: "\e160f"; } .icon-Leaflet:before { - content: "\e60e"; + content: "\e160e"; } .icon-iPortal:before { - content: "\e611"; + content: "\e1611"; } .icon-theme:before { - content: "\e613"; + content: "\e1613"; } .icon-popup:before { - content: "\e614"; + content: "\e1614"; } .icon-iManager:before { - content: "\e615"; + content: "\e1615"; } .icon-viz:before { - content: "\e616"; + content: "\e1616"; } .icon-query:before { - content: "\e617"; + content: "\e1617"; } diff --git a/examples/css/sidebariconfont/iconfont.ttf b/examples/css/sidebariconfont/iconfont.ttf index 08f715f76b..fa7dde7a3b 100644 Binary files a/examples/css/sidebariconfont/iconfont.ttf and b/examples/css/sidebariconfont/iconfont.ttf differ diff --git a/examples/css/sidebariconfont/iconfont.woff b/examples/css/sidebariconfont/iconfont.woff index 642846f935..faedbf47b8 100644 Binary files a/examples/css/sidebariconfont/iconfont.woff and b/examples/css/sidebariconfont/iconfont.woff differ diff --git a/examples/css/sidebariconfont/iconfont.woff2 b/examples/css/sidebariconfont/iconfont.woff2 index 0f01897e16..789e7218d7 100644 Binary files a/examples/css/sidebariconfont/iconfont.woff2 and b/examples/css/sidebariconfont/iconfont.woff2 differ diff --git a/src/common/commontypes/Util.js b/src/common/commontypes/Util.js index 59803646a6..f5a37e021b 100644 --- a/src/common/commontypes/Util.js +++ b/src/common/commontypes/Util.js @@ -435,6 +435,18 @@ const Util = { return paramsArray.join('&'); }, + handleUrlSuffix(url, suffix = '.json') { + if (url.indexOf('?') < 0) { + url += suffix; + } else { + var urlArrays = url.split('?'); + if (urlArrays.length === 2) { + url = urlArrays[0] + suffix + '?' + urlArrays[1]; + } + } + return url + }, + /** * @memberOf CommonUtil * @description 给 URL 追加查询参数。 diff --git a/src/common/iServer/CommonServiceBase.js b/src/common/iServer/CommonServiceBase.js index d4407251da..6f778ac364 100644 --- a/src/common/iServer/CommonServiceBase.js +++ b/src/common/iServer/CommonServiceBase.js @@ -150,6 +150,7 @@ export class CommonServiceBase { options.headers = options.headers || me.headers; options.isInTheSameDomain = me.isInTheSameDomain; options.withoutFormatSuffix = options.scope.withoutFormatSuffix || false; + options.preferServer = options.preferServer || me.preferServer; //为url添加安全认证信息片段 options.url = SecurityManager.appendCredential(options.url); diff --git a/src/common/iServer/FeatureService.js b/src/common/iServer/FeatureService.js index 6f180b3519..9541acb7a6 100644 --- a/src/common/iServer/FeatureService.js +++ b/src/common/iServer/FeatureService.js @@ -17,7 +17,7 @@ const FEATURE_SERVICE_MAP = { bounds: GetFeaturesByBoundsService, buffer: GetFeaturesByBufferService, geometry: GetFeaturesByGeometryService -} +}; /** * @class FeatureService @@ -34,11 +34,11 @@ const FEATURE_SERVICE_MAP = { * @param {boolean} [options.withCredentials=false] - 请求是否携带 cookie。 * @param {boolean} [options.crossOrigin] - 是否允许跨域请求。 * @param {Object} [options.headers] - 请求头。 + * @param {boolean} [options.preferServer=false] - 当resultFormat=DataFormat.GEOJSON时,使用服务器直接返回geojson。 * @extends {ServiceBase} * @usage */ export class FeatureService { - constructor(url, options) { this.url = url; this.options = options || {}; @@ -59,7 +59,8 @@ export class FeatureService { withCredentials: me.options.withCredentials, crossOrigin: me.options.crossOrigin, headers: me.options.headers, - format: resultFormat + format: resultFormat, + preferServer: me.options.preferServer }); return getFeaturesByIDsService.processAsync(params, callback); } @@ -79,7 +80,8 @@ export class FeatureService { withCredentials: me.options.withCredentials, crossOrigin: me.options.crossOrigin, headers: me.options.headers, - format: me._processFormat(resultFormat) + format: me._processFormat(resultFormat), + preferServer: me.options.preferServer }); return getFeaturesByBoundsService.processAsync(params, callback); } @@ -99,7 +101,8 @@ export class FeatureService { withCredentials: me.options.withCredentials, crossOrigin: me.options.crossOrigin, headers: me.options.headers, - format: me._processFormat(resultFormat) + format: me._processFormat(resultFormat), + preferServer: me.options.preferServer }); return getFeatureService.processAsync(params, callback); } @@ -119,7 +122,8 @@ export class FeatureService { withCredentials: me.options.withCredentials, crossOrigin: me.options.crossOrigin, headers: me.options.headers, - format: me._processFormat(resultFormat) + format: me._processFormat(resultFormat), + preferServer: me.options.preferServer }); return getFeatureBySQLService.processAsync(params, callback); } @@ -139,7 +143,8 @@ export class FeatureService { withCredentials: me.options.withCredentials, crossOrigin: me.options.crossOrigin, headers: me.options.headers, - format: me._processFormat(resultFormat) + format: me._processFormat(resultFormat), + preferServer: me.options.preferServer }); return getFeaturesByGeometryService.processAsync(params, callback); } @@ -159,7 +164,7 @@ export class FeatureService { url = me.url, dataSourceName = params.dataSourceName, dataSetName = params.dataSetName; - url = CommonUtil.urlPathAppend(url, "datasources/" + dataSourceName + "/datasets/" + dataSetName); + url = CommonUtil.urlPathAppend(url, 'datasources/' + dataSourceName + '/datasets/' + dataSetName); var editFeatureService = new EditFeaturesService(url, { proxy: me.options.proxy, @@ -182,7 +187,7 @@ export class FeatureService { url = me.url, dataSourceName = params.dataSourceName, dataSetName = params.dataSetName; - url = CommonUtil.urlPathAppend(url, "datasources/" + dataSourceName + "/datasets/" + dataSetName); + url = CommonUtil.urlPathAppend(url, 'datasources/' + dataSourceName + '/datasets/' + dataSetName); var editFeatureService = new EditFeaturesService(url, { proxy: me.options.proxy, withCredentials: me.options.withCredentials, @@ -207,7 +212,7 @@ export class FeatureService { url = me.url, dataSourceName = params.dataSourceName, dataSetName = params.dataSetName; - url = CommonUtil.urlPathAppend(url, "datasources/" + dataSourceName + "/datasets/" + dataSetName); + url = CommonUtil.urlPathAppend(url, 'datasources/' + dataSourceName + '/datasets/' + dataSetName); var featureAttachmentsService = new FeatureAttachmentsService(url, { proxy: me.options.proxy, withCredentials: me.options.withCredentials, @@ -233,7 +238,7 @@ export class FeatureService { url = me.url, dataSourceName = params.dataSourceName, dataSetName = params.dataSetName; - url = CommonUtil.urlPathAppend(url, "datasources/" + dataSourceName + "/datasets/" + dataSetName); + url = CommonUtil.urlPathAppend(url, 'datasources/' + dataSourceName + '/datasets/' + dataSetName); var featureAttachmentsService = new FeatureAttachmentsService(url, { proxy: me.options.proxy, withCredentials: me.options.withCredentials, diff --git a/src/common/iServer/GetFeaturesByBoundsService.js b/src/common/iServer/GetFeaturesByBoundsService.js index 39953436ae..e2e7ec15bf 100644 --- a/src/common/iServer/GetFeaturesByBoundsService.js +++ b/src/common/iServer/GetFeaturesByBoundsService.js @@ -17,6 +17,7 @@ import {GetFeaturesByBoundsParameters} from './GetFeaturesByBoundsParameters'; * @param {DataFormat} [options.format=DataFormat.GEOJSON] - 查询结果返回格式,目前支持 iServerJSON、GeoJSON、FGB 三种格式。参数格式为 "ISERVER","GEOJSON","FGB"。 * @param {boolean} [options.crossOrigin] - 是否允许跨域请求。 * @param {Object} [options.headers] - 请求头。 + * @param {boolean} [options.preferServer=false] - 当options.format=DataFormat.GEOJSON时,使用服务器直接返回geojson。 * @example * var myGetFeaturesByBoundsService = new SuperMa.GetFeaturesByBoundsService(url); * @usage diff --git a/src/common/iServer/GetFeaturesByBufferService.js b/src/common/iServer/GetFeaturesByBufferService.js index e96000e35b..9906ec99fa 100644 --- a/src/common/iServer/GetFeaturesByBufferService.js +++ b/src/common/iServer/GetFeaturesByBufferService.js @@ -16,6 +16,7 @@ import {GetFeaturesByBufferParameters} from './GetFeaturesByBufferParameters'; * @param {DataFormat} [options.format=DataFormat.GEOJSON] - 查询结果返回格式,目前支持 iServerJSON、GeoJSON、FGB 三种格式。参数格式为 "ISERVER","GEOJSON","FGB"。 * @param {boolean} [options.crossOrigin] - 是否允许跨域请求。 * @param {Object} [options.headers] - 请求头。 + * @param {boolean} [options.preferServer=false] - 当options.format=DataFormat.GEOJSON时,使用服务器直接返回geojson。 * @extends {GetFeaturesServiceBase} * @example * var myGetFeaturesByBufferService = new GetFeaturesByBufferService(url); diff --git a/src/common/iServer/GetFeaturesByGeometryService.js b/src/common/iServer/GetFeaturesByGeometryService.js index 7c1e46c6ea..cc42770789 100644 --- a/src/common/iServer/GetFeaturesByGeometryService.js +++ b/src/common/iServer/GetFeaturesByGeometryService.js @@ -16,6 +16,7 @@ import {GetFeaturesByGeometryParameters} from './GetFeaturesByGeometryParameters * @param {DataFormat} [options.format=DataFormat.GEOJSON] - 查询结果返回格式,目前支持 iServerJSON、GeoJSON、FGB 三种格式。参数格式为 "ISERVER","GEOJSON","FGB"。 * @param {boolean} [options.crossOrigin] - 是否允许跨域请求。 * @param {Object} [options.headers] - 请求头。 + * @param {boolean} [options.preferServer=false] - 当options.format=DataFormat.GEOJSON时,使用服务器直接返回geojson。 * @extends {GetFeaturesServiceBase} * @example * var myService = new GetFeaturesByGeometryService(url); diff --git a/src/common/iServer/GetFeaturesByIDsService.js b/src/common/iServer/GetFeaturesByIDsService.js index 9ac2cd86a1..bb2ffc1b13 100644 --- a/src/common/iServer/GetFeaturesByIDsService.js +++ b/src/common/iServer/GetFeaturesByIDsService.js @@ -16,6 +16,7 @@ import {GetFeaturesByIDsParameters} from './GetFeaturesByIDsParameters'; * @param {DataFormat} [options.format=DataFormat.GEOJSON] - 查询结果返回格式,目前支持 iServerJSON、GeoJSON、FGB 三种格式。参数格式为 "ISERVER","GEOJSON","FGB"。 * @param {boolean} [options.crossOrigin] - 是否允许跨域请求。 * @param {Object} [options.headers] - 请求头。 + * @param {boolean} [options.preferServer=false] - 当options.format=DataFormat.GEOJSON时,使用服务器直接返回geojson。 * @extends {GetFeaturesServiceBase} * @example * var myGetFeaturesByIDsService = new GetFeaturesByIDsService(url); diff --git a/src/common/iServer/GetFeaturesBySQLService.js b/src/common/iServer/GetFeaturesBySQLService.js index d4216034d2..d04327e138 100644 --- a/src/common/iServer/GetFeaturesBySQLService.js +++ b/src/common/iServer/GetFeaturesBySQLService.js @@ -17,6 +17,7 @@ import {GetFeaturesBySQLParameters} from './GetFeaturesBySQLParameters'; * @param {DataFormat} [options.format=DataFormat.GEOJSON] - 查询结果返回格式,目前支持 iServerJSON、GeoJSON、FGB 三种格式。参数格式为 "ISERVER","GEOJSON","FGB"。 * @param {boolean} [options.crossOrigin] - 是否允许跨域请求。 * @param {Object} [options.headers] - 请求头。 + * @param {boolean} [options.preferServer=false] - 当options.format=DataFormat.GEOJSON时,使用服务器直接返回geojson。 * @extends {GetFeaturesServiceBase} * @example * var myGetFeaturesBySQLService = new GetFeaturesBySQLService(url); diff --git a/src/common/iServer/GetFeaturesServiceBase.js b/src/common/iServer/GetFeaturesServiceBase.js index d3c3db5021..dc09bb0f1d 100644 --- a/src/common/iServer/GetFeaturesServiceBase.js +++ b/src/common/iServer/GetFeaturesServiceBase.js @@ -1,10 +1,10 @@ /* Copyright© 2000 - 2025 SuperMap Software Co.Ltd. All rights reserved. * This program are made available under the terms of the Apache License, Version 2.0 * which accompanies this distribution and is available at http://www.apache.org/licenses/LICENSE-2.0.html.*/ -import {Util} from '../commontypes/Util'; -import {DataFormat} from '../REST'; -import {CommonServiceBase} from './CommonServiceBase'; -import {GeoJSON} from '../format/GeoJSON'; +import { Util } from '../commontypes/Util'; +import { DataFormat } from '../REST'; +import { CommonServiceBase } from './CommonServiceBase'; +import { GeoJSON } from '../format/GeoJSON'; /** * @class GetFeaturesServiceBase @@ -19,65 +19,65 @@ import {GeoJSON} from '../format/GeoJSON'; * @param {DataFormat} [options.format=DataFormat.GEOJSON] - 查询结果返回格式,目前支持 iServerJSON、GeoJSON、FGB 三种格式。参数格式为 "ISERVER","GEOJSON","FGB"。 * @param {boolean} [options.crossOrigin] - 是否允许跨域请求。 * @param {Object} [options.headers] - 请求头。 + * @param {boolean} [options.preferServer=false] - 当options.format=DataFormat.GEOJSON时,使用服务器直接返回geojson。 * @example * var myService = new GetFeaturesServiceBase(url); * @usage */ export class GetFeaturesServiceBase extends CommonServiceBase { - constructor(url, options) { - super(url, options); - options = options || {}; - - /** - * @member {boolean} [GetFeaturesServiceBase.prototype.returnContent=true] - * @description 是否立即返回新创建资源的表述还是返回新资源的 URI。 - * 如果为 true,则直接返回新创建资源,即查询结果的表述。 - * 如果为 false,则返回的是查询结果资源的 URI。 - */ - this.returnContent = true; - - /** - * @member {boolean} [GetFeaturesServiceBase.prototype.returnFeaturesOnly=false] - * @description 是否仅返回要素信息。 - */ - this.returnFeaturesOnly = false; - - /** - * @member {number} [GetFeaturesServiceBase.prototype.fromIndex=0] - * @description 查询结果的最小索引号。如果该值大于查询结果的最大索引号,则查询结果为空。 - */ - this.fromIndex = 0; - - /** - * @member {number} [GetFeaturesServiceBase.prototype.toIndex=19] - * @description 查询结果的最大索引号。 - * 如果该值大于查询结果的最大索引号,则以查询结果的最大索引号为终止索引号。 - */ - this.toIndex = 19; - - /** - * @member {number} [GetFeaturesServiceBase.prototype.hasGeometry=true] - * @description 返回结果是否包含 Geometry。 - */ - this.hasGeometry = true; - - /** - * @member {number} [GetFeaturesServiceBase.prototype.maxFeatures=1000] - * @description 进行 SQL 查询时,用于设置服务端返回查询结果条目数量。 - */ - this.maxFeatures = null; - - /** - * @member {string} [GetFeaturesServiceBase.prototype.format=DataFormat.GEOJSON] - * @description 查询结果返回格式,目前支持 iServerJSON、GeoJSON、FGB 三种格式。 - * 参数格式为 "ISERVER","GEOJSON","FGB"。 - */ - this.format = DataFormat.GEOJSON; - - Util.extend(this, options); - this.url = Util.urlPathAppend(this.url, 'featureResults'); - this.CLASS_NAME = "SuperMap.GetFeaturesServiceBase"; + super(url, options); + options = options || {}; + + /** + * @member {boolean} [GetFeaturesServiceBase.prototype.returnContent=true] + * @description 是否立即返回新创建资源的表述还是返回新资源的 URI。 + * 如果为 true,则直接返回新创建资源,即查询结果的表述。 + * 如果为 false,则返回的是查询结果资源的 URI。 + */ + this.returnContent = true; + + /** + * @member {boolean} [GetFeaturesServiceBase.prototype.returnFeaturesOnly=false] + * @description 是否仅返回要素信息。 + */ + this.returnFeaturesOnly = false; + + /** + * @member {number} [GetFeaturesServiceBase.prototype.fromIndex=0] + * @description 查询结果的最小索引号。如果该值大于查询结果的最大索引号,则查询结果为空。 + */ + this.fromIndex = 0; + + /** + * @member {number} [GetFeaturesServiceBase.prototype.toIndex=19] + * @description 查询结果的最大索引号。 + * 如果该值大于查询结果的最大索引号,则以查询结果的最大索引号为终止索引号。 + */ + this.toIndex = 19; + + /** + * @member {number} [GetFeaturesServiceBase.prototype.hasGeometry=true] + * @description 返回结果是否包含 Geometry。 + */ + this.hasGeometry = true; + + /** + * @member {number} [GetFeaturesServiceBase.prototype.maxFeatures=1000] + * @description 进行 SQL 查询时,用于设置服务端返回查询结果条目数量。 + */ + this.maxFeatures = null; + + /** + * @member {string} [GetFeaturesServiceBase.prototype.format=DataFormat.GEOJSON] + * @description 查询结果返回格式,目前支持 iServerJSON、GeoJSON、FGB 三种格式。 + * 参数格式为 "ISERVER","GEOJSON","FGB"。 + */ + this.format = DataFormat.GEOJSON; + + Util.extend(this, options); + this.url = Util.urlPathAppend(this.url, 'featureResults'); + this.CLASS_NAME = 'SuperMap.GetFeaturesServiceBase'; } /** @@ -85,14 +85,14 @@ export class GetFeaturesServiceBase extends CommonServiceBase { * @description 释放资源,将引用资源的属性置空。 */ destroy() { - super.destroy(); - var me = this; - me.returnContent = null; - me.fromIndex = null; - me.toIndex = null; - me.maxFeatures = null; - me.format = null; - me.hasGeometry = null; + super.destroy(); + var me = this; + me.returnContent = null; + me.fromIndex = null; + me.toIndex = null; + me.maxFeatures = null; + me.format = null; + me.hasGeometry = null; } /** @@ -103,52 +103,57 @@ export class GetFeaturesServiceBase extends CommonServiceBase { * @returns {Promise} Promise 对象。 */ processAsync(params, callback) { - if (!params) { - return; - } - var me = this, - jsonParameters = null, - firstPara = true; - - me.returnContent = params.returnContent; - me.returnFeaturesOnly = params.returnFeaturesOnly; - me.fromIndex = params.fromIndex; - me.toIndex = params.toIndex; - me.maxFeatures = params.maxFeatures; - me.hasGeometry = params.hasGeometry; - if (me.returnContent) { - firstPara = false; + if (!params) { + return; + } + var me = this, + jsonParameters = null, + firstPara = true; + me.returnContent = params.returnContent; + me.returnFeaturesOnly = params.returnFeaturesOnly; + me.fromIndex = params.fromIndex; + me.toIndex = params.toIndex; + me.maxFeatures = params.maxFeatures; + me.hasGeometry = params.hasGeometry; + if (me.returnContent) { + firstPara = false; + } + var isValidNumber = me.fromIndex != null && me.toIndex != null && !isNaN(me.fromIndex) && !isNaN(me.toIndex); + if (isValidNumber && me.fromIndex >= 0 && me.toIndex >= 0 && !firstPara) { + me.url = Util.urlAppend(me.url, `fromIndex=${me.fromIndex}&toIndex=${me.toIndex}`); + } + + if (me.returnContent) { + if (!params.returnCountOnly && !params.returnDatasetInfoOnly && !params.returnFeaturesOnly) { + console.warn( + 'recommend set returnFeaturesOnly config to true to imporve performance. if need get Total amount and Dataset information. FeatureService provide getFeaturesCount and getFeaturesDatasetInfo method' + ); } - var isValidNumber = me.fromIndex != null && me.toIndex != null && !isNaN(me.fromIndex) && !isNaN(me.toIndex); - if (isValidNumber && me.fromIndex >= 0 && me.toIndex >= 0 && !firstPara) { - me.url = Util.urlAppend(me.url, `fromIndex=${me.fromIndex}&toIndex=${me.toIndex}`); + if (params.returnCountOnly) { + me.url = Util.urlAppend(me.url, 'returnCountOnly=' + params.returnCountOnly); } - if (me.returnContent) { - if (!params.returnCountOnly && !params.returnDatasetInfoOnly && !params.returnFeaturesOnly) { - console.warn('recommend set returnFeaturesOnly config to true to imporve performance. if need get Total amount and Dataset information. FeatureService provide getFeaturesCount and getFeaturesDatasetInfo method'); - } - if (params.returnCountOnly) { - me.url = Util.urlAppend(me.url, "returnCountOnly=" + params.returnCountOnly) - } - - if (params.returnDatasetInfoOnly) { - me.url = Util.urlAppend(me.url, "returnDatasetInfoOnly=" + params.returnDatasetInfoOnly) - } - - if (params.returnFeaturesOnly) { - me.url = Util.urlAppend(me.url, "returnFeaturesOnly=" + params.returnFeaturesOnly) - } - } - - jsonParameters = me.getJsonParameters(params); - return me.request({ - method: "POST", - data: jsonParameters, - scope: me, - success: callback, - failure: callback - }); + if (params.returnDatasetInfoOnly) { + me.url = Util.urlAppend(me.url, 'returnDatasetInfoOnly=' + params.returnDatasetInfoOnly); + } + if (params.returnFeaturesOnly) { + me.url = Util.urlAppend(me.url, 'returnFeaturesOnly=' + params.returnFeaturesOnly); + } + } + + if (me.preferServer && me.format === DataFormat.GEOJSON) { + me.url = Util.handleUrlSuffix(me.url, '.geojson'); + me.withoutFormatSuffix = true; + } + + jsonParameters = me.getJsonParameters(params); + return me.request({ + method: 'POST', + data: jsonParameters, + scope: me, + success: callback, + failure: callback + }); } /** @@ -159,25 +164,29 @@ export class GetFeaturesServiceBase extends CommonServiceBase { * @return {Object} 转换结果。 */ transformResult(result, options) { - var me = this; - result = Util.transformResult(result); - var geoJSONFormat = new GeoJSON(); - if (me.format === DataFormat.GEOJSON && result.features) { - result.features = geoJSONFormat.toGeoJSON(result.features); - } - if (me.returnFeaturesOnly && Array.isArray(result)) { - let succeed = result.succeed; - let features = geoJSONFormat.toGeoJSON(result); - result = { - succeed, - features - }; - } - return { result, options }; + var me = this; + result = Util.transformResult(result); + var geoJSONFormat = new GeoJSON(); + if (me.preferServer && me.format === DataFormat.GEOJSON) { + const succeed = result.succeed; + delete result.succeed; + return { result: { succeed, features: result }, options }; + } + if (me.format === DataFormat.GEOJSON && result.features) { + result.features = geoJSONFormat.toGeoJSON(result.features); + } + if (me.returnFeaturesOnly && Array.isArray(result)) { + let succeed = result.succeed; + let features = geoJSONFormat.toGeoJSON(result); + result = { + succeed, + features + }; + } + return { result, options }; } dataFormat() { return [DataFormat.GEOJSON, DataFormat.ISERVER, DataFormat.FGB]; } - } diff --git a/src/common/mapping/MapBase.js b/src/common/mapping/MapBase.js index 22d3512f87..d4a221adc1 100644 --- a/src/common/mapping/MapBase.js +++ b/src/common/mapping/MapBase.js @@ -57,6 +57,10 @@ export function createMapClassExtending(SuperClass = class {}) { return exsitLayers; } + changeBaseLayer() { + this._sourceListModel && this._sourceListModel.changeBaseLayer(...arguments); + } + echartsLayerResize() {} updateOverlayLayer() {} diff --git a/src/common/mapping/MapStyle.js b/src/common/mapping/MapStyle.js index 555a5d0d2b..cbacf973a4 100644 --- a/src/common/mapping/MapStyle.js +++ b/src/common/mapping/MapStyle.js @@ -39,7 +39,7 @@ export function createMapStyleExtending(SuperClass, { MapManager, crsManager }) } return { url: proxy ? `${proxy}${encodeURIComponent(url)}` : url, - credentials: this.webMapService.handleWithCredentials(proxy, url, this.options.withCredentials || false) + credentials: this.webMapService.handleWithCredentials(proxy, url, false) ? 'include' : undefined, ...(this.options.tileTransformRequest && this.options.tileTransformRequest(url)) diff --git a/src/common/mapping/WebMapBase.js b/src/common/mapping/WebMapBase.js index 335d6b87b4..ff2a18d3ab 100644 --- a/src/common/mapping/WebMapBase.js +++ b/src/common/mapping/WebMapBase.js @@ -28,6 +28,7 @@ const WORLD_WIDTH = 360; * @param {boolean} [options.isSuperMapOnline] - 是否是 SuperMap Online 地图。 * @param {string} [options.iportalServiceProxyUrlPrefix] - iportal的代理服务地址前缀。 * @param {string|boolean} [options.proxy] - HTTP 请求代理地址 。布尔值表示使用 iPortal 默认代理地址。 + * @param {boolean} [options.preferServer=false] - iServer rest/data服务, 使用服务器直接返回geojson。 * @param {Object} mapOptions - 地图参数。 * @param {Array} [mapOptions.center] - 中心点。 * @param {number} [mapOptions.zoom] - 缩放级别。 @@ -486,6 +487,22 @@ export function createWebMapBaseExtending(SuperClass, { mapRepo }) { this.clean(false); } + /** + * @version 12.0.0 + * @function WebMapBase.prototype.changeBaseLayer + * @description 切换底图 + * @param {BaseLayerConfig} layer - 图层配置对象 + * @typedef {Object} BaseLayerConfig + * @property {string} id - 唯一标识 + * @property {string} title - 显示名称 + * @property {Array} layers - 上图的图层 + * @property {Object} sources - 图层对应的source + * @returns {Object} 当前底图信息 + */ + changeBaseLayer() { + return this._handler && this._handler.changeBaseLayer(...arguments); + } + _readyForInitializingWebMap() { this._initWebMap(!this.map); } diff --git a/src/common/mapping/WebMapService.js b/src/common/mapping/WebMapService.js index ed10a9524c..a92f3fca66 100644 --- a/src/common/mapping/WebMapService.js +++ b/src/common/mapping/WebMapService.js @@ -42,6 +42,7 @@ export class WebMapService { this.excludePortalProxyUrl = options.excludePortalProxyUrl; this.iportalServiceProxyUrl = options.iportalServiceProxyUrlPrefix; this.proxy = options.proxy; + this.preferServer = options.preferServer || false; this.proxyOptions = { data: 'apps/viewer/getUrlResource.json?url=', image: 'apps/viewer/getUrlResource.png?url=' @@ -1222,6 +1223,7 @@ export class WebMapService { let options = { proxy, withCredentials: this.handleWithCredentials(proxy, url, false), + preferServer: this.preferServer, eventListeners: { processCompleted: getFeaturesEventArgs => { let result = getFeaturesEventArgs.result; diff --git a/src/common/mapping/WebMapV2.js b/src/common/mapping/WebMapV2.js index 00519e4db1..8abe6c7f41 100644 --- a/src/common/mapping/WebMapV2.js +++ b/src/common/mapping/WebMapV2.js @@ -445,7 +445,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa const { minScale, maxScale } = layer.visibleScale; const crs = this.map.getCRS(); layer.minzoom = Math.max(this._transformScaleToZoom(minScale, crs, layer.tileSize), 0); - layer.maxzoom = Math.min(24, this._transformScaleToZoom(maxScale, crs, layer.tileSize) + 0.0000001); + layer.maxzoom = Math.min(this.map.getMaxZoom()+1, this._transformScaleToZoom(maxScale, crs, layer.tileSize) + 0.0000001); } if (type === 'tile') { @@ -506,6 +506,8 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa features = this.handleLayerFeatures(features, layerInfo); if (layerType === 'VECTOR') { + const styleGroups = this.getVectorStyleGroup(layerInfo); + this._initLegendConfigInfo(layerInfo, styleGroups); if (featureType === 'POINT') { if (style.type === 'SYMBOL_POINT') { this._createSymbolLayer(layerInfo, features); @@ -752,7 +754,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa return resolutions.every((item, i) => this.numberEqual(item, conversion * mapResolutions[i])); } _getMapResolutions() { - return this._getResolutionsByExtent({extent: this.map.getCRS().getExtent(), tileSize: 512}) + return this._getResolutionsByExtent({extent: this.map.getCRS().getExtent(), maxZoom: this.map.getMaxZoom() + 1, tileSize: 512}) } _getResolutionsByExtent({ extent, maxZoom = 24, tileSize }) { const width = extent[2] - extent[0]; @@ -1375,7 +1377,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa }, layout, minzoom: minzoom || 0, - maxzoom: maxzoom || 22 + maxzoom: maxzoom || this.map.getMaxZoom() + 1 }, layerInfo.layerID ); @@ -1427,7 +1429,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa visibility: layerInfo.visible }, minzoom: minzoom || 0, - maxzoom: maxzoom || 22 + maxzoom: maxzoom || this.map.getMaxZoom() + 1 }; if (filter) { layerOptions.filter = filter; @@ -1482,7 +1484,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa 'icon-rotate': iconRotateExpression || ((layerInfo.style.rotation || 0) * 180) / Math.PI }, minzoom: minzoom || 0, - maxzoom: maxzoom || 22 + maxzoom: maxzoom || this.map.getMaxZoom() + 1 }; if (filter) { layerOptions.filter = filter; @@ -1534,7 +1536,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa 'icon-color': style.fillColor }, minzoom: minzoom || 0, - maxzoom: maxzoom || 22 + maxzoom: maxzoom || this.map.getMaxZoom() + 1 }; if (filter) { layerOptions.filter = filter; @@ -1838,7 +1840,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa visibility: visible }, minzoom: minzoom || 0, - maxzoom: maxzoom || 22 + maxzoom: maxzoom || this.map.getMaxZoom() + 1 }; if (filterExpression.length > 1) { layerOptions.filter = filterExpression; @@ -1956,7 +1958,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa 'icon-rotate': symbolStyle.rotation || 0 }, minzoom: minzoom || 0, - maxzoom: maxzoom || 22, + maxzoom: maxzoom || this.map.getMaxZoom() + 1, filter: imagefilterExpression }, layerID @@ -1991,7 +1993,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa 'icon-color': symbolStyle.fillColor }, minzoom: minzoom || 0, - maxzoom: maxzoom || 22, + maxzoom: maxzoom || this.map.getMaxZoom() + 1, filter: svgfilterExpression }, layerID @@ -2162,7 +2164,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa paint: this._transformStyleToMapBoxGl(defaultStyle, geomType), layout: {}, minzoom: minzoom || 0, - maxzoom: maxzoom || 22 + maxzoom: maxzoom || this.map.getMaxZoom() + 1 }, markerLayerID ); @@ -2180,7 +2182,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa visibility: layerInfo.visible }, minzoom: minzoom || 0, - maxzoom: maxzoom || 22 + maxzoom: maxzoom || this.map.getMaxZoom() + 1 }, markerLayerID ); @@ -2284,7 +2286,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa visibility: layerInfo.visible }, minzoom: minzoom || 0, - maxzoom: maxzoom || 22 + maxzoom: maxzoom || this.map.getMaxZoom() + 1 }); if (addToMap) { this._addLayerSucceeded({ layerInfo, features }); @@ -2491,7 +2493,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa paint: layerStyle.style, layout: layerStyle.layout || {}, minzoom: minzoom || 0, - maxzoom: maxzoom || 22 + maxzoom: maxzoom || this.map.getMaxZoom() + 1 }; if (filter) { style.filter = filter; @@ -2506,7 +2508,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa parentLayerId, visibility = true, minzoom = 0, - maxzoom = 22, + maxzoom, isIserver = false, tileSize = 256, bounds @@ -2515,7 +2517,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa type: 'raster', tiles: url, minzoom: minzoom || 0, - maxzoom: maxzoom || 22, + maxzoom: maxzoom || this.map.getMaxZoom() + 1, tileSize: isIserver ? this.rasterTileSize : tileSize, rasterSource: isIserver ? 'iserver' : '', prjCoordSys: @@ -2538,7 +2540,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa type: 'raster', source: sourceId, minzoom: minzoom || 0, - maxzoom: maxzoom || 22, + maxzoom: maxzoom || this.map.getMaxZoom() + 1, layout: { visibility: this._getVisibility(visibility) } @@ -2564,11 +2566,18 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa this._addOverlayToMap({ type: 'LINE', source, layerID, parentLayerId, layerStyle: lineStyle, minzoom, maxzoom }); } + _getThemeField(layerInfo) { + if (layerInfo.layerType === 'VECTOR') { + return '' + } + return layerInfo.layerType === 'HEAT' ? layerInfo.themeSetting.weight : layerInfo.themeSetting.themeField + } + _initLegendConfigInfo(layerInfo, style) { const legendItem = { layerId: layerInfo.layerID, layerTitle: layerInfo.layerID, - themeField: layerInfo.layerType === 'HEAT' ? layerInfo.themeSetting.weight : layerInfo.themeSetting.themeField, + themeField: this._getThemeField(layerInfo), styleGroup: style }; @@ -2585,6 +2594,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa switch (layerInfo.layerType) { case 'UNIQUE': + case 'VECTOR': legendItem.styleGroup = legendItem.styleGroup.map((styleGroup) => { return { fieldValue: styleGroup.value, @@ -2713,7 +2723,7 @@ export function createWebMapV2Extending(SuperClass, { MapManager, mapRepo, crsMa visibility: layerInfo.visible ? 'visible' : 'none' }, minzoom: minzoom || 0, - maxzoom: maxzoom || 22 + maxzoom: maxzoom || this.map.getMaxZoom() + 1 }); this._addLayerSucceeded(); } diff --git a/src/common/mapping/WebMapV2Base.js b/src/common/mapping/WebMapV2Base.js index bc227cbd41..7ffe806283 100644 --- a/src/common/mapping/WebMapV2Base.js +++ b/src/common/mapping/WebMapV2Base.js @@ -722,6 +722,16 @@ export function createWebMapV2BaseExtending(SuperClass = Events, fireField = 'tr return styleGroup; } + + getVectorStyleGroup(layerInfo) { + const color = layerInfo.style.fillColor || layerInfo.style.strokeColor; + const styleGroup = [{ + color: color, + style: layerInfo.style, + value: layerInfo.name + }] + return styleGroup; + } transformFeatures(features) { features && diff --git a/src/common/mapping/utils/AppreciableLayerBase.js b/src/common/mapping/utils/AppreciableLayerBase.js index 45bb6aa851..ec088a003a 100644 --- a/src/common/mapping/utils/AppreciableLayerBase.js +++ b/src/common/mapping/utils/AppreciableLayerBase.js @@ -1,12 +1,12 @@ import { Events } from '../../commontypes'; import SourceModel from './SourceModel'; import { createAppreciableLayerId, getLayerInfosFromCatalogs } from './util'; +import cloneDeep from 'lodash.clonedeep'; export class AppreciableLayerBase extends Events { constructor(options = {}) { super(); this.map = options.map; - this.layers = options.layers || []; this.appendLayers = options.appendLayers || false; this.unexpectedSourceNames = [ 'tdt-search-', @@ -21,12 +21,23 @@ export class AppreciableLayerBase extends Events { this.layersVisibleMap = new Map(); this.eventTypes = ['layerupdatechanged']; this._styleDataUpdatedHandler = this._styleDataUpdatedHandler.bind(this); + this.baseLayerInfoOnMap = null; + this.setLayers(options.layers); + this._initBaseLayerInfo(options.layers); } - setLayers(layers) { + setLayers(layers = []) { this.layers = layers; } + setDefaultBaseLayerInfo(baseLayerInfo) { + this.baseLayerInfoOnMap = baseLayerInfo; + } + + setBaseLayer() { + throw new Error('setBaseLayer is not implemented'); + } + createLayerCatalogs() { throw new Error('createLayerCatalogs is not implemented'); } @@ -39,6 +50,14 @@ export class AppreciableLayerBase extends Events { throw new Error('initLayers is not implemented'); } + changeBaseLayer(layer) { + if (this.map) { + this._removeBaseLayer(); + this._addBaseLayer(layer); + return cloneDeep(this.baseLayerInfoOnMap); + } + } + createAppreciableLayers() { const detailLayers = this.initLayers(); return this._initAppreciableLayers(detailLayers); @@ -335,4 +354,111 @@ export class AppreciableLayerBase extends Events { } return topLayers.concat(autoLayers, bottomLayers); } + + _addBaseLayer(layerItem) { + const { layers, sources } = layerItem; + const renderSources = {}; + Object.keys(sources).forEach(sourceId => { + let nextSourceId = sourceId; + if (this.map.getSource(sourceId)) { + renderSources[sourceId] = `${sourceId}_${+new Date()}`; + nextSourceId = renderSources[sourceId]; + } + this.map.addSource(nextSourceId, sources[sourceId]); + }); + const layersToAdd = []; + layers.forEach(layer => { + let { beforeId } = layer; + if (!beforeId) { + const styles = this.map.getStyle(); + beforeId = styles.layers[0] && styles.layers[0].id; + } + const layerToAdd = Object.assign({}, layer); + delete layerToAdd.beforeId; + const sourceId = layerToAdd.source; + if (renderSources[sourceId]) { + layerToAdd.source = renderSources[sourceId]; + } + if (this.map.getLayer(layerToAdd.id)) { + const nextLayerId = `${layerToAdd.id}_${layerToAdd.source || +new Date()}`; + layerToAdd.id = nextLayerId; + } + layersToAdd.push({ + layer: layerToAdd, + beforeId + }); + }); + this.baseLayerInfoOnMap = { + ...layerItem, + layers: layersToAdd.map(item => Object.assign({}, item.layer)), + sources: Object.keys(layerItem.sources).reduce((sources, sourceId) => { + let source = sourceId; + if (renderSources[source]) { + source = renderSources[source]; + } + sources[source] = renderSources[sourceId]; + return sources; + }, {}) + }; + this.setBaseLayer({ ...this.baseLayerInfoOnMap }); + layersToAdd.forEach(({ layer, beforeId }) => { + this.map.addLayer(layer, beforeId); + }) + } + + _removeBaseLayer() { + if (this.baseLayerInfoOnMap) { + const { layers, sources } = this.baseLayerInfoOnMap; + const layersIds = layers.map(item => item.id); + const sourceIds = Object.keys(sources); + layersIds.forEach(layerId => { + if (this.map.getLayer(layerId)) { + this.map.removeLayer(layerId); + } + }); + sourceIds.forEach(sourceId => { + if (this.map.getSource(sourceId)) { + this.map.removeSource(sourceId); + } + }); + } + } + + _initBaseLayerInfo(layers) { + if (layers && layers.length && !this.baseLayerInfoOnMap) { + const firstLayer = this.layers[0]; + const baseLayer = firstLayer; + const layerList = this.map.getStyle().layers; + const baseLayersOnMap = baseLayer.renderLayers.map((layerId) => { + const nextLayer = layerList.find(item => item.id === layerId); + if (nextLayer) { + const layerIndex = layerList.findIndex(item => item.id === layerId); + const nextLayerIndex = layerIndex + 1; + if (layerList[nextLayerIndex]) { + nextLayer.beforeId = layerList[nextLayerIndex].id; + } + if (!nextLayer.metadata || !nextLayer.metadata.SM_Layer_Title) { + nextLayer.metadata = { + ...nextLayer.metadata, + SM_Layer_Title: baseLayer.title + }; + } + } + return nextLayer; + }).filter(Boolean); + const sourcesMap = this.map.getStyle().sources; + this.setDefaultBaseLayerInfo({ + id: `__default__${baseLayer.id}`, + title: baseLayer.title, + layers: baseLayersOnMap, + sources: baseLayersOnMap.reduce((sources, layer) => { + const sourceId = layer.source; + if (sourceId && !sources[sourceId]) { + sources[sourceId] = sourcesMap[sourceId]; + } + return sources; + }, {}) + }); + } + } } diff --git a/src/common/mapping/utils/SourceListModelV2.js b/src/common/mapping/utils/SourceListModelV2.js index 2cbcb71966..e10d7ae28c 100644 --- a/src/common/mapping/utils/SourceListModelV2.js +++ b/src/common/mapping/utils/SourceListModelV2.js @@ -47,6 +47,21 @@ export class SourceListModelV2 extends AppreciableLayerBase { return this.concatExpectLayers(selfLayers, selfLayerIds, nextLayers); } + setBaseLayer(layerItem) { + const nextLayers = this.layers.slice(1); + const firstLayer = layerItem.layers[0] || {}; + const defaultId = firstLayer.id || ''; + const baseLayer = { + id: layerItem.id || defaultId, + visible: true, + name: layerItem.title || defaultId, + title: layerItem.title || defaultId, + renderLayers: layerItem.layers.map(item => item.id) + } + nextLayers.unshift(baseLayer); + this.setLayers(nextLayers); + } + _isBelongToMapJSON(layerFromMapJSON, layerOnMap) { return ( layerFromMapJSON.renderLayers && layerFromMapJSON.renderLayers.some((subLayerId) => subLayerId === layerOnMap.id) diff --git a/src/common/mapping/utils/SourceListModelV3.js b/src/common/mapping/utils/SourceListModelV3.js index 82b1ca0cdf..7ce035debd 100644 --- a/src/common/mapping/utils/SourceListModelV3.js +++ b/src/common/mapping/utils/SourceListModelV3.js @@ -1,4 +1,3 @@ - import { AppreciableLayerBase } from './AppreciableLayerBase'; import { getLayerCatalogRenderLayers, getLayerInfosFromCatalogs, getMainLayerFromCatalog } from './util'; @@ -6,17 +5,23 @@ export class SourceListModelV3 extends AppreciableLayerBase { constructor(options = {}) { super(options); this._mapInfo = options.mapInfo; - this._layerCatalog = options.mapInfo.metadata.layerCatalog; this._mapResourceInfo = options.mapResourceInfo; this._l7LayerUtil = options.l7LayerUtil; this._legendList = options.legendList; // chart 统计图表 point-extrusion 柱状图 this._immutableTopOrderLayers = ['chart', 'point-extrusion']; + const layerCatalogs = options.mapInfo.metadata.layerCatalog; + this.setLayerCatalog(layerCatalogs); const layers = this._generateLayers(); this.setLayers(layers); + this.setDefaultBaseLayerInfo(this._generateBaseLayerInfo(layerCatalogs, layers)); this.initDatas(); } + setLayerCatalog(catalogs) { + this._layerCatalog = catalogs; + } + createLayerCatalogs() { const appreciableLayers = this.getLayers(false); const sourceList = this._createSourceCatalogs(this._layerCatalog, appreciableLayers); @@ -47,6 +52,49 @@ export class SourceListModelV3 extends AppreciableLayerBase { return this.concatExpectLayers(selfLayers, selfLayerIds, nextLayers); } + setBaseLayer(layerItem) { + const nextLayers = this.layers.slice(); + const nextLayerCatalog = this._layerCatalog.slice(); + const originBaseLayerCatalog = nextLayerCatalog.pop(); + this._removeBaseLayerRenderLayers(originBaseLayerCatalog, nextLayers); + const baseLayers = layerItem.layers.map((layer) => { + const title = layer.metadata && layer.metadata.title; + return { + ...layer, + layerInfo: { + id: layer.id, + title: title || layer.id, + renderLayers: [layer.id] + } + }; + }); + nextLayers.unshift(...baseLayers); + const firstLayer = layerItem.layers[0] || {}; + const defaultId = firstLayer.id || ''; + const baseLayerCatalog = { + id: defaultId, + title: layerItem.title || defaultId, + type: 'basic', + visible: true + }; + if (layerItem.layers.length > 1) { + baseLayerCatalog.id = layerItem.id || defaultId; + baseLayerCatalog.type = 'group'; + baseLayerCatalog.children = layerItem.layers.map((layer) => { + const title = layer.metadata && layer.metadata.title; + return { + id: layer.id, + title: title || layer.id, + type: 'basic', + visible: true + }; + }); + } + nextLayerCatalog.push(baseLayerCatalog); + this.setLayerCatalog(nextLayerCatalog); + this.setLayers(nextLayers); + } + _createSourceCatalogs(catalogs, appreciableLayers) { const formatCatalogs = catalogs.map((catalog) => { let formatItem; @@ -60,7 +108,7 @@ export class SourceListModelV3 extends AppreciableLayerBase { visible }; } else { - const renderLayers = getLayerCatalogRenderLayers(parts, id, this._mapInfo.layers); + const renderLayers = getLayerCatalogRenderLayers(parts, id, this.layers); const matchLayer = appreciableLayers.find((layer) => layer.id === renderLayers[0]); this.removeLayerExtralFields([matchLayer]); formatItem = Object.assign({}, matchLayer); @@ -75,12 +123,17 @@ export class SourceListModelV3 extends AppreciableLayerBase { const projectCataglogs = getLayerInfosFromCatalogs(catalogs, 'catalogType'); const metadataCatalogs = getLayerInfosFromCatalogs(this._mapInfo.metadata.layerCatalog); const l7MarkerLayers = this._l7LayerUtil.getL7MarkerLayers(); - const layerDatas = metadataCatalogs.map(layerCatalog => { + const layerDatas = metadataCatalogs.map((layerCatalog) => { const renderLayers = getLayerCatalogRenderLayers(layerCatalog.parts, layerCatalog.id, this._mapInfo.layers); const layer = getMainLayerFromCatalog(layerCatalog.parts, layerCatalog.id, this._mapInfo.layers); - const layerInfo = { id: layer.id, title: layerCatalog.title, renderLayers, reused: layer.metadata && layer.metadata.reused }; + const layerInfo = { + id: layer.id, + title: layerCatalog.title, + renderLayers, + reused: layer.metadata && layer.metadata.reused + }; const matchProjectCatalog = projectCataglogs.find((item) => item.id === layerCatalog.id) || {}; - const { msDatasetId } = matchProjectCatalog; + const { msDatasetId, relationMsDatasetId } = matchProjectCatalog; let dataSource = {}; if (msDatasetId) { for (const data of datas) { @@ -89,7 +142,7 @@ export class SourceListModelV3 extends AppreciableLayerBase { dataSource = { serverId: matchData.datasetId, type: data.sourceType - } + }; if (data.sourceType === 'REST_DATA') { const [serverUrl, datasourceName] = data.url.split('/rest/data/datasources/'); dataSource.url = `${serverUrl}/rest/data`; @@ -100,6 +153,24 @@ export class SourceListModelV3 extends AppreciableLayerBase { } } } + if (relationMsDatasetId) { + const currentData = datas.find(data => data.datasets.find(dataset => dataset.msDatasetId === relationMsDatasetId)); + const sourceType = currentData && currentData.sourceType; + if (sourceType === 'WFS') { + const withCredential = currentData.withCredential; + let url = currentData.url; + if (withCredential && withCredential.key && withCredential.value) { + const separator = url.includes('?') ? '&' : '?'; + url = `${url}${separator}${withCredential.key}=${withCredential.value}` + } + const dataset = currentData.datasets.find(dataset => dataset.msDatasetId === relationMsDatasetId); + Object.assign(dataSource, { + type: 'WFS', + datasetName: dataset.datasetName, + url + }); + } + } const sourceOnMap = this.map.getSource(layer.source); if (!Object.keys(dataSource).length && sourceOnMap && sourceOnMap.type === 'vector') { const matchSource = this._mapInfo.sources[layer.source] || sourceOnMap; @@ -127,7 +198,7 @@ export class SourceListModelV3 extends AppreciableLayerBase { if (validThemeFields.length > 0) { layerInfo.themeSetting = { themeField: validThemeFields }; } - if (this._immutableTopOrderLayers.some(type => type === layer.type)) { + if (this._immutableTopOrderLayers.some((type) => type === layer.type)) { layerInfo.metadata = Object.assign({}, layer.metadata, { SM_Layer_Order: 'top' }); } return Object.assign({}, layer, { layerInfo }); @@ -135,4 +206,70 @@ export class SourceListModelV3 extends AppreciableLayerBase { layerDatas.reverse(); return layerDatas; } + + _generateBaseLayerInfo(layerCatalog, layers) { + const nextLayerCatalog = layerCatalog.slice(); + const originBaseLayerCatalog = nextLayerCatalog.pop(); + if (!originBaseLayerCatalog) { + return; + } + const renderLayers = this._getBaseLayerRenderLayers(originBaseLayerCatalog, layers); + const baseLayersOnMap = renderLayers.map((layer) => { + const nextLayer = { ...layer }; + delete nextLayer.layerInfo; + const layerIndex = layers.findIndex((item) => item.id === layer.id); + const nextLayerIndex = layerIndex + 1; + if (layers[nextLayerIndex]) { + nextLayer.beforeId = layers[nextLayerIndex].id; + } + return nextLayer; + }); + const sourcesMap = this.map.getStyle().sources; + return { + id: `__default__${originBaseLayerCatalog.id}`, + title: originBaseLayerCatalog.title, + layers: baseLayersOnMap, + sources: baseLayersOnMap.reduce((sources, layer) => { + const sourceId = layer.source; + if (sourceId && !sources[sourceId]) { + sources[sourceId] = sourcesMap[sourceId]; + } + return sources; + }, {}) + }; + } + + _getBaseLayerRenderLayers(layerCatalog, layersOnMap) { + const uniqueSet = new Set(); + const collectIds = (node) => { + if (node.children) { + node.children.forEach((child) => collectIds(child)); + } + const parts = node.parts || [node.id]; + parts.forEach(part => uniqueSet.add(part)); + }; + collectIds(layerCatalog); + + return layersOnMap.filter(layer => uniqueSet.has(layer.id)); + } + + _removeBaseLayerRenderLayers(layerCatalog, layersOnMap) { + const deleteSet = new Set(); + const collectIds = (node) => { + if (node.children) { + node.children.forEach((child) => collectIds(child)); + } + const parts = node.parts || [node.id]; + parts.forEach(part => deleteSet.add(part)); + }; + collectIds(layerCatalog); + + let writeIndex = 0; + for (let i = 0; i < layersOnMap.length; i++) { + if (!deleteSet.has(layersOnMap[i].id)) { + layersOnMap[writeIndex++] = layersOnMap[i]; + } + } + layersOnMap.length = writeIndex; + } } diff --git a/src/common/util/FetchRequest.js b/src/common/util/FetchRequest.js index ef4c3db091..703d11eeb4 100644 --- a/src/common/util/FetchRequest.js +++ b/src/common/util/FetchRequest.js @@ -514,14 +514,7 @@ export var FetchRequest = { } if (url.indexOf('.json') === -1 && !options.withoutFormatSuffix) { - if (url.indexOf('?') < 0) { - url += '.json'; - } else { - var urlArrays = url.split('?'); - if (urlArrays.length === 2) { - url = urlArrays[0] + '.json?' + urlArrays[1]; - } - } + url = Util.handleUrlSuffix(url); } if (options && options.proxy) { if (typeof options.proxy === 'function') { diff --git a/src/mapboxgl/mapping/WebMap.js b/src/mapboxgl/mapping/WebMap.js index 9f6bfc9d59..2dc2a2a4a0 100644 --- a/src/mapboxgl/mapping/WebMap.js +++ b/src/mapboxgl/mapping/WebMap.js @@ -49,6 +49,7 @@ import { GraticuleLayer } from '../overlay/GraticuleLayer'; * @param {boolean} [options.isSuperMapOnline] - 是否是 SuperMap Online 地图。 * @param {string} [options.iportalServiceProxyUrlPrefix] - iportal的代理服务地址前缀。 * @param {string|boolean} [options.proxy] - HTTP 请求代理地址 。布尔值表示使用 iPortal 默认代理地址。 + * @param {boolean} [options.preferServer=false] - 当图层数据来源为SuperMap iServer RestData服务, 使用服务器直接返回geojson。 * @param {Object} mapOptions - 地图参数。 * @param {Array} [mapOptions.center] - 中心点。 * @param {number} [mapOptions.zoom] - 缩放级别。 diff --git a/src/mapboxgl/mapping/webmap/CRSManager.js b/src/mapboxgl/mapping/webmap/CRSManager.js index f5e4bde861..6029596c8d 100644 --- a/src/mapboxgl/mapping/webmap/CRSManager.js +++ b/src/mapboxgl/mapping/webmap/CRSManager.js @@ -1,5 +1,11 @@ import mapboxgl from 'mapbox-gl'; +const equivalenceMap = { + 'EPSG:4490': 'EPSG:4326', + 'EPSG:4326': 'EPSG:4490', + 'EPSG:3857': 'EPSG:900913', + 'EPSG:900913': 'EPSG:3857' +}; export class CRSManager { constructor(proj4) { this.proj4 = proj4; @@ -7,7 +13,9 @@ export class CRSManager { } isSameProjection(map, epsgCode) { - return map.getCRS().epsgCode === epsgCode; + const mapEpsgCode = map.getCRS().epsgCode; + return mapEpsgCode === epsgCode || + (equivalenceMap[mapEpsgCode] === epsgCode && equivalenceMap[epsgCode] === mapEpsgCode); } getProj4() { diff --git a/src/mapboxgl/services/FeatureService.js b/src/mapboxgl/services/FeatureService.js index 6b957d5ac7..d2f9461ffe 100644 --- a/src/mapboxgl/services/FeatureService.js +++ b/src/mapboxgl/services/FeatureService.js @@ -27,6 +27,7 @@ import { FeatureService as CommonFeatureService } from '@supermapgis/iclient-com * @param {boolean} [options.withCredentials=false] - 请求是否携带 cookie。 * @param {boolean} [options.crossOrigin] - 是否允许跨域请求。 * @param {Object} [options.headers] - 请求头。 + * @param {boolean} [options.preferServer] - 当resultFormat=DataFormat.GEOJSON时,使用服务器直接返回geojson。 * @usage */ export class FeatureService extends ServiceBase { diff --git a/test/common/mapping/utils/SourceListModelV2Spec.js b/test/common/mapping/utils/SourceListModelV2Spec.js index e6927c0763..48cf5fa202 100644 --- a/test/common/mapping/utils/SourceListModelV2Spec.js +++ b/test/common/mapping/utils/SourceListModelV2Spec.js @@ -1,7 +1,32 @@ import { SourceListModelV2 } from '../../../../src/common/mapping/utils/SourceListModelV2'; describe('SourceListV2', () => { - let layers, map, mockEvents; + let layers, sources, map, mockEvents, overlayLayersManager; + const baseLayerInfo = { + id: 'wmts100', + title: 'wmts100', + layers: [ + { + id: 'wmts100', + type: 'raster', + source: 'wmts100', + minzoom: 0, + maxzoom: 12 + } + ], + sources: { + wmts100: { + type: 'raster', + tiles: [ + 'http:/localhost:8195/portalproxy/97d2edb85b0cb5d4/iserver/services/map-China100-2/wmts100?service=WMTS&request=GetTile&version=1.0.0&style=default&layer=China&tilematrixSet=Custom_China&format=image%2Fpng&tilematrix={z}&tilerow={y}&tilecol={x}' + ], + maxzoom: 12, + tileSize: 256, + bounds: [-180, -85.05112877980652, 180, 85.05112877980648], + minzoom: 0 + } + } + }; beforeEach(() => { mockEvents = {}; @@ -170,34 +195,51 @@ describe('SourceListV2', () => { } } ]; + sources = { + graticuleLayer_1723443238046_line: { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [] + } + } + }; + overlayLayersManager = { + graticuleLayer_1723443238046: { + id: 'graticuleLayer_1723443238046', + overlay: true, + renderingMode: '3d', + type: 'custom', + visible: true, + sourceId: 'graticuleLayer_1723443238046_line' + } + }; map = { + addLayer: function (layer) { + layers.push(layer); + }, + addSource(sourceId, source) { + sources[sourceId] = source; + }, getStyle() { return { - layers + layers, + sources }; }, - getSource() { - return { - type: 'geojson', - data: { - type: 'FeatureCollection', - features: [] - } - }; + getSource(id) { + return sources[id]; }, getLayer(id) { return layers.find((layer) => layer.id === id); }, - overlayLayersManager: { - graticuleLayer_1723443238046: { - id: 'graticuleLayer_1723443238046', - overlay: true, - renderingMode: '3d', - type: 'custom', - visible: true, - sourceId: 'graticuleLayer_1723443238046_line' - } + removeLayer(id) { + return layers.splice(layers.findIndex((layer) => layer.id === id), 1); + }, + removeSource(id) { + delete sources[id]; }, + overlayLayersManager, on(type, callback) { mockEvents[type] = callback; }, @@ -561,4 +603,398 @@ describe('SourceListV2', () => { expect(mockEvents.styledata).not.toBeUndefined(); mockEvents.styledata(); }); + + it('changeBaseLayer not complicit', (done) => { + const layersInfo = [ + { + layerType: 'TIANDITU_IMG_3857', + labelLayerVisible: true, + tk: '50599c913367188e6c94e872032f4cf1', + name: '天地图影像', + title: '天地图影像', + renderLayers: ['天地图影像', '天地图影像-tdt-label'], + metadata: { + SM_Layer_Id: '天地图影像' + }, + id: '天地图影像', + visible: true, + reused: false + }, + { + layerType: 'UNIQUE', + visible: true, + themeSetting: { + themeField: 'parent', + customSettings: { + '{"adcode":110000}': { + strokeWidth: 1, + fillColor: '#D53E4F', + fillOpacity: 0.9, + lineDash: 'solid', + strokeColor: '#ffffff', + type: 'POLYGON', + strokeOpacity: 1 + } + }, + colors: ['#D53E4F', '#FC8D59', '#FEE08B', '#FFFFBF', '#E6F598', '#99D594', '#3288BD'] + }, + name: '北京市(3)', + featureType: 'POLYGON', + style: { + strokeWidth: 1, + fillColor: '#D53E4F', + fillOpacity: 0.9, + lineDash: 'solid', + strokeColor: '#ffffff', + type: 'POLYGON', + strokeOpacity: 1 + }, + projection: 'EPSG:4326', + enableFields: [ + 'parent', + 'adcode', + 'level', + 'childrenNum', + 'smpid', + 'centroid', + 'center', + 'subFeatureIndex', + 'name', + 'acroutes' + ], + dataSource: { + accessType: 'DIRECT', + type: 'PORTAL_DATA', + serverId: '1371715657' + }, + layerID: '北京市(3)', + renderLayers: ['北京市(3)', '北京市(3)-strokeLine'], + metadata: { + SM_Layer_Id: '北京市(3)' + }, + id: '北京市(3)', + reused: false + } + ]; + layers = [ + { + id: '天地图影像', + type: 'raster', + source: '天地图影像', + metadata: { + SM_Layer_Id: '天地图影像' + }, + minzoom: 0, + maxzoom: 22, + layout: { + visibility: 'visible' + } + }, + { + id: '天地图影像-tdt-label', + type: 'raster', + source: '天地图影像-tdt-label', + metadata: { + SM_Layer_Id: '天地图影像' + }, + minzoom: 0, + maxzoom: 22, + layout: { + visibility: 'visible' + } + }, + { + id: '北京市(3)', + type: 'fill', + source: '北京市(3)', + metadata: { + SM_Layer_Id: '北京市(3)' + }, + minzoom: 0, + maxzoom: 22, + layout: { + visibility: 'visible' + }, + paint: { + 'fill-color': '#D53E4F', + 'fill-opacity': 0.9 + } + }, + { + id: '北京市(3)-strokeLine', + type: 'line', + source: '北京市(3)', + metadata: { + SM_Layer_Id: '北京市(3)' + }, + minzoom: 0, + maxzoom: 22, + filter: ['all'], + layout: { + visibility: 'visible' + }, + paint: { + 'line-width': 1, + 'line-color': '#ffffff', + 'line-opacity': 1 + } + } + ]; + sources = { + '北京市(3)': { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [] + } + }, + '天地图影像': { + type: 'raster', + tiles: [ + 'https://t0.tianditu.gov.cn/img_w/wmts?tk=50599c913367188e6c94e872032f4cf1&service=WMTS&request=GetTile&style=default&version=1.0.0&layer=img&tilematrixSet=w&format=tiles&width=256&height=256&tilematrix={z}&tilerow={y}&tilecol={x}' + ], + minzoom: 0, + maxzoom: 22, + tileSize: 256, + rasterSource: '', + prjCoordSys: '', + proxy: null, + bounds: [-180, -90, 180, 90] + }, + '天地图影像-tdt-label': { + type: 'raster', + tiles: [ + 'https://t0.tianditu.gov.cn/cia_w/wmts?tk=50599c913367188e6c94e872032f4cf1&service=WMTS&request=GetTile&style=default&version=1.0.0&layer=cia&tilematrixSet=w&format=tiles&width=256&height=256&tilematrix={z}&tilerow={y}&tilecol={x}' + ], + minzoom: 0, + maxzoom: 22, + tileSize: 256, + rasterSource: '', + prjCoordSys: '', + proxy: null, + bounds: [-180, -90, 180, 90] + } + }; + overlayLayersManager = {}; + + const sourceListModel = new SourceListModelV2({ map, layers: layersInfo }); + expect(map.getStyle().layers.some(item => ['天地图影像', '天地图影像-tdt-label'].includes(item.id))).toBeTruthy(); + const layerList = sourceListModel.getLayerCatalog(); + const appreciableLayers = sourceListModel.getLayers(); + expect(layerList.length).toBe(2); + expect(appreciableLayers.length).toBe(2); + const nextBaseLayerInfo = sourceListModel.changeBaseLayer(baseLayerInfo); + expect(nextBaseLayerInfo).toBeTruthy(); + expect(nextBaseLayerInfo.layers.length).toBe(1); + expect(nextBaseLayerInfo.layers).toEqual(baseLayerInfo.layers); + expect(map.getStyle().layers.some(item => ['天地图影像', '天地图影像-tdt-label'].includes(item.id))).toBeFalsy(); + done(); + }); + + it('changeBaseLayer complicit', (done) => { + const layersInfo = [ + { + layerType: 'raster', + name: 'wmts100', + title: 'wmts100', + renderLayers: ['wmts100'], + metadata: { + SM_Layer_Id: 'wmts100' + }, + id: 'wmts100', + visible: true, + reused: false + }, + { + layerType: 'TIANDITU_IMG_3857', + labelLayerVisible: true, + tk: '50599c913367188e6c94e872032f4cf1', + name: '天地图影像', + title: '天地图影像', + renderLayers: ['天地图影像', '天地图影像-tdt-label'], + metadata: { + SM_Layer_Id: '天地图影像' + }, + id: '天地图影像', + visible: true, + reused: false + }, + { + layerType: 'UNIQUE', + visible: true, + themeSetting: { + themeField: 'parent', + customSettings: { + '{"adcode":110000}': { + strokeWidth: 1, + fillColor: '#D53E4F', + fillOpacity: 0.9, + lineDash: 'solid', + strokeColor: '#ffffff', + type: 'POLYGON', + strokeOpacity: 1 + } + }, + colors: ['#D53E4F', '#FC8D59', '#FEE08B', '#FFFFBF', '#E6F598', '#99D594', '#3288BD'] + }, + name: '北京市(3)', + featureType: 'POLYGON', + style: { + strokeWidth: 1, + fillColor: '#D53E4F', + fillOpacity: 0.9, + lineDash: 'solid', + strokeColor: '#ffffff', + type: 'POLYGON', + strokeOpacity: 1 + }, + projection: 'EPSG:4326', + enableFields: [ + 'parent', + 'adcode', + 'level', + 'childrenNum', + 'smpid', + 'centroid', + 'center', + 'subFeatureIndex', + 'name', + 'acroutes' + ], + dataSource: { + accessType: 'DIRECT', + type: 'PORTAL_DATA', + serverId: '1371715657' + }, + layerID: '北京市(3)', + renderLayers: ['北京市(3)', '北京市(3)-strokeLine'], + metadata: { + SM_Layer_Id: '北京市(3)' + }, + id: '北京市(3)', + reused: false + } + ]; + layers = [ + ...baseLayerInfo.layers, + { + id: '天地图影像', + type: 'raster', + source: '天地图影像', + metadata: { + SM_Layer_Id: '天地图影像' + }, + minzoom: 0, + maxzoom: 22, + layout: { + visibility: 'visible' + } + }, + { + id: '天地图影像-tdt-label', + type: 'raster', + source: '天地图影像-tdt-label', + metadata: { + SM_Layer_Id: '天地图影像' + }, + minzoom: 0, + maxzoom: 22, + layout: { + visibility: 'visible' + } + }, + { + id: '北京市(3)-strokeLine', + type: 'line', + source: '北京市(3)', + metadata: { + SM_Layer_Id: '北京市(3)' + }, + minzoom: 0, + maxzoom: 22, + filter: ['all'], + layout: { + visibility: 'visible' + }, + paint: { + 'line-width': 1, + 'line-color': '#ffffff', + 'line-opacity': 1 + } + } + ]; + sources = { + '北京市(3)': { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [] + } + }, + '天地图影像': { + type: 'raster', + tiles: [ + 'https://t0.tianditu.gov.cn/img_w/wmts?tk=50599c913367188e6c94e872032f4cf1&service=WMTS&request=GetTile&style=default&version=1.0.0&layer=img&tilematrixSet=w&format=tiles&width=256&height=256&tilematrix={z}&tilerow={y}&tilecol={x}' + ], + minzoom: 0, + maxzoom: 22, + tileSize: 256, + rasterSource: '', + prjCoordSys: '', + proxy: null, + bounds: [-180, -90, 180, 90] + }, + '天地图影像-tdt-label': { + type: 'raster', + tiles: [ + 'https://t0.tianditu.gov.cn/cia_w/wmts?tk=50599c913367188e6c94e872032f4cf1&service=WMTS&request=GetTile&style=default&version=1.0.0&layer=cia&tilematrixSet=w&format=tiles&width=256&height=256&tilematrix={z}&tilerow={y}&tilecol={x}' + ], + minzoom: 0, + maxzoom: 22, + tileSize: 256, + rasterSource: '', + prjCoordSys: '', + proxy: null, + bounds: [-180, -90, 180, 90] + }, + ...baseLayerInfo.sources + }; + overlayLayersManager = {}; + + const sourceListModel = new SourceListModelV2({ map, layers: layersInfo }); + expect(map.getStyle().layers.some(item => ['天地图影像', '天地图影像-tdt-label'].includes(item.id))).toBeTruthy(); + expect(map.getStyle().layers.some(item => ['wmts100'].includes(item.id))).toBeTruthy(); + let layerList = sourceListModel.getLayerCatalog(); + let appreciableLayers = sourceListModel.getLayers(); + expect(layerList.length).toBe(3); + expect(layerList[layerList.length - 1].id).toBe('wmts100'); + expect(appreciableLayers.length).toBe(3); + expect(appreciableLayers[0].id).toBe('wmts100'); + const sameBaseLayer = { + id: 'sameBaseLayer', + layers: layers.slice(1, 3).map(item => { + const nextItem = Object.assign({}, item); + nextItem.metadata = { SM_Layer_Id: 'sameBaseLayer' }; + return nextItem; + }), + sources: { + '天地图影像': sources['天地图影像'], + '天地图影像-tdt-label': sources['天地图影像-tdt-label'] + } + } + const nextBaseLayerInfo = sourceListModel.changeBaseLayer(sameBaseLayer); + expect(nextBaseLayerInfo).toBeTruthy(); + expect(nextBaseLayerInfo.layers.length).toBe(2); + expect(nextBaseLayerInfo.layers).not.toEqual(sameBaseLayer.layers); + expect(map.getStyle().layers.some(item => ['天地图影像', '天地图影像-tdt-label'].includes(item.id))).toBeTruthy(); + expect(map.getStyle().layers.some(item => [/天地图影像_\d+$/, /天地图影像-tdt-label_\d+$/].some(reg => reg.test(item.id)))).toBeTruthy(); + expect(map.getStyle().layers.some(item => ['wmts100'].includes(item.id))).toBeFalsy(); + layerList = sourceListModel.getLayerCatalog(); + appreciableLayers = sourceListModel.getLayers(); + expect(layerList.length).toBe(3); + expect(layerList[layerList.length - 1].id).toBe('sameBaseLayer'); + expect(appreciableLayers.length).toBe(3); + expect(appreciableLayers[0].id).toBe('sameBaseLayer'); + done(); + }); }); diff --git a/test/common/mapping/utils/SourceListModelV3Spec.js b/test/common/mapping/utils/SourceListModelV3Spec.js index c5d801c8b5..3b99ac7d4a 100644 --- a/test/common/mapping/utils/SourceListModelV3Spec.js +++ b/test/common/mapping/utils/SourceListModelV3Spec.js @@ -1,9 +1,140 @@ import { SourceListModelV3 } from '../../../../src/common/mapping/utils/SourceListModelV3'; import { isL7Layer } from '../../../../src/common/mapping/utils/L7LayerUtil'; import '../../../resources/WebMapV3.js'; +import cloneDeep from 'lodash.clonedeep'; describe('SourceListV3', () => { - let map, layers, mockEvents; + let map, layers, sources, mockEvents, overlayLayersManager; + const baseLayerInfo = { + id: 'wmts100', + title: 'wmts100', + layers: [ + { + id: 'wmts100', + type: 'raster', + source: 'wmts100', + minzoom: 0, + maxzoom: 12 + } + ], + sources: { + wmts100: { + type: 'raster', + tiles: [ + 'http:/localhost:8195/portalproxy/97d2edb85b0cb5d4/iserver/services/map-China100-2/wmts100?service=WMTS&request=GetTile&version=1.0.0&style=default&layer=China&tilematrixSet=Custom_China&format=image%2Fpng&tilematrix={z}&tilerow={y}&tilecol={x}' + ], + maxzoom: 12, + tileSize: 256, + bounds: [-180, -85.05112877980652, 180, 85.05112877980648], + minzoom: 0 + } + } + }; + const changeBaseLayerMapInfo = { + metadata: { + layerCatalog: [ + { + visible: true, + parts: ['北京市住宅小区'], + id: 'layer_北京市住宅小区_1754359974753_24', + title: '北京市住宅小区', + type: 'composite' + }, + { + visible: true, + children: [ + { + visible: true, + id: 'ms_TIANDITU_IMG_3857_label', + title: 'ms_TIANDITU_IMG_3857_label', + type: 'basic' + }, + { + visible: true, + id: 'TIANDITU_IMG_3857', + title: 'TIANDITU_IMG_3857', + type: 'basic' + } + ], + id: 'group_tianditu_img_3857_1754377584218_382', + title: 'tianditu_img_3857', + type: 'group' + } + ] + }, + sources: { + ms_TIANDITU_IMG_3857_label: { + tiles: [ + 'https://t0.tianditu.gov.cn/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=50599c913367188e6c94e872032f4cf1&host=172.16.14.44:8190' + ], + tileSize: 256, + attribution: '', + bounds: [-180, -90, 180, 90], + type: 'raster' + }, + ms_1750973565_1754359974753_23: { + tiles: [ + 'http://localhost:8190/iportal/web/datas/1750973565/structureddata/tiles/{z}/{x}/{y}.mvt?epsgCode=3857&returnedFieldNames=%5B%22smpid%22%2C%22%E5%B0%8F%E5%8C%BA%E5%90%8D%22%2C%22SmGeometrySize%22%2C%22%E5%B9%B4%E4%BB%A3%22%2C%22%E5%8D%95%E4%BB%B7%22%2C%22%E6%A5%BC%E5%B1%82%22%2C%22SmID%22%2C%22%E6%80%BB%E4%BB%B7%22%2C%22SmUserID%22%2C%22%E6%88%B7%E5%9E%8B%22%2C%22%E6%9C%9D%E5%90%91%22%2C%22%E5%9C%B0%E5%9D%80%22%2C%22SmY%22%2C%22SmX%22%2C%22SmLibTileID%22%2C%22%E9%9D%A2%E7%A7%AF%22%5D&geometryFieldName=geometry' + ], + bounds: [115.89763001613301, 39.40606, 117.48732001635402, 40.6500100064203], + type: 'vector' + }, + TIANDITU_IMG_3857: { + tiles: [ + 'https://t0.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=50599c913367188e6c94e872032f4cf1&host=172.16.14.44:8190' + ], + tileSize: 256, + attribution: '', + bounds: [-180, -90, 180, 90], + type: 'raster' + } + }, + crs: 'EPSG:3857', + center: [116.22715983919534, 39.878220196575874], + zoom: 8.79189646012174, + glyphs: {}, + version: '3.3.2', + maxzoom: 19, + name: '无标题地图-tianditu', + layers: [ + { + maxzoom: 19, + id: 'TIANDITU_IMG_3857', + source: 'TIANDITU_IMG_3857', + type: 'raster', + minzoom: 0 + }, + { + layout: { + visibility: 'visible' + }, + maxzoom: 19, + id: 'ms_TIANDITU_IMG_3857_label', + source: 'ms_TIANDITU_IMG_3857_label', + type: 'raster', + minzoom: 0 + }, + { + metadata: {}, + maxzoom: 24, + paint: { + 'circle-color': '#EE4D5A', + 'circle-opacity': 0.9, + 'circle-translate-anchor': 'map', + 'circle-radius': 4, + 'circle-translate': [0, 0] + }, + id: '北京市住宅小区', + source: 'ms_1750973565_1754359974753_23', + 'source-layer': '1750973565$geometry', + type: 'circle', + minzoom: 0 + } + ], + sprite: 'http://localhost:8190/iportal/web/maps/1874751978/sprites/sprite', + pitch: 0, + minzoom: 0 + }; beforeEach(() => { mockEvents = {}; @@ -111,7 +242,7 @@ describe('SourceListV3', () => { 'line-opacity': 0.8 } }, - + { id: 'mapbox-gl-draw', type: 'line', @@ -172,34 +303,104 @@ describe('SourceListV3', () => { } } ]; + sources = { + CHINA_DARK: { + type: 'raster', + tiles: [] + }, + 'test-source': { + type: 'raster', + tiles: [] + }, + 'tracklayer-1-line': { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [] + } + }, + graticuleLayer_1_line: { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [] + } + }, + 'tdt-search-line': { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [] + } + }, + 'tdt-route-line': { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [] + } + }, + smmeasure: { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [] + } + }, + 'mapbox-gl-draw': { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [] + } + }, + graticuleLayer_1723443238046_line: { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [] + } + } + }; + overlayLayersManager = { + graticuleLayer_1723443238046: { + id: 'graticuleLayer_1723443238046', + overlay: true, + renderingMode: '3d', + type: 'custom', + visible: true, + sourceId: 'graticuleLayer_1723443238046_line' + } + }; map = { + addLayer: function (layer) { + layers.push(layer); + }, + addSource(sourceId, source) { + sources[sourceId] = source; + }, getStyle() { return { - layers + layers, + sources }; }, - getSource() { - return { - type: 'geojson', - data: { - type: 'FeatureCollection', - features: [] - } - }; + getSource(id) { + return sources[id]; }, getLayer(id) { return layers.find((layer) => layer.id === id); }, - overlayLayersManager: { - graticuleLayer_1723443238046: { - id: 'graticuleLayer_1723443238046', - overlay: true, - renderingMode: '3d', - type: 'custom', - visible: true, - sourceId: 'graticuleLayer_1723443238046_line' - } + removeLayer(id) { + return layers.splice( + layers.findIndex((layer) => layer.id === id), + 1 + ); + }, + removeSource(id) { + delete sources[id]; }, + overlayLayersManager, on(type, callback) { mockEvents[type] = callback; }, @@ -250,6 +451,146 @@ describe('SourceListV3', () => { done(); }); + it('getLayers - wfs', (done) => { + const mapInfo = { + "metadata": { + "layerCatalog": [{ + "visible": true, + "children": [{ + "visible": true, + "parts": [ + "ProvinceCapital_P@Population#1_0.8" + ], + "id": "layer_ProvinceCapital_P@Population#1_1755679838482_95", + "title": "ProvinceCapital_P@Population#1", + "type": "composite" + }], + "id": "group_PopulationDistribution_wms111_1755679838482_96", + "title": "PopulationDistribution_wms111", + "type": "group" + }, + { + "visible": true, + "children": [{ + "visible": true, + "parts": [ + "Province_L@Population_0.3" + ], + "id": "layer_Province_L@Population_1755679795075_67", + "title": "Province_L@Population", + "type": "composite" + }], + "id": "group_PopulationDistribution_wms111_1755679795075_68", + "title": "PopulationDistribution_wms111", + "type": "group" + }, + { + "visible": true, + "id": "CHINA_DARK", + "title": "中国暗色地图", + "type": "basic" + } + ] + }, + "sources": { + "CHINA_DARK": { + "tiles": [ + "https://maptiles.supermapol.com/iserver/services/map_China/rest/maps/China_Dark/tileimage.png?scale={scale}&x={x}&y={y}&width={width}&height={height}&transparent=true&redirect=false&cacheEnabled=true" + ], + "tileSize": 256, + "attribution": "", + "bounds": [ + -180, + -90, + 180, + 90 + ], + "type": "raster" + }, + "ms_wms_1755679795073_58": { + "tiles": [ + "http://172.16.14.77:8090/iserver/services/map-Population/wms111/PopulationDistribution?service=WMS&request=GetMap&layers=0.3&styles=&format=image/png&transparent=true&version=1.1.1&width=256&height=256&srs=EPSG:3857&bbox={bbox-epsg-3857}" + ], + "tileSize": 256, + "bounds": [ + 79.00794462500004, + 20.0992050343981, + 131.29906509500006, + 53.333658559101075 + ], + "type": "raster" + }, + "ms_wms_1755679838481_90": { + "tiles": [ + "http://172.16.14.77:8090/iserver/services/map-Population/wms111/PopulationDistribution?service=WMS&request=GetMap&layers=0.8&styles=&format=image/png&transparent=true&version=1.1.1&width=256&height=256&srs=EPSG:3857&bbox={bbox-epsg-3857}" + ], + "tileSize": 256, + "bounds": [ + 87.61425523000014, + 19.997037504400623, + 126.53037681500007, + 45.803316189065896 + ], + "type": "raster" + } + }, + "crs": "EPSG:3857", + "center": [ + 99.85865648224853, + 31.86438306758635 + ], + "zoom": 3.826097678440538, + "glyphs": {}, + "version": "3.3.0", + "rootUrl": "http://172.16.15.206:8190/iportal/", + "maxzoom": 12, + "name": "无标题地图", + "viewExtent": [ + 68.52728177830532, + 12.16261318538571, + 131.1900311861916, + 48.1198896120401 + ], + "layers": [{ + "maxzoom": 12, + "id": "CHINA_DARK", + "source": "CHINA_DARK", + "type": "raster", + "minzoom": 0 + }, + { + "metadata": {}, + "id": "Province_L@Population_0.3", + "source": "ms_wms_1755679795073_58", + "type": "raster" + }, + { + "metadata": {}, + "id": "ProvinceCapital_P@Population#1_0.8", + "source": "ms_wms_1755679838481_90", + "type": "raster" + } + ], + "pitch": 0, + "minzoom": 0 + }; + const projInfo = {"catalogs":[{"visible":true,"catalogType":"group","children":[{"catalogType":"layer","relationMsDatasetId":"ms_Population:ProvinceCapital_P_1755679835391_71","serviceLayerId":"0.8","id":"layer_ProvinceCapital_P@Population#1_1755679838482_95","popupInfo":{"elements":[{"fieldName":"SmID","type":"FIELD"},{"fieldName":"SmX","type":"FIELD"},{"fieldName":"SmY","type":"FIELD"},{"fieldName":"SmLibTileID","type":"FIELD"},{"fieldName":"SmUserID","type":"FIELD"},{"fieldName":"SmGeometrySize","type":"FIELD"},{"fieldName":"SmGeoPosition","type":"FIELD"},{"fieldName":"Name","type":"FIELD"}],"title":"ProvinceCapital_P@Population#1"},"title":"ProvinceCapital_P@Population#1","layerSourceType":"WMSService","zoomRange":[0,24],"layersContent":["ProvinceCapital_P@Population#1_0.8"]}],"name":"PopulationDistribution_wms111","id":"group_PopulationDistribution_wms111_1755679838482_96"},{"visible":true,"catalogType":"group","children":[{"catalogType":"layer","relationMsDatasetId":"ms_Population:Province_L_1755679787206_46","serviceLayerId":"0.3","id":"layer_Province_L@Population_1755679795075_67","popupInfo":{"elements":[{"fieldName":"SmID","type":"FIELD"},{"fieldName":"SmLength","type":"FIELD"},{"fieldName":"SmSdriW","type":"FIELD"},{"fieldName":"SmSdriN","type":"FIELD"},{"fieldName":"SmSdriE","type":"FIELD"},{"fieldName":"SmSdriS","type":"FIELD"},{"fieldName":"SmUserID","type":"FIELD"},{"fieldName":"SmTopoError","type":"FIELD"},{"fieldName":"SmGeometrySize","type":"FIELD"},{"fieldName":"SmGeoPosition","type":"FIELD"},{"fieldName":"GB","type":"FIELD"}],"title":"Province_L@Population"},"title":"Province_L@Population","layerSourceType":"WMSService","zoomRange":[0,24],"layersContent":["Province_L@Population_0.3"]}],"name":"PopulationDistribution_wms111","id":"group_PopulationDistribution_wms111_1755679795075_68"}],"datas":[{"sourceType":"WFS","datasets":[{"datasetTitle":"Country_R","msDatasetId":"ms_Population:Country_R_1755679787206_42","datasetName":"Population:Country_R"},{"datasetTitle":"HeiHeTengChong_P","msDatasetId":"ms_Population:HeiHeTengChong_P_1755679787206_43","datasetName":"Population:HeiHeTengChong_P"},{"datasetTitle":"ProvinceCapital_P","msDatasetId":"ms_Population:ProvinceCapital_P_1755679787206_44","datasetName":"Population:ProvinceCapital_P"},{"datasetTitle":"BorderTest_L","msDatasetId":"ms_Population:BorderTest_L_1755679787206_45","datasetName":"Population:BorderTest_L"},{"datasetTitle":"Province_L","msDatasetId":"ms_Population:Province_L_1755679787206_46","datasetName":"Population:Province_L"},{"datasetTitle":"Island_R","msDatasetId":"ms_Population:Island_R_1755679787206_47","datasetName":"Population:Island_R"},{"datasetTitle":"PopDensity_R","msDatasetId":"ms_Population:PopDensity_R_1755679787206_48","datasetName":"Population:PopDensity_R"},{"datasetTitle":"Coastline_L","msDatasetId":"ms_Population:Coastline_L_1755679787206_49","datasetName":"Population:Coastline_L"},{"datasetTitle":"Buffer20000","msDatasetId":"ms_Population:Buffer20000_1755679787206_50","datasetName":"Population:Buffer20000"},{"datasetTitle":"Buffer35000","msDatasetId":"ms_Population:Buffer35000_1755679787206_51","datasetName":"Population:Buffer35000"},{"datasetTitle":"County_R","msDatasetId":"ms_Population:County_R_1755679787206_52","datasetName":"Population:County_R"},{"datasetTitle":"County_P","msDatasetId":"ms_Population:County_P_1755679787206_53","datasetName":"Population:County_P"}],"title":"示例 WFS 服务","url":"http://172.16.14.77:8090/iserver/services/data-Population-2/wfs200/gb18030"},{"sourceType":"WFS","withCredential":{"key": "token", "value": "test"},"datasets":[{"datasetTitle":"Country_R","msDatasetId":"ms_Population:Country_R_1755679835391_69","datasetName":"Population:Country_R"},{"datasetTitle":"HeiHeTengChong_P","msDatasetId":"ms_Population:HeiHeTengChong_P_1755679835391_70","datasetName":"Population:HeiHeTengChong_P"},{"datasetTitle":"ProvinceCapital_P","msDatasetId":"ms_Population:ProvinceCapital_P_1755679835391_71","datasetName":"Population:ProvinceCapital_P"},{"datasetTitle":"BorderTest_L","msDatasetId":"ms_Population:BorderTest_L_1755679835391_72","datasetName":"Population:BorderTest_L"},{"datasetTitle":"Province_L","msDatasetId":"ms_Population:Province_L_1755679835391_73","datasetName":"Population:Province_L"},{"datasetTitle":"Island_R","msDatasetId":"ms_Population:Island_R_1755679835391_74","datasetName":"Population:Island_R"},{"datasetTitle":"PopDensity_R","msDatasetId":"ms_Population:PopDensity_R_1755679835391_75","datasetName":"Population:PopDensity_R"},{"datasetTitle":"Coastline_L","msDatasetId":"ms_Population:Coastline_L_1755679835391_76","datasetName":"Population:Coastline_L"},{"datasetTitle":"Buffer20000","msDatasetId":"ms_Population:Buffer20000_1755679835391_77","datasetName":"Population:Buffer20000"},{"datasetTitle":"Buffer35000","msDatasetId":"ms_Population:Buffer35000_1755679835391_78","datasetName":"Population:Buffer35000"},{"datasetTitle":"County_R","msDatasetId":"ms_Population:County_R_1755679835391_79","datasetName":"Population:County_R"},{"datasetTitle":"County_P","msDatasetId":"ms_Population:County_P_1755679835391_80","datasetName":"Population:County_P"}],"title":"示例 WFS 服务","url":"http://172.16.14.77:8090/iserver/services/data-Population-2/wfs200/gb18030"}],"baseLayer":{"internetMapName":"CHINA_DARK","type":"INTERNET_MAP"},"version":"3.1.2"}; + + const sourceListModel = new SourceListModelV3({ + map, + mapInfo, + mapResourceInfo: projInfo, + legendList: [], + l7LayerUtil: { + isL7Layer, + getL7MarkerLayers: () => ({}) + } + }); + const appreciableLayers = sourceListModel.getLayers(); + expect(appreciableLayers.find(l=>l.dataSource.type === 'WFS')).toBeTruthy(); + done(); + }); + it('getLayerCatalog without group', (done) => { const mapInfo = JSON.parse(apstudioWebMap_layerData); const sourceListModel = new SourceListModelV3({ @@ -298,9 +639,9 @@ describe('SourceListV3', () => { }); const layerList = sourceListModel.getLayerCatalog(); expect(layerList.length).toBe(mapInfo.metadata.layerCatalog.length + 3); - const selfIds = mapInfo.metadata.layerCatalog.map(item => item.id); - const selfLayerCatalogs = layerList.filter(layer => selfIds.includes(layer.id)); - expect(selfLayerCatalogs.some(layer => !layer.renderLayers.includes(layer.id))).toBe(false); + const selfIds = mapInfo.metadata.layerCatalog.map((item) => item.id); + const selfLayerCatalogs = layerList.filter((layer) => selfIds.includes(layer.id)); + expect(selfLayerCatalogs.some((layer) => !layer.renderLayers.includes(layer.id))).toBe(false); done(); }); @@ -318,9 +659,9 @@ describe('SourceListV3', () => { }); const layerList = sourceListModel.getLayerCatalog(); expect(layerList.length).toBe(mapInfo.metadata.layerCatalog.length + 2); - const selfIds = mapInfo.metadata.layerCatalog.map(item => item.id); - const selfLayerCatalogs = layerList.filter(layer => selfIds.includes(layer.id)); - expect(selfLayerCatalogs.some(layer => !layer.renderLayers.includes(layer.id))).toBe(false); + const selfIds = mapInfo.metadata.layerCatalog.map((item) => item.id); + const selfLayerCatalogs = layerList.filter((layer) => selfIds.includes(layer.id)); + expect(selfLayerCatalogs.some((layer) => !layer.renderLayers.includes(layer.id))).toBe(false); done(); }); @@ -338,9 +679,9 @@ describe('SourceListV3', () => { }); const layerList = sourceListModel.getLayerCatalog(); expect(layerList.length).toBe(mapInfo.metadata.layerCatalog.length + 3); - const selfIds = mapInfo.metadata.layerCatalog.filter(item => item.parts).map(item => item.id); - const selfLayerCatalogs = layerList.filter(layer => selfIds.includes(layer.id)); - expect(selfLayerCatalogs.some(layer => layer.renderLayers.includes(layer.id))).toBe(false); + const selfIds = mapInfo.metadata.layerCatalog.filter((item) => item.parts).map((item) => item.id); + const selfLayerCatalogs = layerList.filter((layer) => selfIds.includes(layer.id)); + expect(selfLayerCatalogs.some((layer) => layer.renderLayers.includes(layer.id))).toBe(false); done(); }); @@ -367,9 +708,9 @@ describe('SourceListV3', () => { const markerList = { ['中国金牌个人获奖者(1)']: { show: jasmine.createSpy('show').and.callFake(() => {}), - hide: jasmine.createSpy('hide').and.callFake(() => {}), + hide: jasmine.createSpy('hide').and.callFake(() => {}) } - } + }; const sourceListModel = new SourceListModelV3({ map, mapInfo, @@ -401,9 +742,9 @@ describe('SourceListV3', () => { const markerList = { ['中国金牌个人获奖者(1)']: { show: jasmine.createSpy('show').and.callFake(() => {}), - hide: jasmine.createSpy('hide').and.callFake(() => {}), + hide: jasmine.createSpy('hide').and.callFake(() => {}) } - } + }; const sourceListModel = new SourceListModelV3({ map, mapInfo, @@ -435,9 +776,9 @@ describe('SourceListV3', () => { const markerList = { ['中国金牌个人获奖者(1)']: { show: jasmine.createSpy('show').and.callFake(() => {}), - hide: jasmine.createSpy('hide').and.callFake(() => {}), + hide: jasmine.createSpy('hide').and.callFake(() => {}) } - } + }; const sourceListModel = new SourceListModelV3({ map, mapInfo, @@ -487,4 +828,154 @@ describe('SourceListV3', () => { expect(mockEvents.styledata).not.toBeUndefined(); mockEvents.styledata(); }); + + it('changeBaseLayer not complicit', (done) => { + const nextBaseLayerMapInfo = cloneDeep(changeBaseLayerMapInfo); + layers = nextBaseLayerMapInfo.layers; + sources = nextBaseLayerMapInfo.sources; + + overlayLayersManager = {}; + + const sourceListModel = new SourceListModelV3({ + map, + mapInfo: cloneDeep(nextBaseLayerMapInfo), + mapResourceInfo: {}, + legendList: [], + l7LayerUtil: { + isL7Layer, + getL7MarkerLayers: () => [] + } + }); + expect(map.getStyle().layers.some((item) => ['TIANDITU_IMG_3857', 'ms_TIANDITU_IMG_3857_label'].includes(item.id))).toBeTruthy(); + const layerList = sourceListModel.getLayerCatalog(); + const appreciableLayers = sourceListModel.getLayers(); + expect(layerList.length).toBe(2); + expect(appreciableLayers.length).toBe(3); + const nextBaseLayerInfo = sourceListModel.changeBaseLayer(baseLayerInfo); + expect(nextBaseLayerInfo).toBeTruthy(); + expect(nextBaseLayerInfo.layers.length).toBe(1); + expect(nextBaseLayerInfo.layers).toEqual(baseLayerInfo.layers); + expect(map.getStyle().layers.some((item) => ['TIANDITU_IMG_3857', 'ms_TIANDITU_IMG_3857_label'].includes(item.id))).toBeFalsy(); + done(); + }); + + it('changeBaseLayer complicit', (done) => { + let nextBaseLayerMapInfo = cloneDeep(changeBaseLayerMapInfo); + layers = [ + ...baseLayerInfo.layers, + ...nextBaseLayerMapInfo.layers + ]; + sources = { + ...nextBaseLayerMapInfo.sources, + ...baseLayerInfo.sources + }; + const copyMapInfo = cloneDeep(changeBaseLayerMapInfo); + nextBaseLayerMapInfo = { + ...copyMapInfo, + layers: cloneDeep(layers), + sources: cloneDeep(sources), + metadata: { + layerCatalog: copyMapInfo.metadata.layerCatalog.concat(baseLayerInfo.layers.map(item => ({ + id: item.id, + title: item.id, + type: 'basic', + visible: true + }))) + } + } + overlayLayersManager = {}; + + const sourceListModel = new SourceListModelV3({ + map, + mapInfo: nextBaseLayerMapInfo, + mapResourceInfo: {}, + legendList: [], + l7LayerUtil: { + isL7Layer, + getL7MarkerLayers: () => [] + } + }); + expect(map.getStyle().layers.some((item) => ['TIANDITU_IMG_3857', 'ms_TIANDITU_IMG_3857_label'].includes(item.id))).toBeTruthy(); + expect(map.getStyle().layers.some((item) => ['wmts100'].includes(item.id))).toBeTruthy(); + let layerList = sourceListModel.getLayerCatalog(); + let appreciableLayers = sourceListModel.getLayers(); + expect(layerList.length).toBe(3); + expect(layerList[layerList.length - 1].id).toBe('wmts100'); + expect(appreciableLayers.length).toBe(4); + expect(appreciableLayers[0].id).toBe('wmts100'); + const sameBaseLayer = { + id: 'sameBaseLayer', + layers: layers.slice(1, 3).map((item) => { + const nextItem = Object.assign({}, item); + nextItem.metadata = { SM_Layer_Id: 'sameBaseLayer', title: `custom_${item.id}` }; + return nextItem; + }), + sources: { + TIANDITU_IMG_3857: sources['TIANDITU_IMG_3857'], + 'ms_TIANDITU_IMG_3857_label': sources['ms_TIANDITU_IMG_3857_label'] + } + }; + const nextBaseLayerInfo = sourceListModel.changeBaseLayer(sameBaseLayer); + expect(nextBaseLayerInfo).toBeTruthy(); + expect(nextBaseLayerInfo.layers.length).toBe(2); + expect(nextBaseLayerInfo.layers).not.toEqual(sameBaseLayer.layers); + expect(map.getStyle().layers.some((item) => ['TIANDITU_IMG_3857', 'ms_TIANDITU_IMG_3857_label'].includes(item.id))).toBeTruthy(); + expect( + map + .getStyle() + .layers.some((item) => [/TIANDITU_IMG_3857_\d+$/, /ms_TIANDITU_IMG_3857_label_\d+$/].some((reg) => reg.test(item.id))) + ).toBeTruthy(); + expect(map.getStyle().layers.some((item) => ['wmts100'].includes(item.id))).toBeFalsy(); + layerList = sourceListModel.getLayerCatalog(); + appreciableLayers = sourceListModel.getLayers(); + expect(layerList.length).toBe(3); + expect(layerList[layerList.length - 1].id).toBe('sameBaseLayer'); + expect(layerList[layerList.length - 1].children[0].title.match(/custom_TIANDITU_IMG_3857$/)).toBeTruthy(); + expect(layerList[layerList.length - 1].children[1].title.match(/custom_ms_TIANDITU_IMG_3857_label$/)).toBeTruthy(); + expect(appreciableLayers.length).toBe(5); + expect(appreciableLayers[0].id.match(/TIANDITU_IMG_3857_TIANDITU_IMG_3857_\d+$/)).toBeTruthy(); + expect(appreciableLayers[1].id.match(/ms_TIANDITU_IMG_3857_label_ms_TIANDITU_IMG_3857_label_\d+$/)).toBeTruthy(); + expect(appreciableLayers[0].title.match(/custom_TIANDITU_IMG_3857/)).toBeTruthy(); + expect(appreciableLayers[1].title.match(/custom_ms_TIANDITU_IMG_3857_label/)).toBeTruthy(); + done(); + }); + + it('changeBaseLayer show title', (done) => { + const nextBaseLayerMapInfo = cloneDeep(changeBaseLayerMapInfo); + layers = nextBaseLayerMapInfo.layers; + sources = nextBaseLayerMapInfo.sources; + + overlayLayersManager = {}; + + const sourceListModel = new SourceListModelV3({ + map, + mapInfo: cloneDeep(nextBaseLayerMapInfo), + mapResourceInfo: {}, + legendList: [], + l7LayerUtil: { + isL7Layer, + getL7MarkerLayers: () => [] + } + }); + expect(map.getStyle().layers.some((item) => ['TIANDITU_IMG_3857', 'ms_TIANDITU_IMG_3857_label'].includes(item.id))).toBeTruthy(); + const layerList = sourceListModel.getLayerCatalog(); + const appreciableLayers = sourceListModel.getLayers(); + expect(layerList.length).toBe(2); + expect(appreciableLayers.length).toBe(3); + const baseLayerInfoCopy = { + ...baseLayerInfo, + layers: baseLayerInfo.layers.map((item) => ({ + ...item, + metadata: { title: `custom_${item.id}`} + })) + }; + const nextBaseLayerInfo = sourceListModel.changeBaseLayer(baseLayerInfoCopy); + expect(nextBaseLayerInfo).toBeTruthy(); + expect(nextBaseLayerInfo.layers.length).toBe(1); + expect(nextBaseLayerInfo.layers).toEqual(baseLayerInfoCopy.layers); + expect(map.getStyle().layers.some((item) => ['TIANDITU_IMG_3857', 'ms_TIANDITU_IMG_3857_label'].includes(item.id))).toBeFalsy(); + const nextAppreciableLayers = sourceListModel.getLayers(); + expect(nextAppreciableLayers.some(item => item.title === baseLayerInfoCopy.layers[0].metadata.title)).toBeTruthy(); + done(); + }); }); diff --git a/test/mapboxgl/mapping/WebMapSpec.js b/test/mapboxgl/mapping/WebMapSpec.js index 32a74957ca..1d38969303 100644 --- a/test/mapboxgl/mapping/WebMapSpec.js +++ b/test/mapboxgl/mapping/WebMapSpec.js @@ -732,6 +732,40 @@ describe('mapboxgl_WebMap', () => { }); }); + it('createThemeLayer_SUPERMAPREST_DATA preferServer', (done) => { + let options = { + server: server, + preferServer: true + }; + spyOn(FetchRequest, 'get').and.callFake((url) => { + if (url.indexOf('web/config/portal.json') > -1) { + return Promise.resolve(new Response(JSON.stringify(iportal_serviceProxy))); + } + if (url.indexOf('map.json') > -1) { + var mapJson = datavizWebMap_RestData; + return Promise.resolve(new Response(mapJson)); + } + return Promise.resolve(); + }); + spyOn(FetchRequest, 'post').and.callFake((url) => { + expect(url).toBe('http://fakeiserver/iserver/services/data-jingjin/rest/data/featureResults.geojson?returnFeaturesOnly=true&returnContent=true'); + return Promise.resolve(new Response(JSON.stringify(JSON.parse(markerData2.content)))); + }); + var datavizWebmap = new WebMap(id, options); + + datavizWebmap.on('mapcreatesucceeded', function () { + expect(datavizWebmap.credentialKey).toBeUndefined(); + expect(datavizWebmap.credentialValue).toBeUndefined(); + + var map = datavizWebmap.map; + expect(map.getZoom()).toBeCloseTo(9, 0.001); + expect(map.getCenter()).toEqual(new mapboxgl.LngLat(116.8995771532053, 39.700527641334965)); + expect(datavizWebmap.mapParams.title).toBe('RestData'); + expect(datavizWebmap.mapParams.description).toBe(''); + done(); + }); + }); + it('WMS', (done) => { let options = { server: server diff --git a/test/mapboxgl/mapping/WebMapV2Spec.js b/test/mapboxgl/mapping/WebMapV2Spec.js index c2ff4d4e30..328cc27715 100644 --- a/test/mapboxgl/mapping/WebMapV2Spec.js +++ b/test/mapboxgl/mapping/WebMapV2Spec.js @@ -203,7 +203,11 @@ describe('mapboxgl_WebMapV2', () => { getZoom: () => { return 2; }, + getMaxZoom: () => { + return 22; + }, setZoom: jasmine.createSpy('setZoom').and.callFake(() => {}), + setMaxZoom: jasmine.createSpy('setZoom').and.callFake(() => {}), setCRS: jasmine.createSpy('setCRS').and.callFake(() => {}), getCenter: () => { return { @@ -486,6 +490,29 @@ describe('mapboxgl_WebMapV2', () => { datavizWebmap.on('mapcreatesucceeded', callback); }); + it('vectorlayer should have legends', (done) => { + spyOn(FetchRequest, 'get').and.callFake((url) => { + if (url.indexOf('map.json') > -1) { + return Promise.resolve(new Response(JSON.stringify(vectorLayer_line))); + } else if (url.indexOf('1788054202/content.json?') > -1) { + return Promise.resolve(new Response(JSON.stringify(chart_content))); + } else if (url.indexOf('13136933/content.json?') > -1) { + return Promise.resolve(new Response(JSON.stringify(layerData_geojson['POINT_GEOJSON']))); + } else if (url.indexOf('portal.json') > -1) { + return Promise.resolve(new Response(JSON.stringify(iportal_serviceProxy))); + } else if (url.indexOf('web/datas/1920557079/content.json') > -1) { + return Promise.resolve(new Response(layerData_CSV)); + } + return Promise.resolve(new Response(JSON.stringify({}))); + }); + datavizWebmap = new WebMap(id, { ...commonOption, map: commonMap }, { ...commonMapOptions }); + const callback = function (data) { + expect(datavizWebmap.getLegends().length).toBe(1); + done(); + }; + datavizWebmap.on('mapcreatesucceeded', callback); + }); + it('add heatLayer', (done) => { spyOn(FetchRequest, 'get').and.callFake((url) => { if (url.indexOf('web/datas/1920557079/content.json') > -1) { diff --git a/test/mapboxgl/mapping/WebMapV3Spec.js b/test/mapboxgl/mapping/WebMapV3Spec.js index 84bb818fe6..48397fc36b 100644 --- a/test/mapboxgl/mapping/WebMapV3Spec.js +++ b/test/mapboxgl/mapping/WebMapV3Spec.js @@ -318,6 +318,8 @@ describe('mapboxgl-webmap3.0', () => { existedMap.on('load', function () { mapstudioWebmap.initializeMap(nextMapInfo, existedMap); }); + const isSameCrs = extendOptions.crsManager.isSameProjection(existedMap, 'EPSG:4326'); + expect(isSameCrs).toBe(true); mapstudioWebmap.on('mapcreatesucceeded', ({ map }) => { expect(mapstudioWebmap._appendLayers).toBe(true); expect(map).toEqual(existedMap); diff --git a/test/mapboxgl/services/GetFeaturesByBoundsSpec.js b/test/mapboxgl/services/GetFeaturesByBoundsSpec.js index c88acc9bab..d8e7ae708a 100644 --- a/test/mapboxgl/services/GetFeaturesByBoundsSpec.js +++ b/test/mapboxgl/services/GetFeaturesByBoundsSpec.js @@ -63,26 +63,40 @@ describe('mapboxgl_FeatureService_getFeaturesByBounds', () => { done(); }); }); - it('GetFeaturesByBoundsParameters:targetEpsgCode', done => { - var sw = new mapboxgl.LngLat(-20, -20); - var ne = new mapboxgl.LngLat(20, 20); - var lngLatBounds = new mapboxgl.LngLatBounds(sw, ne); - var boundsParam = new GetFeaturesByBoundsParameters({ - datasetNames: ['World:Capitals'], - bounds: lngLatBounds, - targetEpsgCode: 4326 - }); - var service = new FeatureService(url); - spyOn(FetchRequest, 'commit').and.callFake((method, testUrl, params, options) => { - var paramsObj = JSON.parse(params.replace(/'/g, '"')); - expect(paramsObj.targetEpsgCode).toEqual(4326); - return Promise.resolve(new Response(JSON.stringify(getFeaturesResultJson))); - }); - service.getFeaturesByBounds(boundsParam, result => { - serviceResult = result; - boundsParam.destroy(); - done(); - }); + it('getFeaturesByBounds preferServer', done => { + var sw = new mapboxgl.LngLat(-20, -20); + var ne = new mapboxgl.LngLat(20, 20); + var lngLatBounds = new mapboxgl.LngLatBounds(sw, ne); + var boundsParam = new GetFeaturesByBoundsParameters({ + datasetNames: ['World:Capitals'], + bounds: lngLatBounds, + fromIndex: 1, + toIndex: 3 + }); + var service = new FeatureService(url, { preferServer: true }); + spyOn(FetchRequest, 'commit').and.callFake((method, testUrl, params, options) => { + expect(method).toBe('POST'); + expect(testUrl).toBe(url + '/featureResults.geojson?fromIndex=1&toIndex=3&returnContent=true'); + var paramsObj = JSON.parse(params.replace(/'/g, '"')); + expect(paramsObj.datasetNames[0]).toBe('World:Capitals'); + expect(paramsObj.getFeatureMode).toBe('BOUNDS'); + expect(paramsObj.spatialQueryMode).toBe('CONTAIN'); + expect(options).not.toBeNull(); + expect(options.withoutFormatSuffix).toBe(true); + return Promise.resolve(new Response(JSON.stringify(getFeaturesBySQLService.result.features))); + }); + service.getFeaturesByBounds(boundsParam, testResult => { + serviceResult = testResult; + expect(service).not.toBeNull(); + expect(serviceResult.type).toBe('processCompleted'); + expect(serviceResult.object.format).toBe('GEOJSON'); + var result = serviceResult.result; + expect(result.succeed).toBe(true); + expect(result.features.type).toEqual('FeatureCollection'); + expect(serviceResult.object.preferServer).toBe(true); + boundsParam.destroy(); + done(); + }); }); it('GetFeaturesByBoundsParameters:targetPrj', done => { var sw = new mapboxgl.LngLat(-20, -20); diff --git a/test/mapboxgl/services/GetFeaturesByBufferSpec.js b/test/mapboxgl/services/GetFeaturesByBufferSpec.js index 8dce24e577..5965e44ccd 100644 --- a/test/mapboxgl/services/GetFeaturesByBufferSpec.js +++ b/test/mapboxgl/services/GetFeaturesByBufferSpec.js @@ -72,6 +72,51 @@ describe('mapboxgl_FeatureService_getFeaturesByBuffer', () => { done(); }); }); + it('getFeaturesByBuffer_geometry preferServer', done => { + var queryBufferGeometry = { + type: 'Polygon', + coordinates: [ + [ + [-20, 20], + [-20, -20], + [20, -20], + [20, 20], + [-20, 20] + ] + ] + }; + var bufferParam = new GetFeaturesByBufferParameters({ + datasetNames: ['World:Capitals'], + bufferDistance: 10, + geometry: queryBufferGeometry, + fromIndex: 1, + toIndex: 3 + }); + var service = new FeatureService(url, { preferServer: true }); + spyOn(FetchRequest, 'commit').and.callFake((method, testUrl, params, options) => { + expect(method).toBe('POST'); + expect(testUrl).toBe(url + '/featureResults.geojson?fromIndex=1&toIndex=3&returnContent=true'); + var paramsObj = JSON.parse(params.replace(/'/g, '"')); + expect(paramsObj.datasetNames[0]).toBe('World:Capitals'); + expect(paramsObj.bufferDistance).toEqual(10); + expect(paramsObj.getFeatureMode).toBe('BUFFER'); + expect(options.withoutFormatSuffix).toBe(true); + expect(options).not.toBeNull(); + return Promise.resolve(new Response(JSON.stringify(getFeaturesBySQLService.result.features))); + }); + service.getFeaturesByBuffer(bufferParam, testResult => { + serviceResult = testResult; + expect(service).not.toBeNull(); + expect(serviceResult.type).toBe('processCompleted'); + expect(serviceResult.object.format).toBe('GEOJSON'); + var result = serviceResult.result; + expect(result.succeed).toBe(true); + expect(serviceResult.result.features.type).toEqual('FeatureCollection'); + expect(serviceResult.object.preferServer).toBe(true); + bufferParam.destroy(); + done(); + }); + }); it('GetFeaturesByBufferParameters:targetEpsgCode', done => { var queryBufferGeometry = { type: 'Polygon', diff --git a/test/mapboxgl/services/GetFeaturesByGeometrySpec.js b/test/mapboxgl/services/GetFeaturesByGeometrySpec.js index d052d64bfb..755b73f37c 100644 --- a/test/mapboxgl/services/GetFeaturesByGeometrySpec.js +++ b/test/mapboxgl/services/GetFeaturesByGeometrySpec.js @@ -73,6 +73,52 @@ describe('mapboxgl_FeatureService_getFeaturesByGeometry', () => { } }); }); + it('getFeaturesByGeometry preferServer', done => { + var queryPolygonGeometry = { + type: 'Polygon', + coordinates: [ + [ + [0, 0], + [-10, 30], + [-30, 0], + [0, 0] + ] + ] + }; + var geometryParam = new GetFeaturesByGeometryParameters({ + datasetNames: ['World:Countries'], + geometry: queryPolygonGeometry, + spatialQueryMode: 'INTERSECT' + }); + var service = new FeatureService(url, { preferServer: true }); + spyOn(FetchRequest, 'commit').and.callFake((method, testUrl, params, options) => { + expect(method).toBe('POST'); + expect(testUrl).toBe(url + '/featureResults.geojson?fromIndex=0&toIndex=19&returnContent=true'); + var paramsObj = JSON.parse(params.replace(/'/g, '"')); + expect(paramsObj.datasetNames[0]).toBe('World:Countries'); + expect(paramsObj.spatialQueryMode).toBe('INTERSECT'); + expect(options.withoutFormatSuffix).toBe(true); + expect(options).not.toBeNull(); + return Promise.resolve(new Response(JSON.stringify(getFeaturesBySQLService.result.features))); + }); + service.getFeaturesByGeometry(geometryParam, result => { + serviceResult = result; + try { + expect(service).not.toBeNull(); + expect(serviceResult).not.toBeNull(); + expect(serviceResult.type).toBe('processCompleted'); + expect(serviceResult.result.succeed).toBe(true); + expect(serviceResult.options.data).toContain('World:Countries'); + expect(serviceResult.object.preferServer).toBe(true); + expect(serviceResult.result.features.type).toBe('FeatureCollection'); + done(); + } catch (e) { + console.log("'getFeaturesByGeometry preferServer'案例失败" + e.name + ':' + e.message); + expect(false).toBeTruthy(); + done(); + } + }); + }); it('GetFeaturesByGeometryParameters:targetEpsgCode', done => { var queryPolygonGeometry = { type: 'Polygon', diff --git a/test/mapboxgl/services/GetFeaturesByIDsSpec.js b/test/mapboxgl/services/GetFeaturesByIDsSpec.js index 34e691e884..7d3eeeb2dc 100644 --- a/test/mapboxgl/services/GetFeaturesByIDsSpec.js +++ b/test/mapboxgl/services/GetFeaturesByIDsSpec.js @@ -20,19 +20,65 @@ describe('mapboxgl_FeatureService_getFeaturesByIDs', () => { //数据集ID查询服务 it('getFeaturesByIDs', done => { + var idsParam = new GetFeaturesByIDsParameters({ + IDs: [247], + datasetNames: ['World:Countries'] + }); + var service = new FeatureService(url); + spyOn(FetchRequest, 'commit').and.callFake((method, testUrl, params, options) => { + expect(method).toBe('POST'); + expect(testUrl).toBe(url + '/featureResults?fromIndex=0&toIndex=19&returnContent=true'); + var paramsObj = JSON.parse(params.replace(/'/g, '"')); + expect(paramsObj.datasetNames[0]).toBe('World:Countries'); + expect(paramsObj.getFeatureMode).toBe('ID'); + expect(options).not.toBeNull(); + return Promise.resolve(new Response(JSON.stringify(getFeaturesResultJson))); + }); + service.getFeaturesByIDs(idsParam, result => { + serviceResult = result; + try { + expect(service).not.toBeNull(); + expect(serviceResult).not.toBeNull(); + expect(serviceResult.type).toBe('processCompleted'); + expect(serviceResult.result.succeed).toBe(true); + expect(serviceResult.options.data).toContain('World:Countries'); + expect(serviceResult.result.featureCount).toEqual(1); + expect(serviceResult.result.totalCount).toEqual(serviceResult.result.featureCount); + expect(serviceResult.result.features.type).toEqual('FeatureCollection'); + expect(serviceResult.result.features.features[0].id).toEqual(127); + expect(serviceResult.result.features.features[0].type).toEqual('Feature'); + expect(serviceResult.result.features.features[0].geometry.type).toEqual('MultiPolygon'); + var coordinates = serviceResult.result.features.features[0].geometry.coordinates; + expect(coordinates.length).toBeGreaterThan(0); + for (var i = 0; i < coordinates.length; i++) { + expect(coordinates[i][0].length).toBeGreaterThan(0); + for (var j = 0; j < coordinates[i][0].length; j++) { + expect(coordinates[i][0][j].length).toEqual(2); + } + } + done(); + } catch (e) { + console.log("'getFeaturesByIDs'案例失败" + e.name + ':' + e.message); + expect(false).toBeTruthy(); + done(); + } + }); + }); + it('getFeaturesByIDs preferServer', done => { var idsParam = new GetFeaturesByIDsParameters({ IDs: [247], datasetNames: ['World:Countries'] }); - var service = new FeatureService(url); + var service = new FeatureService(url, { preferServer: true }); spyOn(FetchRequest, 'commit').and.callFake((method, testUrl, params, options) => { expect(method).toBe('POST'); - expect(testUrl).toBe(url + '/featureResults?fromIndex=0&toIndex=19&returnContent=true'); + expect(testUrl).toBe(url + '/featureResults.geojson?fromIndex=0&toIndex=19&returnContent=true'); var paramsObj = JSON.parse(params.replace(/'/g, '"')); expect(paramsObj.datasetNames[0]).toBe('World:Countries'); expect(paramsObj.getFeatureMode).toBe('ID'); expect(options).not.toBeNull(); - return Promise.resolve(new Response(JSON.stringify(getFeaturesResultJson))); + expect(options.withoutFormatSuffix).toBe(true); + return Promise.resolve(new Response(JSON.stringify(getFeaturesBySQLService.result.features))); }); service.getFeaturesByIDs(idsParam, result => { serviceResult = result; @@ -41,24 +87,12 @@ describe('mapboxgl_FeatureService_getFeaturesByIDs', () => { expect(serviceResult).not.toBeNull(); expect(serviceResult.type).toBe('processCompleted'); expect(serviceResult.result.succeed).toBe(true); + expect(serviceResult.object.preferServer).toBe(true); expect(serviceResult.options.data).toContain('World:Countries'); - expect(serviceResult.result.featureCount).toEqual(1); - expect(serviceResult.result.totalCount).toEqual(serviceResult.result.featureCount); expect(serviceResult.result.features.type).toEqual('FeatureCollection'); - expect(serviceResult.result.features.features[0].id).toEqual(127); - expect(serviceResult.result.features.features[0].type).toEqual('Feature'); - expect(serviceResult.result.features.features[0].geometry.type).toEqual('MultiPolygon'); - var coordinates = serviceResult.result.features.features[0].geometry.coordinates; - expect(coordinates.length).toBeGreaterThan(0); - for (var i = 0; i < coordinates.length; i++) { - expect(coordinates[i][0].length).toBeGreaterThan(0); - for (var j = 0; j < coordinates[i][0].length; j++) { - expect(coordinates[i][0][j].length).toEqual(2); - } - } done(); } catch (e) { - console.log("'getFeaturesByIDs'案例失败" + e.name + ':' + e.message); + console.log("'getFeaturesByIDs preferServer'案例失败" + e.name + ':' + e.message); expect(false).toBeTruthy(); done(); } diff --git a/test/mapboxgl/services/GetFeaturesBySQLSpec.js b/test/mapboxgl/services/GetFeaturesBySQLSpec.js index 048320f797..0531fbc8bc 100644 --- a/test/mapboxgl/services/GetFeaturesBySQLSpec.js +++ b/test/mapboxgl/services/GetFeaturesBySQLSpec.js @@ -26,7 +26,87 @@ describe('mapboxgl_FeatureService_getFeaturesBySQL', () => { expect(getFeaturesBySQLService.options.headers).not.toBeNull(); }); - //数据集SQL查询服务 + it('getFeaturesBySQL geojson preferServer true', done => { + var sqlParam = new GetFeaturesBySQLParameters({ + queryParameter: { + name: 'Countries@World', + attributeFilter: 'SMID = 247' + }, + datasetNames: ['World:Countries'] + }); + var service = new FeatureService(url, { preferServer: true }); + spyOn(FetchRequest, 'commit').and.callFake((method, testUrl, params, options) => { + expect(method).toBe('POST'); + expect(testUrl).toBe(url + '/featureResults.geojson?fromIndex=0&toIndex=19&returnContent=true'); + var paramsObj = JSON.parse(params.replace(/'/g, '"')); + expect(paramsObj.datasetNames[0]).toBe('World:Countries'); + expect(paramsObj.getFeatureMode).toBe('SQL'); + expect(options).not.toBeNull(); + expect(options.withoutFormatSuffix).toBe(true); + return Promise.resolve(new Response(JSON.stringify(getFeaturesBySQLService.result.features))); + }); + service.getFeaturesBySQL(sqlParam, result => { + serviceResult = result; + + try { + expect(service).not.toBeNull(); + expect(serviceResult).not.toBeNull(); + expect(serviceResult.type).toBe('processCompleted'); + expect(serviceResult.result.succeed).toBe(true); + expect(serviceResult.object.preferServer).toBe(true); + expect(serviceResult.result.features.type).toBe('FeatureCollection'); + expect(serviceResult.options.data).toContain('Countries@World'); + expect(serviceResult.options.data).toContain('SMID = 247'); + done(); + } catch (e) { + console.log("'getFeaturesBySQL prefreServer'案例失败" + e.name + ':' + e.message); + expect(false).toBeTruthy(); + done(); + } + }); + }); + + it('getFeaturesBySQL iserver preferServer true', done => { + var sqlParam = new GetFeaturesBySQLParameters({ + queryParameter: { + name: 'Countries@World', + attributeFilter: 'SMID = 247' + }, + datasetNames: ['World:Countries'] + }); + var service = new FeatureService(url, { preferServer: true }); + spyOn(FetchRequest, 'commit').and.callFake((method, testUrl, params, options) => { + expect(method).toBe('POST'); + expect(testUrl).toBe(url + '/featureResults?fromIndex=0&toIndex=19&returnContent=true'); + var paramsObj = JSON.parse(params.replace(/'/g, '"')); + expect(paramsObj.datasetNames[0]).toBe('World:Countries'); + expect(paramsObj.getFeatureMode).toBe('SQL'); + expect(options).not.toBeNull(); + expect(options.withoutFormatSuffix).toBe(false); + return Promise.resolve(new Response(JSON.stringify(getFeaturesResultJson))); + }); + service.getFeaturesBySQL(sqlParam, result => { + serviceResult = result; + try { + expect(service).not.toBeNull(); + expect(serviceResult).not.toBeNull(); + expect(serviceResult.type).toBe('processCompleted'); + expect(serviceResult.result.succeed).toBe(true); + expect(serviceResult.object.preferServer).toBe(true); + expect(serviceResult.result.features).not.toBeNull(); + expect(serviceResult.options.data).toContain('Countries@World'); + expect(serviceResult.options.data).toContain('SMID = 247'); + expect(serviceResult.result.featureCount).toEqual(1); + expect(serviceResult.result.totalCount).toEqual(1); + done(); + } catch (e) { + console.log("'getFeaturesBySQL prefreServer'案例失败" + e.name + ':' + e.message); + expect(false).toBeTruthy(); + done(); + } + }, 'ISERVER'); + }); + it('getFeaturesBySQL', done => { var sqlParam = new GetFeaturesBySQLParameters({ queryParameter: { diff --git a/test/maplibregl/mapping/WebMapV2Spec.js b/test/maplibregl/mapping/WebMapV2Spec.js index 26d3d26219..78e89354a0 100644 --- a/test/maplibregl/mapping/WebMapV2Spec.js +++ b/test/maplibregl/mapping/WebMapV2Spec.js @@ -203,7 +203,11 @@ describe('maplibregl_WebMapV2', () => { getZoom: () => { return 2; }, + getMaxZoom: () => { + return 22; + }, setZoom: jasmine.createSpy('setZoom').and.callFake(() => {}), + setMaxZoom: jasmine.createSpy('setMaxZoom').and.callFake(() => {}), setCRS: jasmine.createSpy('setCRS').and.callFake(() => {}), getCenter: () => { return { diff --git a/test/maplibregl/overlay/GraticuleLayerSpec.js b/test/maplibregl/overlay/GraticuleLayerSpec.js index 36aab46ede..40c25b2ffb 100644 --- a/test/maplibregl/overlay/GraticuleLayerSpec.js +++ b/test/maplibregl/overlay/GraticuleLayerSpec.js @@ -1,6 +1,5 @@ import maplibregl from 'maplibre-gl'; import { GraticuleLayer } from '../../../src/maplibregl/overlay/GraticuleLayer'; -var url = GlobeParameter.ChinaURL + '/zxyTileImage.png?z={z}&x={x}&y={y}'; describe('maplibregl_GraticuleLayer', () => { var originalTimeout; @@ -18,22 +17,8 @@ describe('maplibregl_GraticuleLayer', () => { container: 'map', style: { version: 8, - sources: { - 'raster-tiles': { - type: 'raster', - tiles: [url], - tileSize: 256 - } - }, - layers: [ - { - id: 'simple-tiles', - type: 'raster', - source: 'raster-tiles', - minzoom: 0, - maxzoom: 22 - } - ] + sources: {}, + layers: [] }, center: [112, 37.94], zoom: 3 diff --git a/test/tool/mock_mapboxgl_map.js b/test/tool/mock_mapboxgl_map.js index 5e934a333f..3afab25965 100644 --- a/test/tool/mock_mapboxgl_map.js +++ b/test/tool/mock_mapboxgl_map.js @@ -33,6 +33,7 @@ const Map = function (options) { this._sources = {}; this._collectResourceTiming = !!this.options.collectResourceTiming; this.zoom = this.options.zoom || 0; + this.maxZoom = this.options.maxZoom || 22; this._container = this.options.container || 'map'; this._layers = {}; this._layersList = []; @@ -107,7 +108,7 @@ const Map = function (options) { // Settings 'setMaxBounds', 'setMinZoom', - 'setMaxZoom', + // 'setMaxZoom', // Layer properties 'setLayoutProperty', 'setPaintProperty' @@ -142,6 +143,12 @@ const Map = function (options) { layers: this._layersList }; }; + this.getMaxZoom = function () { + return this.maxZoom; + }; + this.setMaxZoom = function (zoom) { + this.maxZoom = zoom ; + }; this.getContainer = function () { const container = { @@ -291,9 +298,6 @@ const Map = function (options) { this.getMinZoom = function () { return 0; }; - this.getMaxZoom = function () { - return 22; - }; this.doubleClickZoom = { disable: function () {}, enable: function () {} diff --git a/test/tool/mock_maplibregl_map.js b/test/tool/mock_maplibregl_map.js index 3434e7129e..4456f1dd10 100644 --- a/test/tool/mock_maplibregl_map.js +++ b/test/tool/mock_maplibregl_map.js @@ -35,6 +35,7 @@ const Map = function (options) { this.zoom = this.options.zoom || 0; this._container = this.options.container || 'map'; this._layers = {}; + this.maxZoom = 22; this._layersList = []; this.getContainer = function () { return this._container; @@ -107,7 +108,7 @@ const Map = function (options) { // Settings 'setMaxBounds', 'setMinZoom', - 'setMaxZoom', + // 'setMaxZoom', // Layer properties 'setLayoutProperty', 'setPaintProperty' @@ -292,7 +293,10 @@ const Map = function (options) { return 0; }; this.getMaxZoom = function () { - return 22; + return this.maxZoom || 22; + }; + this.setMaxZoom = function (maxZoom) { + this.maxZoom = maxZoom; }; this.doubleClickZoom = { disable: function () {},