转载:Cesium SuperMap问题调研汇总
作者:互联网
转自:https://segmentfault.com/a/1190000040577369
主要参考资料汇总
http://support.supermap.com.c...
http://cesium.xin/cesium/cn/D...
http://support.supermap.com.c...
描绘点
viewer.entities.add({ name: name, position: new Cesium.Cartesian3.fromDegrees(lon, lat, h), // 广告牌 billboard: new Cesium.BillboardGraphics({ image: icon || "images/shuniu.png", horizontalOrigin: Cesium.HorizontalOrigin.CENTER, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, alignedAxis: Cesium.Cartesian3.ZERO, disableDepthTestDistance: Number.POSITIVE_INFINITY, // 可以显示的距离 distanceDisplayCondition: new Cesium.DistanceDisplayCondition( 0, height ), }), });
描绘线
// positions 是笛卡尔坐标系x y z let polyCenter = Cesium.BoundingSphere.fromPoints(positions).center; polyCenter = Cesium.Ellipsoid.WGS84.scaleToGeodeticSurface(polyCenter); viewer.entities.add({ show: true, position: polyCenter, // 为了找到线的中心点, 不需要可以不用写 name: row.PlacemarkName, polyline: { positions, width: row.LineWidth || 2, material: new Cesium.Color.fromCssColorString(row.LineColor || 'red'), clampToGround: true, show: true, distanceDisplayCondition: new Cesium.DistanceDisplayCondition( 0, row.LineShowHeight ), } })
添加闪光尾迹线
首先得先全局开启闪耀效果
viewer.scene.bloomEffect.show = true; viewer.scene.hdrEnabled = true; viewer.scene.bloomEffect.bloomIntensity = 1;
然后实现尾迹线
viewer.entities.add({ // 尾迹线 polyline: { positions, width: row.LineWidth || 2, // 线的宽度,像素为单位 material: new Cesium.PolylineTrailMaterialProperty({ // 尾迹线材质 值越大光越闪耀 0-1属于正常 1以上闪耀效果 color: new Cesium.Color( 1.00392156862745098, 3.8784313725490196, 0.3176470588235294, 1 ), trailLength: 0.4, period: 10, }), distanceDisplayCondition: new Cesium.DistanceDisplayCondition( 0, row.LineShowHeight ), }, ClampToGround: true, });
波纹雷达圈
首先得扩展cesium方法 存为CircleWaveMaterialProperty.js
export class CircleWaveMaterialProperty { constructor(options) { options = Cesium.defaultValue(options, Cesium.defaultValue.EMPTY_OBJECT); this._definitionChanged = new Cesium.Event(); this._color = undefined; this._colorSubscription = undefined; this.color = options.color; this.duration = Cesium.defaultValue(options.duration, 1e3); this.count = Cesium.defaultValue(options.count, 2); if (this.count <= 0) this.count = 1; this.gradient = Cesium.defaultValue(options.gradient, 0.1); if (this.gradient < 0) this.gradient = 0; else if (this.gradient > 1) this.gradient = 1; this._time = performance.now(); } } Object.defineProperties(CircleWaveMaterialProperty.prototype, { isConstant: { get: function () { return false; } }, definitionChanged: { get: function () { return this._definitionChanged; } }, color: Cesium.createPropertyDescriptor('color') }); CircleWaveMaterialProperty.prototype.getType = function (time) { return Cesium.Material.CircleWaveMaterialType; } CircleWaveMaterialProperty.prototype.getValue = function (time, result) { if (!Cesium.defined(result)) { result = {}; } result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color); result.time = (performance.now() - this._time) / this.duration; result.count = this.count; result.gradient = 1 + 10 * (1 - this.gradient); return result; } CircleWaveMaterialProperty.prototype.equals = function (other) { return this === other || (other instanceof CircleWaveMaterialProperty && Cesium.Property.equals(this._color, other._color)) } Cesium.Material.CircleWaveMaterialType = 'CircleWaveMaterial'; Cesium.Material.PolylineTrailSource = `czm_material czm_getMaterial(czm_materialInput materialInput)\n {\n czm_material material = czm_getDefaultMaterial(materialInput);\n material.diffuse = 1.5 * color.rgb;\n vec2 st = materialInput.st;\n vec3 str = materialInput.str;\n float dis = distance(st, vec2(0.5, 0.5));\n float per = fract(time);\n if (abs(str.z) > 0.001) {\n discard;\n }\n if (dis > 0.5) { \n discard; \n } else { \n float perDis = 0.5 / count;\n float disNum; \n float bl = .0; \n for (int i = 0; i <= 999; i++) { \n if (float(i) <= count) { \n disNum = perDis * float(i) - dis + per / count; \n if (disNum > 0.0) { \n if (disNum < perDis) { \n bl = 1.0 - disNum / perDis;\n }\n else if (disNum - perDis < perDis) { \n bl = 1.0 - abs(1.0 - disNum / perDis); \n } \n material.alpha = pow(bl, gradient); \n } \n } \n } \n } \n return material; \n } \n`; Cesium.Material._materialCache.addMaterial(Cesium.Material.CircleWaveMaterialType, { fabric: { type: Cesium.Material.CircleWaveMaterialType, uniforms: { color: new Cesium.Color(1.0, 0.0, 0.0, 1.0), time: 1, count: 1, gradient: 0.1 }, source: Cesium.Material.PolylineTrailSource }, translucent: function (material) { return !0; } }); Cesium.CircleWaveMaterialProperty = CircleWaveMaterialProperty;
调用前需要存在此方法,也就是得全局调用一次,让cesium拥有雷达圈得类
require("./CircleWaveMaterialProperty");
调用
viewer.entities.add({ position: new Cesium.Cartesian3.fromDegrees(lon, lat, h), ellipse: { height: 1, semiMinorAxis: 1000, semiMajorAxis: 1000, material: new Cesium.CircleWaveMaterialProperty({ duration: 2e3, gradient: 0.5, color: new Cesium.Color(1.0, 0.0, 0.0, 1.0), count: 2, }), disableDepthTestDistance: Number.POSITIVE_INFINITY, distanceDisplayCondition: new Cesium.DistanceDisplayCondition( 0, height ), }, clampToGround: true, billboard: { image: this.renderText(name), horizontalOrigin: Cesium.HorizontalOrigin.CENTER, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, alignedAxis: Cesium.Cartesian3.ZERO, disableDepthTestDistance: Number.POSITIVE_INFINITY, pixelOffset: new Cesium.Cartesian2(0, -40), distanceDisplayCondition: new Cesium.DistanceDisplayCondition( 0, height ), }, });
点击某个图层出现对应弹窗
注意: 因为是监听每一帧的事件, 弹窗太多cesium必会卡顿!
// 创建弹窗对象的方法 const Popup = function (info) { this.constructor(info); }; Popup.prototype.id = 0; Popup.prototype.constructor = function (info) { const _this = this; _this.viewer = info.viewer;//弹窗创建的viewer _this.geometry = info.geometry;//弹窗挂载的位置 _this.id = "popup_" + _this.__proto__.id++; _this.html = info.html const dom = document.createElement('div'); dom.className = 'bx-popup-ctn'; dom.id = _this.id; _this.ctn = dom; _this.viewer.container.appendChild(_this.ctn); _this.ctn.insertAdjacentHTML('beforeend', _this.createHtml(info.title, info.data)); _this.render(_this.geometry); _this.viewer.scene.postRender.addEventListener(_this.eventListener, _this) } Popup.prototype.eventListener = function () { this.render.call(this, this.geometry); } // 弹窗的内容 Popup.prototype.createHtml = function (title, data) { window.pop = this return ` <div class="cesium-pupop-title"> <h1 class="title">${title}</h1> <span class="iconfont icon-cha1" style="position: absolute;color: #00fbfb;top: 33px;right: 30px;cursor:pointer;" onclick="pop.close()"></span> ${data.length > 0 ? data.map(v => `<div class="cesium-row"><span>${v.name}:</span> <span>${v.value}</span></div>`).join('') : '<div class="cesium-row" style="color: #fff;text-align: center;height: 200px;line-height: 200px;">暂无属性</div>'} </div>` } // 重点是实时刷新 Popup.prototype.render = function (geometry) { var _this = this; var position = Cesium.SceneTransforms.wgs84ToWindowCoordinates(_this.viewer.scene, geometry) _this.ctn.style.left = `${position.x - Math.floor(_this.ctn.offsetWidth / 2)}px` _this.ctn.style.top = `${position.y - _this.ctn.offsetHeight - 10}px` } // 关闭弹窗按钮 Popup.prototype.close = function () { var _this = this; _this.ctn.remove(); // _this.viewer.clock.onTick.removeEventListener(_this.eventListener); _this.viewer.scene.postRender.removeEventListener(_this.eventListener, _this) } export default Popup;
调用
new CesiumPopup({ viewer: viewer, geometry: polyCenter, // 这个坐标是世界坐标也就是笛卡尔坐标! title: entity._name, data: ddd });
拿到图层后如何设置图层高度
const osgbLayer = viewer.scene.addS3MTilesLayerByScp(url, { name: row }) Cesium.when(osgbLayer, function (row) { if (node.data.DisplayHeight) { // 设置海拔高度 row._style3D.bottomAltitude = node.data.DisplayHeight } })
拿到图层后如何设置图层可见高度
const osgbLayer = viewer.scene.addS3MTilesLayerByScp(url, { name: row }) Cesium.when(osgbLayer, function (row) { // 可见海拔高度设置 // row.maxVisibleAltitude = node.data.MaxDisplayHeight // 设置相机和图层的可见距离 row.visibleDistanceMax = layer.DisplayHeight || 100000; })
设置地形
viewer.terrainProvider = terrainProvider = new Cesium.CesiumTerrainProvider({ // url形如: http://172.18.1.106:8090/iserver/services/3D-SuiZhouDianChang/rest/realspace/datas/图层名称 url: url + '/datas/' + name, isSct: true })
加载影像
viewer.imageryLayers.addImageryProvider(new Cesium.UrlTemplateImageryProvider({ url: _url, tilingScheme: new Cesium.WebMercatorTilingScheme(), subdomains: '1234', }));
加载服务器贴图
viewer.imageryLayers.addImageryProvider(new Cesium.SuperMapImageryProvider({ url: '/iserver/services/3D-QuanMuTangChuSheFaBu/rest/realspace/datas/xxx影像缓存', }));
获取实体属性
首先拿到选中的图层及其SMID
// 获取到选中的layer const selectedLayer = scene.layers.getSelectedLayer(); if (selectedLayer) { var selectedSmid = parseInt(selectedLayer.getSelection()); //取得超图属性 if(callback){ // 拿到layer和smid就行了 callback(selectedLayer, selectedSmid) } }
根据SMID查询属性
doSqlQuery(sqlStr, dataSerice, dataset, datasource) { const _this = this; const sqlParameter = { "datasetNames": [`${datasource}:${dataset}`], getFeatureMode: "SQL", queryParameter: { attributeFilter: sqlStr } }; const url = `/iserver/services/${dataSerice}/data/featureResults.json?returnContent=true&token=${eval(localStorage.getItem('TOKEN_ISERVER'))}` const queryData = JSON.stringify(sqlParameter); const IGNOREFIELD = JSON.parse(localStorage.getItem('IGNOREFIELD')) _this.loading = true $.ajax({ type: "post", url: url, data: queryData, success: function (result) { if (result.features && result.features.length > 0) { const data = result.features[0] const fieldNames = data.fieldNames const fieldValues = data.fieldValues _this.moduleListData = [] fieldNames.forEach((row, i) => { if (IGNOREFIELD.indexOf(row) !== -1) return _this.moduleListData.push({ Name: row, Value: fieldValues[i] }) }) } else { _this.$message.info('没有查询到属性!') } _this.loading = false }, error: function () { _this.$message.info('没有查询到属性!') _this.loading = false }, }) } // 这么调用 this.doSqlQuery('SmID=' + this.relationListCode[1], layer.DataService, layer.SurMapDataSet, layer.DataSource)
设置图层透明度
function translucentLayers(scene, alpha) { for (var i = 0; i < scene.layers.layerQueue.length; i++) { var layer = scene.layers.findByIndex(i); if (layer) { layer.style3D.fillForeColor.alpha = parseFloat(alpha); } } }
设置影像透明度
const _layers = viewer.imageryLayers._layers for (let i = 0, len = _layers.length; i < len; i++) { _layers[i].alpha = 0.6 }
监听点击事件
const events = { click: "LEFT_CLICK", wheel: "WHEEL", middleClick: "MIDDLE_DOWN", mouseMove: "MOUSE_MOVE" } viewer.screenSpaceEventHandler.setInputAction(e => { this.$emit(key, e) }, Cesium.ScreenSpaceEventType[events[key]])
通过超图名称获取图层
viewer.scene.layers.find(SuperLayerName)
设置更改构件颜色
layer.setObjsColor(ids, cesiumColor);
其中:
- layer是图层对象
- ids是smid数组
- cesiumColor是cesium的颜色对象
如果只需要影响一个构件使用此方法
layer.setOnlyObjsColor(smId, cesiumColor);
通过图层获取其下的所有smid
layer._selections
返回的是["3762", "123"]这样的smid集合
隐藏构件
layer.setObjsVisible(ids, bool)
其中
- layer是图层对象
- ids是smid集合
- bool是是否显示, true为显示 false为隐藏
将图层下的构件全部显示只需要将ids设置为[]即可
layer.setObjsVisible([], false);
如果只需要影响一个构件使用此方法
layer.setOnlyObjsVisible(smid, bool)
设置光源跟随摄像头
//设置光源跟随 var degZ = 0;//水平夹角 var degX = 0; //垂直夹角 scene.sun.show = false; // 设置环境光的强度 scene.lightSource.ambientLightColor = new Cesium.Color(0.86,0.86, 0.86, 1); // var position1 = new Cesium.Cartesian3.fromDegrees(117.61862360516848 - 0.000009405717451407729 * 86.6, 40.2317259501307 - 0.00000914352698135 * 50, 350); // 设置初始光源位置 var position1 = new Cesium.Cartesian3.fromDegrees(117.61862360516848, 32.19180102105889, 350); var targetPosition1 = new Cesium.Cartesian3.fromDegrees(117.61862360516848, 32.19180102105889, 130); var dirLightOptions = { targetPosition: targetPosition1, color: new Cesium.Color(1.0, 1.0, 1.0, 1), intensity: 0.7 }; directionalLight_1 = new Cesium.DirectionalLight(position1, dirLightOptions); scene.addLightSource(directionalLight_1); scene.postRender.addEventListener(function () { // 每一帧 非常耗性能 var cameraPosition = Cesium.Cartesian3.clone(scene.camera.position); var length = 100; var quad1 = Cesium.Quaternion.fromAxisAngle(viewer.scene.camera.upWC, Cesium.Math.toRadians(degZ)); var quad2 = Cesium.Quaternion.fromAxisAngle(viewer.scene.camera.rightWC, Cesium.Math.toRadians(degX)); var resQuad = Cesium.Quaternion.add(quad2, quad1, quad1); var rotation = Cesium.Matrix3.fromQuaternion(resQuad); var direction = Cesium.Matrix3.multiplyByVector(rotation, viewer.scene.camera.directionWC, new Cesium.Cartesian3()); var targetPosition2 = Cesium.Cartesian3.add( viewer.scene.camera.positionWC, Cesium.Cartesian3.multiplyByScalar(direction, length, new Cesium.Cartesian3()), new Cesium.Cartesian3() ); directionalLight_1.position = cameraPosition; directionalLight_1.targetPosition = targetPosition2; });
点击某个点出现弹窗并且使用Vue组件完成
Pop.js
// 创建弹窗对象的方法 import Vue from 'vue' const Popup = function (info, component) { this.constructor(info, component) } Popup.prototype.id = 0 Popup.prototype.constructor = function (info, component) { const _this = this window.pop = this _this.viewer = info.viewer// 弹窗创建的viewer _this.geometry = info.geometry// 弹窗挂载的位置 // eslint-disable-next-line no-proto _this.id = 'popup_' + _this.__proto__.id++ _this.html = info.html const dom = document.createElement('div') dom.className = 'bx-popup-ctn' dom.id = _this.id _this.ctn = dom // 主要步骤 if (component) { const vuecomponent = Vue.extend(component) // eslint-disable-next-line new-cap const c = new vuecomponent().$mount() _this.ctn.appendChild(c.$el) } else { _this.ctn.insertAdjacentHTML('beforeend', _this.createHtml(info.title, info.data)) } _this.viewer.container.appendChild(_this.ctn) _this.viewer.scene.postRender.addEventListener(_this.eventListener, _this) } Popup.prototype.eventListener = function () { this.render(this.geometry) } // 弹窗的内容 Popup.prototype.createHtml = function (title, data) { let html if (Object.prototype.toString.call(data) === '[object Array]') { html = data.reduce((acc, val) => { return acc + `<div class="bx-attribute-item"> <span class="bx-attr-name">${val.PropertyName}</span> <span class="bx-attr-name">${val.value}</span> </div>` }, '') } else { html = data } return ` <div class="bx-popup"> <img src="${require('./image/attribute/ff.png')}" alt=""/> <div class="bx-content"> <div class="bx-top"></div> <div class="bx-bd-c-bottom"></div> <div class="bx-bd-c-left"></div> <div class="bx-bd-c-right"></div> <div class="bx-bd-dashed-top"></div> <div class="bx-bd-dashed-left"></div> <div class="bx-bd-dashed-bottom"></div> <div class="bx-bd-dashed-right"></div> <img src="${require('./image/attribute/hh.png')}" alt="" class="bx-bd-dashed-c-bottom"/> <img src="${require('./image/attribute/gg.png')}" alt="" class="bx-bd-bottom"/> <img src="${require('./image/attribute/cc.png')}" alt="" class="bx-bd-right"/> <div class="bx-body"> <h1 class="bx-title">${title}</h1> <div class="bx-body-content"> ${html} </div> </div> </div> </div> ` } // 重点是实时刷新 Popup.prototype.render = function (geometry) { const _this = this const position = Cesium.SceneTransforms.wgs84ToWindowCoordinates(_this.viewer.scene, geometry) if (position) { _this.ctn.style.left = `${position.x}px` _this.ctn.style.top = `${position.y - _this.ctn.offsetHeight / 2 - 10}px` } } // 关闭弹窗按钮 Popup.prototype.close = function () { const _this = this _this.viewer.scene.postRender.removeEventListener(_this.eventListener, _this) _this.ctn.remove() // _this.viewer.clock.onTick.removeEventListener(_this.eventListener); } export default Popup
使用时
new Popup({ viewer, geometry: e.data.position, title: '门禁信息', data: '<div>Fuck</div>' }, AccessControl)
其中: AccessControl是vue组件!
import AccessControl from '@/components/AccessControl.vue'
主要使用了Vue的$mount()
方法
获取相机信息
viewer.scene.camera
将世界坐标转换为屏幕坐标
Cesium.SceneTransforms.wgs84ToWindowCoordinates(scene, geometry)
其中
- scene 是场景
- geometry 是世界坐标
根据CSS颜色值创建一个Color实例。
Cesium.Color.fromCssColorString('#67ADDF');
Cesium颜色数值和常规HTML颜色数值的转换公式
经过一番调研,发现Cesium.Color(r, g,b,a)中, r,g,b,a的值均在0-1之间.和html rgba的换算如下:
Cesium.Color(html.r/255, html.g/255, html.b/255, html.a)
js方法如下, 其中colorString必须是16进制色
colorConvert(colorString) { const red = parseInt(colorString.slice(1, 3), 16) / 255; const green = parseInt(colorString.slice(3, 5), 16) / 255; const blue = parseInt(colorString.slice(5, 7), 16) / 255; return new Cesium.Color(red, green, blue, 1); },
聚合label、广告牌
_this.clusteringlayer = new Cesium.CustomDataSource('clusteringlayer'); const pixelRange = 50; const minimumClusterSize = 2; const enabled = true; //启用集群 _this.clusteringlayer.clustering.enabled = enabled; //设置扩展屏幕空间边界框的像素范围。 _this.clusteringlayer.clustering.pixelRange = pixelRange; //可以群集的最小屏幕空间对象 _this.clusteringlayer.clustering.minimumClusterSize = minimumClusterSize; //将进行实体的广告牌聚类 _this.clusteringlayer.clustering.clusterBillboards = true; var removeListener; //自定义地图图钉生成为画布元素 var pinBuilder = new Cesium.PinBuilder(); customStyle(); function customStyle() { if (Cesium.defined(removeListener)) { removeListener(); removeListener = undefined; } else { removeListener = _this.clusteringlayer.clustering.clusterEvent.addEventListener(function(clusteredEntities, cluster) { cluster.label.show = false; cluster.billboard.show = true; cluster.billboard.id = cluster.label.id; cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM; cluster.billboard.disableDepthTestDistance = Number.POSITIVE_INFINITY; //文本将被调整为尽可能大的大小同时仍完全包含在图钉中 // var pinimg = pinBuilder.fromText(clusteredEntities.length, Cesium.Color.BLUE, 50).toDataURL(); // var pinimg='./images/location4.png'; if (clusteredEntities?.[0]?._name) cluster.billboard.image = _this.renderText(clusteredEntities[0]._name, undefined, undefined, 14); //cluster.billboard.scale=0.2; }); } } // 对于需要聚合的实体使用 // _this.clusteringlayer.entities.add(entity) // 添加到viewer中 viewer.dataSources.add(_this.clusteringlayer)
超图动态绘标汇总
初始化绘标以及加载标注库
methods: { // 初始化 InitPlot(viewer, serverUrl) { if (!viewer) { return; } const _this = this; const plottingLayer = new Cesium.PlottingLayer( viewer.scene, 'plottingLayer' ); this.plottingLayer = plottingLayer; viewer.scene.plotLayers.add(plottingLayer); const plotting = Cesium.Plotting.getInstance( serverUrl, viewer.scene ); this.plotting = plotting; this.plotEditControl = new Cesium.PlotEditControl( viewer.scene, plottingLayer ); //编辑控件 this.plotEditControl.activate(); this.plotDrawControl = new Cesium.PlotDrawControl( viewer.scene, plottingLayer ); //绘制控件 this.plotDrawControl.drawControlEndEvent.addEventListener( function() { //标绘结束,激活编辑控件 _this.plotEditControl.activate(); } ); this.loadSymbolLib(plotting); console.log(plotting.getDefaultStyle()); // 一些缺省属性,不需要可以删除 plotting.getDefaultStyle().lineWidth = this.thickness; plotting.getDefaultStyle().lineColor = this.colorConvert( this.color ); plotting.getDefaultStyle().defaultFlag = true; }, // 加载标注库 loadSymbolLib(plotting) { const symbolLibManager = plotting.getSymbolLibManager(); if (symbolLibManager.isInitializeOK()) { // isok } else { symbolLibManager.initializecompleted.addEventListener( function(result) { if (result.libIDs.length !== 0) { // isok } } ); symbolLibManager.initializeAsync(); } }, }
只需要执行InitPlot
方法即可
this.InitPlot( viewer, '/iserver/services/plot-jingyong/rest/plot' );
不使用面板如何画标
handleDraw(id, code) { this.plotDrawControl.setAction(id, code); this.plotDrawControl.activate(); this.plotEditControl.deactivate(); },
绘标需要一个id和code, 那么如何获取id和code?
-
如果是基本标记(线之类的)
http://support.supermap.com.c...可以点击画好的标注查看属性,属性中有id和code
-
除了基本标记外
http://${ip或域名}/iserver/services/plot-jingyong/rest/plot/symbolLibs/
可以看到所有的标记库
如何预定义样式
修改超图默认的标注颜色等
plotting.getDefaultStyle().lineWidth = this.thickness;
可以从控制台中看到plotting.getDefaultStyle()中所有的缺省属性,直接赋值就可以修改缺省属性
标签:function,SuperMap,const,viewer,汇总,scene,Cesium,new 来源: https://www.cnblogs.com/yaohuimo/p/16357274.html