/** * 等高线 */ import Dialog from "../../Obj/Element/Dialog"; import Tools from "../../Tools"; import { flyTo } from '../global' import YJColorPicker from "../../Obj/Element/yj-color-picker"; import { html } from "./_element"; let _DialogObject = null; let material = null; let handler = null; let activeHeightElm = null; let tools let _sdk let secondaryLinesCount = 19 let show = false let equalHeightDistance = 10 let activeColor = '#ffd000' let indexContourShow = true let indexContourWidth = 2.5 let indexContourColor = '#43cf7c' let intermediateContourShow = true let intermediateContourWidth = 1.8 let intermediateContourColor = '#ff0000' let halfIntervalContourShow = false let halfIntervalContourWidth = 1.0 let halfIntervalContourColor = '#64b6d9' let supplementaryContourShow = false let supplementaryContourWidth = 1.0 let supplementaryContourColor = '#d084d1' activeHeightElm = document.createElement('div') activeHeightElm.className = 'YJ-customize-active-height-elm' activeHeightElm.style.position = 'absolute' activeHeightElm.style.left = '10px' activeHeightElm.style.top = '10px' activeHeightElm.style.width = '100px' // activeHeightElm.style.backgroundColor = 'rgba(0, 0, 0, 0.5)' activeHeightElm.style.textAlign = 'center' activeHeightElm.style.pointerEvents = 'none' activeHeightElm.style.color = '#ff0000' activeHeightElm.style.display = 'none' function accordingToCameraHeight() { if (_sdk) { const camera = _sdk.viewer.camera; const position = camera.positionCartographic; // 计算相机高度(相对于椭球面) let cameraHeight = Cesium.Math.toDegrees(position.height); if (cameraHeight < 1000000) { if (!_sdk.viewer.scene.globe.material && show === true) { showContour(_sdk) } // if (material) { // if (cameraHeight > 450000) { // material.uniforms.supplementaryContourShow = false // } // else if (supplementaryContourShow) { // material.uniforms.supplementaryContourShow = true // } // } } else { hideContour(_sdk) } // console.log(cameraHeight) } } async function dialog(sdk) { _sdk = sdk if (!sdk || _DialogObject) { return } if (!material) { createMaterial() } if (!tools) { tools = new Tools(sdk) } _DialogObject = await new Dialog(sdk, {}, { title: "等高线", left: '180px', top: '100px', closeCallBack: () => { _DialogObject = null } }); _DialogObject._element.body.className = _DialogObject._element.body.className + ' contour' let contentElm = document.createElement('div') contentElm.innerHTML = html(this) _DialogObject.contentAppChild(contentElm) sdk.viewer.scene.postRender.removeEventListener(accordingToCameraHeight) sdk.viewer.scene.postRender.addEventListener(accordingToCameraHeight) // 显示 let showBtn = contentElm.getElementsByClassName('show')[0] showBtn.checked = show showBtn.addEventListener('change', (e) => { if (e.target.checked) { show = true let height = sdk.viewer.camera.positionCartographic.height if(height>16360) { let cartographic = sdk.viewer.camera.positionCartographic let options = { position: { lng: Cesium.Math.toDegrees(cartographic.longitude), lat: Cesium.Math.toDegrees(cartographic.latitude), alt: 16360, }, } flyTo(sdk, options, 0.5) } showContour(sdk) } else { show = false hideContour(sdk) } }) // 等高距 let equalHeightDistanceInput = contentElm.getElementsByClassName('equal-height-distance')[0] equalHeightDistanceInput.value = equalHeightDistance equalHeightDistanceInput.addEventListener('blur', (e) => { let value = initInputValue(e) equalHeightDistance = value equalHeightDistanceInput.value = value if (material) { material.uniforms.spacing = equalHeightDistance * 5 } }) // 选中颜色 // let activeColorPicker = new YJColorPicker({ // el: contentElm.getElementsByClassName('active-color')[0], // size: "mini", // isLog: false, // alpha: true, //是否开启透明度 // disabled: false, //是否禁止打开颜色选择器 // predefineColor: true, // 预定义颜色 // defaultColor: '#ffffff', // sure: color => { // activeColor = color // if (material) { // material.uniforms.activeColor = Cesium.Color.fromCssColorString(activeColor) // } // }, // clear: () => { // activeColor = 'rgba(255,255,255,1)' // if (material) { // material.uniforms.activeColor = Cesium.Color.fromCssColorString(activeColor) // } // } // }) let activeColorPicker = new ewPlugins('colorpicker', { el: contentElm.getElementsByClassName('active-color')[0], size: 'mini',//颜色box类型 alpha: true,//是否开启透明度 defaultColor: activeColor, disabled: false,//是否禁止打开颜色选择器 openPickerAni: 'opacity',//打开颜色选择器动画 sure: color => { activeColor = color if (material) { material.uniforms.activeColor = Cesium.Color.fromCssColorString(activeColor) } }, clear: () => { activeColor = 'rgba(255,255,255,1)' if (material) { material.uniforms.activeColor = Cesium.Color.fromCssColorString(activeColor) } } }) // 计曲线开关 let indexContourSwitch = contentElm.getElementsByClassName('index-contour-switch')[0] indexContourSwitch.checked = indexContourShow indexContourSwitch.addEventListener('change', (e) => { indexContourShow = e.target.checked if (material) { material.uniforms.indexContourShow = indexContourShow } }) // 计曲线颜色 let indexContourColorPicker = new ewPlugins('colorpicker', { el: contentElm.getElementsByClassName('index-contour-color')[0], size: 'mini',//颜色box类型 alpha: true,//是否开启透明度 defaultColor: indexContourColor, disabled: false,//是否禁止打开颜色选择器 openPickerAni: 'opacity',//打开颜色选择器动画 sure: color => { indexContourColor = color if (material) { material.uniforms.indexContourColor = Cesium.Color.fromCssColorString(indexContourColor) } }, clear: () => { indexContourColor = 'rgba(255,255,255,1)' if (material) { material.uniforms.indexContourColor = Cesium.Color.fromCssColorString(indexContourColor) } } }) // 计曲线宽度 let indexContourWidthInput = contentElm.getElementsByClassName('index-contour-width')[0] indexContourWidthInput.value = indexContourWidth indexContourWidthInput.addEventListener('blur', (e) => { let value = initInputValue(e) indexContourWidth = value indexContourWidthInput.value = value if (material) { material.uniforms.indexContourWidth = indexContourWidth } }) // 首曲线开关 let intermediateContourSwitch = contentElm.getElementsByClassName('intermediate-contour-switch')[0] intermediateContourSwitch.checked = intermediateContourShow intermediateContourSwitch.addEventListener('change', (e) => { intermediateContourShow = e.target.checked if (material) { material.uniforms.intermediateContourShow = intermediateContourShow } }) // 首曲线颜色 let intermediateContourColorPicker = new ewPlugins('colorpicker', { el: contentElm.getElementsByClassName('intermediate-contour-color')[0], size: 'mini',//颜色box类型 alpha: true,//是否开启透明度 defaultColor: intermediateContourColor, disabled: false,//是否禁止打开颜色选择器 openPickerAni: 'opacity',//打开颜色选择器动画 sure: color => { intermediateContourColor = color if (material) { material.uniforms.intermediateContourColor = Cesium.Color.fromCssColorString(intermediateContourColor) } }, clear: () => { intermediateContourColor = 'rgba(255,255,255,1)' if (material) { material.uniforms.intermediateContourColor = Cesium.Color.fromCssColorString(intermediateContourColor) } } }) // 首曲线宽度 let intermediateContourWidthInput = contentElm.getElementsByClassName('intermediate-contour-width')[0] intermediateContourWidthInput.value = intermediateContourWidth intermediateContourWidthInput.addEventListener('blur', (e) => { let value = initInputValue(e) intermediateContourWidth = value intermediateContourWidthInput.value = value if (material) { material.uniforms.intermediateContourWidth = intermediateContourWidth } }) // 间曲线开关 let halfIntervalContourSwitch = contentElm.getElementsByClassName('halfInterval-contour-switch')[0] halfIntervalContourSwitch.checked = halfIntervalContourShow halfIntervalContourSwitch.addEventListener('change', (e) => { halfIntervalContourShow = e.target.checked if (material) { material.uniforms.halfIntervalContourShow = halfIntervalContourShow } }) // 间曲线颜色 let halfIntervalContourColorPicker = new ewPlugins('colorpicker', { el: contentElm.getElementsByClassName('halfInterval-contour-color')[0], size: 'mini',//颜色box类型 alpha: true,//是否开启透明度 defaultColor: halfIntervalContourColor, disabled: false,//是否禁止打开颜色选择器 openPickerAni: 'opacity',//打开颜色选择器动画 sure: color => { halfIntervalContourColor = color if (material) { material.uniforms.halfIntervalContourColor = Cesium.Color.fromCssColorString(halfIntervalContourColor) } }, clear: () => { halfIntervalContourColor = 'rgba(255,255,255,1)' if (material) { material.uniforms.halfIntervalContourColor = Cesium.Color.fromCssColorString(halfIntervalContourColor) } } }) // 间曲线宽度 let halfIntervalContourWidthInput = contentElm.getElementsByClassName('halfInterval-contour-width')[0] halfIntervalContourWidthInput.value = halfIntervalContourWidth halfIntervalContourWidthInput.addEventListener('blur', (e) => { let value = initInputValue(e) halfIntervalContourWidth = value halfIntervalContourWidthInput.value = value if (material) { material.uniforms.halfIntervalContourWidth = halfIntervalContourWidth } }) // 助曲线开关 let supplementaryContourSwitch = contentElm.getElementsByClassName('supplementary-contour-switch')[0] supplementaryContourSwitch.checked = supplementaryContourShow supplementaryContourSwitch.addEventListener('change', (e) => { supplementaryContourShow = e.target.checked if (material) { material.uniforms.supplementaryContourShow = supplementaryContourShow } }) // 助曲线颜色 let supplementaryContourColorPicker = new ewPlugins('colorpicker', { el: contentElm.getElementsByClassName('supplementary-contour-color')[0], size: 'mini',//颜色box类型 alpha: true,//是否开启透明度 defaultColor: supplementaryContourColor, disabled: false,//是否禁止打开颜色选择器 openPickerAni: 'opacity',//打开颜色选择器动画 sure: color => { supplementaryContourColor = color if (material) { material.uniforms.supplementaryContourColor = Cesium.Color.fromCssColorString(supplementaryContourColor) } }, clear: () => { supplementaryContourColor = 'rgba(255,255,255,1)' if (material) { material.uniforms.supplementaryContourColor = Cesium.Color.fromCssColorString(supplementaryContourColor) } } }) // 助曲线宽度 let supplementaryContourWidthInput = contentElm.getElementsByClassName('supplementary-contour-width')[0] supplementaryContourWidthInput.value = supplementaryContourWidth supplementaryContourWidthInput.addEventListener('blur', (e) => { let value = initInputValue(e) supplementaryContourWidth = value supplementaryContourWidthInput.value = value if (material) { material.uniforms.supplementaryContourWidth = supplementaryContourWidth } }) function initInputValue(e) { let value = e.target.value if (e.target.value || (e.target.dataset.null !== 'undefined' && e.target.dataset.null !== '' && !Boolean(e.target.dataset.null))) { value = Number(value) if ((e.target.max) && value > Number(e.target.max)) { value = Number(e.target.max) } if ((e.target.min) && value < Number(e.target.min)) { value = Number(e.target.min) } if ((e.target.dataset.min) && value < Number(e.target.dataset.min)) { value = Number(e.target.dataset.min) } } return value } } function showContour(sdk) { const camera = sdk.viewer.camera; const position = camera.positionCartographic; // 计算相机高度(相对于椭球面) let cameraHeight = Cesium.Math.toDegrees(position.height); if (cameraHeight > 1000000) { return } if (handler) { handler.destroy() } if (!sdk.viewer.container.getElementsByClassName('YJ-customize-active-height-elm')[0]) { sdk.viewer.container.appendChild(activeHeightElm) } handler = new Cesium.ScreenSpaceEventHandler( sdk.viewer.canvas ) handler.setInputAction((movement) => { let cartesian = sdk.viewer.scene.pickPosition(movement.endPosition) if (cartesian) { let top = 0 let left = 0 if (sdk.viewer && sdk.viewer._element) { let element = sdk.viewer._element.getElementsByClassName('cesium-widget')[0].getElementsByTagName('canvas')[0] top = element.getBoundingClientRect().top + window.scrollY left = element.getBoundingClientRect().left + window.scrollX } activeHeightElm.style.left = movement.endPosition.x - 50 + left + 'px' activeHeightElm.style.top = movement.endPosition.y - 40 + top + 'px' activeHeightElm.style.display = 'block' // let pos = sdk.viewer.scene.clampToHeight(cartesian) let pos84 = tools.cartesian3Towgs84(cartesian, sdk.viewer) // pos84.alt = height let mainContourHeight = Math.floor(pos84.alt / material.uniforms.spacing) * material.uniforms.spacing let gap = pos84.alt - mainContourHeight let gap2 = material.uniforms.spacing / (material.uniforms.secondaryLinesCount + 1) let activeHeight = Math.floor(gap / gap2) * gap2 + mainContourHeight if ((pos84.alt - activeHeight) > gap2 / 2) { activeHeight = activeHeight + gap2 } material.uniforms.mouseHeight = pos84.alt material.uniforms.mousePosition = cartesian activeHeightElm.innerHTML = `${activeHeight.toFixed(0)}` } else { activeHeightElm.style.display = 'none' } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE) sdk.viewer.scene.globe.material = material; } function hideContour(sdk) { if (handler) { handler.destroy() handler = null } if (sdk.viewer.container.getElementsByClassName('YJ-customize-active-height-elm')[0]) { activeHeightElm.style.display = 'none' sdk.viewer.container.removeChild(activeHeightElm) } sdk.viewer.scene.globe.material = null; } function createMaterial() { Cesium.Material._materialCache._materials.ElevationContour.fabric.source = ` uniform vec4 activeColor; // 选中颜色 uniform float spacing; // 等高距 // 计曲线 uniform bool indexContourShow; uniform float indexContourWidth; uniform vec4 indexContourColor; // 首曲线 uniform bool intermediateContourShow; uniform float intermediateContourWidth; uniform vec4 intermediateContourColor; // 间曲线 uniform bool halfIntervalContourShow; uniform float halfIntervalContourWidth; uniform vec4 halfIntervalContourColor; // 助曲线 uniform bool supplementaryContourShow; uniform float supplementaryContourWidth; uniform vec4 supplementaryContourColor; uniform float mouseHeight; uniform float secondaryLinesCount; // 0=无次线, 1=1条次线, 2=2条次线... czm_material czm_getMaterial(czm_materialInput materialInput) { czm_material material = czm_getDefaultMaterial(materialInput); // 主等高线计算 float distanceToMainContour = mod(materialInput.height, spacing); // 抗锯齿计算 #if (__VERSION__ == 300 || defined(GL_OES_standard_derivatives)) float dxc = abs(dFdx(materialInput.height)); float dyc = abs(dFdy(materialInput.height)); float dFMain = max(dxc, dyc) * czm_pixelRatio * indexContourWidth; #else float dFMain = czm_pixelRatio * indexContourWidth; #endif bool isMainContour = distanceToMainContour < dFMain; bool isSecondaryContour = false; float dFSecondary = 0.0; float secondarySpacing = 0.0; bool isHalfInterval = false; bool isIntermediate= false; // 计算当前高度所属的等高线高度 float mainContourHeight = floor(materialInput.height / spacing) * spacing; float secondaryContourHeight = floor(materialInput.height / spacing * (secondaryLinesCount + 1.0)) * spacing / (secondaryLinesCount + 1.0); // 计算次线在两条主等高线之间的相对位置 float relativeHeight = materialInput.height - mainContourHeight; float normalizedPosition = relativeHeight / spacing; // 计算次线索引(从主等高线开始计数) float lineIndex = floor(normalizedPosition * (secondaryLinesCount + 1.0)); // 只有当存在次线时才计算次线 if(secondaryLinesCount > 0.0) { float secondaryLinesWidth = supplementaryContourWidth; secondarySpacing = spacing / (secondaryLinesCount + 1.0); float distanceToSecondaryContour = mod(materialInput.height, secondarySpacing); // 确保次线不会与主线重叠 float minDistanceToMain = min(distanceToMainContour, spacing - distanceToMainContour); bool notCloseToMain = minDistanceToMain > dFMain * 2.0; // 2倍线宽缓冲 if (lineIndex > 0.0 && lineIndex < secondaryLinesCount) { // 使用mod函数检查余数是否接近0(考虑浮点数精度问题) isHalfInterval = abs(mod(lineIndex, 2.0)) < 0.01; if(isHalfInterval) { secondaryLinesWidth = halfIntervalContourWidth; } // 使用mod函数检查余数是否接近0(考虑浮点数精度问题) isIntermediate = abs(mod(lineIndex, 4.0)) < 0.01; if(isIntermediate) { secondaryLinesWidth = intermediateContourWidth; } } #if (__VERSION__ == 300 || defined(GL_OES_standard_derivatives)) dFSecondary = max(dxc, dyc) * czm_pixelRatio * secondaryLinesWidth; #else dFSecondary = czm_pixelRatio * secondaryLinesWidth; #endif isSecondaryContour = (distanceToSecondaryContour < dFSecondary) && notCloseToMain; } // 高亮判断 bool shouldHighlight = false; if(isMainContour && abs(mainContourHeight - mouseHeight) < 0.5 * (spacing/(secondaryLinesCount+1.0))) { shouldHighlight = true; } else if(isSecondaryContour && abs(secondaryContourHeight - mouseHeight) < 0.5 * (spacing/(secondaryLinesCount+1.0))) { shouldHighlight = true; } // 颜色输出 vec4 outColor; if(shouldHighlight) { outColor = czm_gammaCorrect(vec4(activeColor.rgb, activeColor.a)); } else if(isMainContour) { float a = indexContourColor.a; if(!indexContourShow) { a = 0.0; } outColor = czm_gammaCorrect(vec4(indexContourColor.rgb, a)); } else if(isSecondaryContour) { float a = supplementaryContourColor.a; if(!supplementaryContourShow) { a = 0.0; } outColor = czm_gammaCorrect(vec4(supplementaryContourColor.rgb, a)); if(isHalfInterval) { float a = halfIntervalContourColor.a; if(!halfIntervalContourShow) { a = 0.0; } outColor = czm_gammaCorrect(vec4(halfIntervalContourColor.rgb, a)); } if(isIntermediate) { float a = intermediateContourColor.a; if(!intermediateContourShow) { a = 0.0; } outColor = czm_gammaCorrect(vec4(intermediateContourColor.rgb, a)); } } else { outColor = vec4(0.0); } material.diffuse = outColor.rgb; material.alpha = outColor.a; return material; } ` material = new Cesium.Material({ fabric: { type: "ElevationContour", uniforms: { spacing: 10 * 5, activeColor: Cesium.Color.fromCssColorString(activeColor), mouseHeight: -100000, mousePosition: new Cesium.Cartesian3(0, 0, 0), secondaryLinesCount: secondaryLinesCount, cameraHeight: 0, indexContourShow: indexContourShow, indexContourWidth: indexContourWidth, indexContourColor: Cesium.Color.fromCssColorString(indexContourColor), intermediateContourShow: intermediateContourShow, intermediateContourWidth: intermediateContourWidth, intermediateContourColor: Cesium.Color.fromCssColorString(intermediateContourColor), halfIntervalContourShow: halfIntervalContourShow, halfIntervalContourWidth: halfIntervalContourWidth, halfIntervalContourColor: Cesium.Color.fromCssColorString(halfIntervalContourColor), supplementaryContourShow: supplementaryContourShow, supplementaryContourWidth: supplementaryContourWidth, supplementaryContourColor: Cesium.Color.fromCssColorString(supplementaryContourColor), }, } }); } export { dialog }