'first-commit'

main
石超 2 years ago
commit df1240a026

31
.gitignore vendored

@ -0,0 +1,31 @@
.DS_Store
node_modules
/dist
public/lib/CesiumUnminified/
packages/mars3d/dist/plugins/
packages/mars3d/node_modules/
mars3d-*src.*
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# System Files
.DS_Store
Thumbs.db
package-lock.json

@ -0,0 +1,4 @@
# 地图基础封装
## node 版本 16+
## vue版本 3.2

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Mars3D最简项目模版 - Vue3+Vite版</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

@ -0,0 +1,42 @@
{
"name": "mars3d-vue-template",
"version": "3.6.0",
"description": "",
"main": "index.js",
"scripts": {
"serve": "vite",
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@element-plus/icons-vue": "^2.1.0",
"@turf/turf": "^6.5.0",
"axios": "^1.5.0",
"echarts": "^5.4.3",
"element-plus": "^2.3.14",
"mars3d": "~3.6.0",
"mars3d-cesium": "~1.109.0",
"mitt": "^3.0.1",
"vue": "^3.2.27"
},
"devDependencies": {
"@types/node": "^17.0.13",
"@vitejs/plugin-vue": "^4.0.0",
"@vitejs/plugin-vue-jsx": "^3.0.2",
"less": "^4.1.2",
"terser": "^5.16.1",
"typescript": "4.5.5",
"vite": "^4.3.9",
"vite-plugin-mars3d": "^3.0.0",
"vue-tsc": "^0.29.8"
},
"repository": {
"type": "git",
"url": "https://github.com/marsgis/mars3d-vue-template.git"
},
"bugs": {
"url": "https://github.com/marsgis/mars3d-vue-template/issues",
"email": "wh@marsgis.cn"
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 KiB

@ -0,0 +1,48 @@
<template>
<MarsMap :url="configUrl" map-key="map" @onload="marsOnload" />
<mapTree />
<mapControl />
<mapFenXi />
</template>
<script setup>
import * as mars3d from "mars3d";
import { getCurrentInstance } from "vue";
import MarsMap from "./components/map/mars-map.vue";
import mapTree from "./components/map/mapTree.vue";
import mapControl from "./components/map/mapControl.vue";
import mapFenXi from "./components/map/mapFenXi.vue";
import axios from "axios";
const configUrl = "config/config.json";
const Cesium = mars3d.Cesium;
const instance = getCurrentInstance();
const marsOnload = (map) => {
window.globalMap = map;
//
instance?.proxy?.$emitter.emit("mapOnLoad");
//MapTree
instance?.proxy?.$emitter.emit("loadLayerTree", map.options.layers);
//
let tiles3dLayer = new mars3d.layer.TilesetLayer({
name: "县城社区",
url: "http://192.168.10.118:8088/tileset.json",
cullRequestsWhileMoving:true,
skipLevelOfDetail:true,
skipLevels:25,
maximumScreenSpaceError:10,
cacheBytes:2536870912,
progressiveResolutionHeightFraction:0.1,
dynamicScreenSpaceErrorDensity:0.1,
dynamicScreenSpaceError: true,
preferLeaves:true,
preloadWhenHidden:true,
flyTo: true
})
map.addLayer(tiles3dLayer)
};
</script>
<style></style>

@ -0,0 +1,305 @@
.cesium-viewer-toolbar {
top: auto !important;
bottom: 35px !important;
left: 12px !important;
right: auto !important;
}
.cesium-toolbar-button img {
height: 100%;
}
.cesium-viewer-toolbar>.cesium-toolbar-button,
.cesium-navigationHelpButton-wrapper,
.cesium-viewer-geocoderContainer {
margin-bottom: 5px;
float: left;
clear: both;
text-align: center;
}
.cesium-button {
background-color: rgba(23, 49, 71, 0.8);
color: #e6e6e6;
fill: #e6e6e6;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
line-height: 32px;
}
.cesium-button:hover {
background: #3ea6ff;
}
/**cesium 底图切换面板*/
.cesium-baseLayerPicker-dropDown {
bottom: 0;
left: 40px;
max-height: 700px;
margin-bottom: 5px;
background-color: rgba(23, 49, 71, 0.8);
}
/**cesium 帮助面板*/
.cesium-navigation-help {
top: auto;
bottom: 0;
left: 40px;
transform-origin: left bottom;
background: none;
background-color: rgba(23, 49, 71, 0.8);
.cesium-navigation-help-instructions {
background: none;
}
.cesium-navigation-button {
background: none;
}
.cesium-navigation-button-selected,
.cesium-navigation-button-unselected:hover {
background: rgba(0, 138, 255, 0.2);
}
}
/**cesium 二维三维切换*/
.cesium-sceneModePicker-wrapper {
width: auto;
}
.cesium-sceneModePicker-wrapper .cesium-sceneModePicker-dropDown-icon {
float: right;
margin: 0 3px;
}
/**cesium POI查询输入框*/
.cesium-viewer-geocoderContainer .search-results {
left: 0;
right: 40px;
width: auto;
z-index: 9999;
}
.cesium-geocoder-searchButton {
background-color: rgba(23, 49, 71, 0.8);
}
.cesium-viewer-geocoderContainer .cesium-geocoder-input {
background-color: rgba(63, 72, 84, 0.7);
}
.cesium-viewer-geocoderContainer .cesium-geocoder-input:focus {
background-color: rgba(63, 72, 84, 0.9);
}
.cesium-viewer-geocoderContainer .search-results {
background-color: rgba(23, 49, 71, 0.8);
}
/**cesium info信息框*/
.cesium-infoBox {
top: 50px;
background-color: rgba(23, 49, 71, 0.8);
}
.cesium-infoBox-title {
background-color: rgba(23, 49, 71, 0.8);
}
/**cesium 任务栏的FPS信息*/
.cesium-performanceDisplay-defaultContainer {
top: auto;
bottom: 35px;
right: 50px;
}
.cesium-performanceDisplay-ms,
.cesium-performanceDisplay-fps {
color: #fff;
}
/**cesium tileset调试信息面板*/
.cesium-viewer-cesiumInspectorContainer {
top: 10px;
left: 10px;
right: auto;
}
.cesium-cesiumInspector {
background-color: rgba(23, 49, 71, 0.8);
}
/**覆盖mars3d内部控件的颜色等样式*/
.mars3d-compass .mars3d-compass-outer {
fill: rgba(23, 49, 71, 0.8);
}
.mars3d-contextmenu-ul,
.mars3d-sub-menu {
background-color: rgba(23, 49, 71, 0.8);
>li>a:hover,
>li>a:focus,
>li>.active {
background-color: #3ea6ff;
}
>.active>a,
>.active>a:hover,
>.active>a:focus {
background-color: #3ea6ff;
}
}
/* Popup样式*/
.mars3d-popup-color {
color: #ffffff;
}
.mars3d-popup-background {
background: rgba(23, 49, 71, 0.8);
}
.mars3d-popup-content {
margin: 15px;
}
.mars3d-template-content label {
padding-right: 6px;
}
.mars3d-template-titile {
border-bottom: 1px solid #3ea6ff;
}
.mars3d-template-titile a {
font-size: 16px;
}
.mars3d-tooltip {
background: rgba(23, 49, 71, 0.8);
border: 1px solid rgba(23, 49, 71, 0.8);
}
.mars3d-popup-btn-custom {
padding: 3px 10px;
border: 1px solid #209ffd;
background: #209ffd1c;
}
.maptool-container {
position: absolute;
left: 20px;
top: 80px;
width: 300px;
height: 800px;
background-color: #3d84a8;
box-sizing: border-box;
user-select: none;
color: #fff;
box-shadow: 0 10px 40px -10px rgba(0, 64, 128, 0.2);
border-radius: 8px;
&-title {
text-align: left;
height: 50px;
line-height: 50px;
padding-left: 20px;
font-weight: bold;
border-bottom: 2px solid #ffffff;
}
}
.maptree {
overflow-y: scroll;
overflow-x: hidden;
height: calc(100% - 50px);
.el-tree {
background-color: transparent;
color: #fff;
}
.el-tree-node__expand-icon {
font-size: 22px;
color: #48466d;
}
.el-tree-node__label {
font-size: 18px;
}
.el-tree-node__content {
// padding-left: 10px !important;
width: 100%;
height: 50px;
box-sizing: border-box;
background-color: transparent !important;
border-bottom: 1px solid #48466d;
}
.el-checkbox {
--el-checkbox-input-height: 20px;
--el-checkbox-input-width: 20px;
}
.el-checkbox__inner::after {
border: 2px solid transparent;
border-left: 0;
border-top: 0;
height: 12px;
left: 5px;
position: absolute;
top: 0px;
width: 6px;
}
.el-checkbox__inner::before {
top: 8px !important;
height: 4px !important;
}
}
.maptree::-webkit-scrollbar {
display: none;
}
.maptree-node {
width: 100%;
box-sizing: border-box;
padding-right: 20px;
display: flex;
flex-direction: column;
}
.maptree-index {
padding-top: 10px;
}
.mapfenxi {
.maptool-container-btn {
display: flex;
flex-wrap: wrap;
padding: 20px 5px;
.el-button {
margin-bottom: 10px;
}
}
}
.measureView {
position: absolute;
background-color: rgba(0, 0, 0, 0.6);
color: #fff;
box-sizing: border-box;
}
.sectionMeasureChartView {
right: 20px;
bottom: 50px;
padding: 0 20px 30px;
}
.analysisMeasureContatiner {
right: 20px;
bottom: 50px;
padding: 0 20px 30px;
}
.analysisMeasureLabel{
line-height: 50px;
}

@ -0,0 +1,36 @@
<template>
<el-row class="map-control-btn">
<el-button plain @click="handlerControl('TCGL')"></el-button>
<el-button type="primary" plain @click="handlerControl('ZHFX')"
>综合空间分析</el-button
>
<el-button type="success" plain>Success</el-button>
<el-button type="info" plain>Info</el-button>
<el-button type="warning" plain>Warning</el-button>
<el-button type="danger" plain>Danger</el-button>
</el-row>
</template>
<script setup>
import { getCurrentInstance } from "vue";
const instance = getCurrentInstance();
//
const handlerControl = (key) => {
switch (key) {
case "TCGL":
instance?.proxy?.$emitter.emit("showLayerTree");
break;
case "ZHFX":
instance?.proxy?.$emitter.emit("showMapFenXi");
default:
break;
}
};
</script>
<style>
.map-control-btn {
position: absolute;
left: 20px;
top: 20px;
display: flex;
}
</style>

@ -0,0 +1,209 @@
<template>
<div class="maptool-container mapfenxi" v-show="dataSet.show">
<div class="maptool-container-title">测量</div>
<div>
<div class="maptool-container-title">
<el-button @click="handlerClear"></el-button>
</div>
<div class="maptool-container-btn">
<el-button @click="handlerMeasureLength"></el-button>
<el-button @click="handlerMeasureArea"></el-button>
<el-button @click="handlerMeasureHeight"></el-button>
<el-button @click="handlerMeasurePoint"></el-button>
<el-button @click="handlerMeasureSurfaceLength"></el-button>
<el-button @click="handlerMeasureSurfaceeArea"></el-button>
<el-button @click="handlerMeasureTriangleHeight"></el-button>
<el-button @click="handlerMeasureAngle"></el-button>
</div>
</div>
<div class="maptool-container-title">综合空间分析</div>
<div>
<div class="maptool-container-btn">
<el-button @click="handlerMeasureSection"></el-button>
<el-button>方量分析</el-button>
<el-button>通视分析</el-button>
<el-button>缓冲分析</el-button>
<el-button>可视域分析</el-button>
<el-button>淹没分析</el-button>
<el-button>日照分析</el-button>
<el-button>天际线分析</el-button>
<el-button>开敞度分析</el-button>
</div>
</div>
</div>
<sectionMeasure v-show="dataSet.sectionMeasureShow" />
<analysisMeasure/>
</template>
<script setup>
import { reactive, getCurrentInstance } from "vue";
import "./map.less";
import * as mars3d from "mars3d";
import { ElLoading } from "element-plus";
import sectionMeasure from "./widget/sectionMeasure.vue";
import analysisMeasure from "./widget/analysisMeasure.vue";
const Cesium = mars3d.Cesium;
let measure;
let loading;
const instance = getCurrentInstance();
const dataSet = reactive({
show: false,
sectionMeasureShow: false,
});
instance?.proxy?.$emitter.on("showMapFenXi", () => {
dataSet.show = !dataSet.show;
});
//
instance?.proxy?.$emitter.on("mapOnLoad", () => {
initMeasure();
});
//
const openLoading = () => {
loading = ElLoading.service({
lock: true,
text: "计算中",
background: "rgba(0, 0, 0, 0.5)",
});
};
const closeLoading = () => {
if (loading) {
loading.close();
}
};
//
const initMeasure = () => {
mars3d.DrawUtil.setPointStyle({ pixelSize: 14 });
measure = new mars3d.thing.Measure({
label: {
color: "#ffffff",
font_family: "楷体",
font_size: 20,
background: false,
},
});
window.globalMap.addThing(measure);
measure.on(mars3d.EventType.start, function (e) {
openLoading();
});
measure.on(mars3d.EventType.end, function (e) {
closeLoading();
//
if (e.graphic?.type === mars3d.graphic.SectionMeasure.type) {
dataSet.sectionMeasureShow = true;
instance?.proxy?.$emitter.emit("onSectionMeasureEnd",e);
}
});
};
//
const handlerClear = () => {
measure.clear();
instance?.proxy?.$emitter.emit("measureClear");
//
dataSet.sectionMeasureShow = false;
};
//
const handlerMeasureLength = () => {
measure.distance({
showAddText: true,
...measureLineOption(false),
});
};
//
const handlerMeasureArea = () => {
measure.area(measureAreaOption(false));
};
//
const handlerMeasureHeight = () => {
measure.height(measureLineOption(false));
};
//
const handlerMeasurePoint = () => {
measure.point();
};
//
const handlerMeasureSurfaceLength = () => {
measure.distance({
showAddText: true,
exact: false,
unit: "m",
...measureLineOption(true),
});
};
//
const handlerMeasureSurfaceeArea = () => {
measure.areaSurface({
splitNum: 10,
exact: false,
...measureAreaOption(true),
});
};
//
const handlerMeasureTriangleHeight = () => {
measure.heightTriangle(measureLineOption(false));
};
//
const handlerMeasureAngle = () => {
measure.angle(measureLineOption(false));
};
//
const handlerMeasureSection = () => {
measure.section({
splitNum: 300,
exact: false,
...measureLineOption(false),
});
};
//style
const measureLineOption = (clampToGround) => {
return {
label: {
type: "div",
updateText: function (text, graphic) {
graphic.html = `<div class="marsGreenGradientPnl" >${text}</div>`;
},
html: `<div class="marsGreenGradientPnl" ></div>`,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
},
style: {
color: "#ffff00",
width: 5,
clampToGround: clampToGround,
},
};
};
//style
const measureAreaOption = (clampToGround) => {
return {
label: {
type: "div",
updateText: function (text, graphic) {
graphic.html = `<div class="marsGreenGradientPnl" >${text}</div>`;
},
html: `<div class="marsGreenGradientPnl" ></div>`,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
},
style: {
color: "#00fff2",
opacity: 0.4,
outline: true,
outlineColor: "#fafa5a",
outlineWidth: 1,
clampToGround: clampToGround,
},
};
};
</script>
<style>
.marsGreenGradientPnl {
color: yellow;
background-color: rgba(0, 0, 0, 0.5);
padding: 2px 3px;
border-radius: 3px;
}
</style>

@ -0,0 +1,149 @@
<template>
<div class="maptool-container" v-show="dataSet.show">
<div class="maptool-container-title">图层管理</div>
<div class="maptree">
<el-tree
:data="dataSet.treeData"
show-checkbox
node-key="id"
default-expand-all
:props="dataSet.defaultProps"
:default-checked-keys="dataSet.checkedKey"
@check-change="handleNodeClick"
@node-contextmenu="handleNodeContextmenu"
>
<template #default="{ node, data }">
<span>{{ data.show }}</span>
<span v-if="data.pid == -1">{{ node.label }}</span>
<span class="maptree-node" v-if="data.pid != -1">
<el-popover
ref="popover"
title="图层调整"
placement="right"
:width="200"
trigger="contextmenu"
>
<template #reference>
<span>{{ node.label }}</span>
</template>
<div class="maptree-node">
<span>透明度调整</span>
<el-slider
class="maptree-node-slider"
:min="0"
:max="1"
:step="0.01"
@change="handlerSliderChange(data)"
v-model="data.opacity"
/>
</div>
<div class="maptree-node">
<span>图层顺序</span>
<div class="maptree-index">
<el-button
type="success"
size="small"
:icon="Upload"
circle
@click="handlerChangeIndex(data.id, 'upper')"
/>
<el-button
type="primary"
size="small"
:icon="Download"
circle
@click="handlerChangeIndex(data.id, 'down')"
/>
</div>
</div>
</el-popover>
</span>
</template>
</el-tree>
</div>
</div>
</template>
<script setup>
import { reactive,getCurrentInstance } from "vue";
import { Upload, Download } from "@element-plus/icons-vue";
import "./map.less";
import { array2tree } from "../../tools/arrayTree.js";
import { deleteArrayItem } from "../../tools/index.js";
const instance = getCurrentInstance();
const dataSet = reactive({
treeData: [],
checkedKey: [],
defaultProps: {
children: "children",
label: "name",
},
show: false,
});
//mitt
instance?.proxy?.$emitter.on("loadLayerTree", (_data) => {
dataSet.treeData = array2tree(_data, "id", "pid", -1);
dataSet.checkedKey = _data.filter((r) => r.show).map((v) => v.id);
});
instance?.proxy?.$emitter.on("showLayerTree", () => {
dataSet.show = !dataSet.show
});
const handleNodeClick = (e, v) => {
let id = e.id;
if (e.pid == -1) {
return false;
} else {
let layer = window.globalMap.getLayerById(id) || null;
if (window.globalMap.hasLayer(layer)) {
if (v) {
layer.setOptions({ show: true });
} else {
layer.setOptions({ show: false });
}
} else {
window.globalMap.addLayer(layer);
if (v) {
layer.setOptions({ show: true });
} else {
layer.setOptions({ show: false });
}
}
}
};
const handlerSliderChange = (e) => {
let layer = window.globalMap.getLayerById(e.id) || null;
console.log("layer::: ", layer.uuid);
if (layer) {
layer.setOptions({ opacity: e.opacity });
}
};
const handlerChangeIndex = (id, type) => {
let layer = window.globalMap.getLayerById(id) || null;
switch (type) {
case "upper":
//
layer.toTop();
break;
case "down":
//
layer.toBottom();
break;
default:
break;
}
};
const handleNodeContextmenu = (e, v, x, y) => {
console.log("e::: ", e);
console.log("v::: ", v);
console.log("x::: ", x);
console.log("y::: ", y);
};
const remove = (node, data) => {
console.log("data::: ", data);
console.log("node::: ", node);
};
</script>

@ -0,0 +1,99 @@
<template>
<div :id="withKeyId" class="mars3d-container"></div>
</template>
<script setup lang="ts">
import "./map.less";
import { computed, onUnmounted, onMounted } from "vue"
import axios from 'axios';
import * as mars3d from "mars3d"
const props = withDefaults(
defineProps<{
url: string
mapKey?: string
options?: any
}>(),
{
url: "",
mapKey: "default",
options: () => ({})
}
)
let map: mars3d.Map
// 使 mapKey withKeyId id
const withKeyId = computed(() => `mars3d-container-${props.mapKey}`)
onMounted(() => {
//
axios.get(props.url).then((res: { data: any; }) => {
let data = res.data
initMars3d({
//
...data.map3d,
...props.options
})
})
})
// onload
const emit = defineEmits(["onload"])
const initMars3d = (option: any) => {
map = new mars3d.Map(withKeyId.value, option)
//
// map.openFlyAnimation();
//
if (mars3d.Util.isPCBroswer()) {
// map.zoomFactor = 2.0 //
map.zoomFactor = 5.0 //
// IE
if (window.navigator.userAgent.toLowerCase().indexOf("msie") >= 0) {
map.viewer.targetFrameRate = 20 //
map.scene.requestRenderMode = false //
}
} else {
map.zoomFactor = 5.0 //
//
map.scene.requestRenderMode = false //
map.scene.fog.enabled = false
map.scene.skyAtmosphere.show = false
map.scene.globe.showGroundAtmosphere = false
}
// //
if (map.viewer.sceneModePicker) {
map.viewer.sceneModePicker.viewModel.duration = 0.0
}
// webgl
map.on(mars3d.EventType.renderError, async () => {
await alert("程序内存消耗过大,请重启浏览器")
window.location.reload()
})
// map
onMapLoad()
emit("onload", map)
}
// map
function onMapLoad() {
// // Mars3D使
}
// mars3d
onUnmounted(() => {
if (map) {
map.destroy()
map = null
}
console.log("map销毁完成", map)
})
</script>
<style lang="less"> /**cesium 工具按钮栏*/
</style>

@ -0,0 +1,69 @@
<!--
*************************************************************************
方量分析
*************************************************************************
-->
<template>
<div class="measureView analysisMeasureContatiner">
<h2>方量分析</h2>
<p>
提示单击分析按钮激活绘制分析对绘制面()内的进行以下计算<br />
1. 挖方量: 计算基准面到地表之间的凸出部分进行挖掉的体积<br />
2. 填方量计算基准面墙底部之间的缺少部分进行填平的体积
</p>
<div>
<el-button type="primary" @click="analysisMeasure"
>绘制分析区域</el-button
>
<el-button type="danger" @click="clear"></el-button>
</div>
<el-row>
<el-col :span="24">
<span class="analysisMeasureLabel">基准面高():</span>
</el-col>
<el-col :span="16">
<el-input
type="number"
@change="baseHeight"
id="inputNumber"
v-model:value="baseValue"
step="0.1"
/>
</el-col>
<el-col :span="4" :offset="1">
<el-button @click="selHeight"></el-button>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<span class="analysisMeasureLabel">围墙底高():</span>
</el-col>
<el-col :span="16">
<el-input
type="number"
@change="txtMinHeight"
id="inputNumber"
v-model:value="bottomValue"
step="0.1"
/>
</el-col>
</el-row>
<div>
<el-col :span="24">
<span class="analysisMeasureLabel">围墙顶高():</span>
</el-col>
<el-col :span="16">
<el-input
type="number"
@change="txtMaxHeight"
id="inputNumber"
v-model:value="topValue"
step="0.1"
/>
</el-col>
</div>
</div>
</template>
<script setup>
import "../map.less";
</script>

@ -0,0 +1,198 @@
<!--
*************************************************************************
剖面分析
*************************************************************************
-->
<template>
<div class="measureView sectionMeasureChartView">
<h2>剖面分析</h2>
<div id="sectionMeasureChart" style="width: 1000px; height: 300px"></div>
</div>
</template>
<script setup>
import { onMounted, getCurrentInstance } from "vue";
import * as echarts from "echarts";
import * as mars3d from "mars3d";
import '../map.less'
const Cesium = mars3d.Cesium;
const instance = getCurrentInstance();
let sectionMeasureChart;
let tipGraphic;
onMounted(() => {
sectionMeasureChart = echarts.init(
document.getElementById("sectionMeasureChart")
);
});
window.onresize = function () {
sectionMeasureChart.resize();
};
//
instance?.proxy?.$emitter.on("onSectionMeasureEnd", (e) => {
setSectionMeasureEchart(e);
});
//
instance?.proxy?.$emitter.on("measureClear", () => {
hideTipMarker();
sectionMeasureChart.clear();
});
const setSectionMeasureEchart = (data) => {
if (data == null || data.arrPoint == null) {
return;
}
const arrPoint = data.arrPoint;
let inhtml = "";
const option = {
grid: {
left: 10,
right: 40,
bottom: 10,
top: 40,
containLabel: true,
},
dataZoom: [
{
type: "inside",
throttle: 50,
},
],
tooltip: {
trigger: "axis",
// position: function (point, params, dom, rect, size) {
// return [10, 20];
// },
formatter: (params) => {
if (params.length === 0) {
hideTipMarker();
return inhtml;
}
const hbgd = params[0].value; //
const point = arrPoint[params[0].dataIndex]; //
const result = calculation(params[0]);
inhtml = `当前位置<br />
距起点${result.len}<br />
海拔<span style='color:${params[0].color};'>${result.hbgdStr}</span><br />
经度${point.lng}<br />
纬度${point.lat}`;
showTipMarker(point, hbgd, inhtml);
return inhtml;
},
},
xAxis: [
{
name: "行程",
type: "category",
nameTextStyle: { color: "rgb(255, 70, 131)" },
boundaryGap: false,
axisLine: {
show: true,
},
axisLabel: {
show: true,
formatter: "{value} 米",
color: "#fff",
},
data: data.arrLen,
},
],
yAxis: [
{
name: "高程",
nameTextStyle: { color: "rgb(255, 70, 131)" },
type: "value",
min: getMinZ(arrPoint),
axisLabel: {
formatter: "{value} 米",
color: "#fff",
},
},
],
series: [
{
name: "高程值",
type: "line",
smooth: true,
symbol: "none",
sampling: "average",
itemStyle: {
normal: {
color: "rgb(255, 70, 131)",
},
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: "rgb(255, 158, 68)",
},
{
offset: 1,
color: "rgb(255, 70, 131)",
},
]),
},
},
data: data.arrHB,
},
],
};
sectionMeasureChart.setOption(option);
sectionMeasureChart.resize();
};
const getMinZ = (arr) => {
let minz = "dataMin";
if (arr == null || arr.length === 0) {
return minz;
}
minz = arr[0].alt;
for (let i = 0; i < arr.length; i++) {
if (arr[i].alt < minz) {
minz = arr[i].alt;
}
}
return minz;
};
const showTipMarker = (point, z, inthtml) => {
const _position_draw = Cesium.Cartesian3.fromDegrees(point.lng, point.lat, z);
if (!tipGraphic) {
tipGraphic = new mars3d.graphic.BillboardEntity({
name: "当前点",
position: _position_draw,
style: {
image: "img/marker/mark-blue.png",
scale: 1,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
scaleByDistance: new Cesium.NearFarScalar(10000, 1.0, 500000, 0.2),
},
}).addTo(window.globalMap.graphicLayer);
tipGraphic._setPositionsToCallback();
}
tipGraphic._position_draw = _position_draw;
tipGraphic.bindPopup(inthtml).openPopup();
};
const hideTipMarker = () => {
if (!tipGraphic) {
return;
}
tipGraphic.remove(true);
tipGraphic = null;
};
const calculation = (params) => {
const len = mars3d.MeasureUtil.formatDistance(Number(params.axisValue));
const hbgdStr = mars3d.MeasureUtil.formatDistance(Number(params.value));
return { len, hbgdStr };
};
</script>

8
src/env.d.ts vendored

@ -0,0 +1,8 @@
/// <reference types="vite/client" />
declare module '*.vue' {
import { DefineComponent } from 'vue'
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any>
export default component
}

@ -0,0 +1,13 @@
import "mars3d-cesium/Build/Cesium/Widgets/widgets.css"
import "mars3d/dist/mars3d.css"
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import mitt from "mitt"
import { createApp } from 'vue'
import App from './App.vue'
import "./style.css"
const app = createApp(App)
app.config.globalProperties.$emitter = mitt()
app.use(ElementPlus)
app.mount('#app')

@ -0,0 +1,64 @@
body,
html,
#app {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
.bg-gis {
background-size: auto;
overflow: hidden;
left: 0;
width: "100%";
position: absolute;
transition: all 0.3s;
}
.collapsed {
left: 0;
width: 100%;
height: 100%;
}
input,
button,
select,
textarea {
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
a {
color: #62a8ea;
text-decoration: none;
}
a:hover,
a:focus {
color: #89bceb;
text-decoration: underline;
}
a:focus {
outline: thin dotted;
outline: 5px auto -webkit-focus-ring-color;
outline: none;
outline-offset: -2px;
}
ul,
li {
list-style: none;
}
/*dark样式*/
a {
color: #ffffff;
text-decoration: none;
}
a:hover {
color: #cc3300;
text-decoration: underline;
}

@ -0,0 +1,205 @@
/**
* 数组对象去除空字符串使其为null
* @param object
*/
export function removeEmptyString(object) {
for (const i in object) {
if (typeof object[i] === 'string' && (object[i] === '' || object[i].replace(/\s+/g, '') === '')) {
object[i] = null
}
}
}
/**
* list to tree
* @desc 就是不停的获取当前节点的父节点并把当前节点的加入到父节点的children中
* @param array
* @param id 主键名称
* @param pid 对应node parentId
* @param rootValue array里根节点的 parentId value
* @returns {[]}
*/
export function array2tree(array, id, pid, rootValue) {
const newList = []
for (let i = 0; i < array.length; i++) {
if (array[i][pid] === rootValue) {
newList.push(array[i]) // 把根节点放入新的list中
} else { // Parent
const parent = array.find(item => item[id] === array[i][pid]) // 获取 当前节点的父节点
if (parent) { // 如果当前节点的父节点不为空,就把当前节点放入父节点的 children 数组属性中
if (parent.children) {
// 更改原数组就相当于给新数组里面添加了children因为新数组里面元素的地址和原数组是一个、
parent.children.push(array[i])
} else {
parent.children = [array[i]]
}
}
}
}
return newList
}
/**
* tree list
* @desc 利用队列的特性不停的往队列里存放当前node的children然后边遍历
* @param tree 是数组 是tree数组
* @returns {[]}
*/
export function tree2List(trees) {
const newList = []
const queue = []
trees.forEach(tree => {
// 1. 对根节点的处理
const { children, ...meta } = tree // 去除子节点集合
newList.push(meta) // 把当前节点介入到 新的list里
if (children) { // 如果当前节点的 children 数组属性不为空,就把它加入到队列中
queue.push(children)
}
// 2. 对根节点以外的节点进行处理
// 遍历队列,可以看出 队列的操作 边遍历,边放入新的元素
while (queue.length) {
const item = queue.pop() // 从队列里推出一个元素
item && item.forEach(node => { // 如果子节点还有子节点,就继续往队列里存放
// 以下是重复性操作
const { children, ...meta } = node
newList.push(meta)
if (children) {
queue.push(children)
}
})
}
})
return newList
}
/**
* 获取node 的上级node集合(包含当前节点)就是获取所以的父节点
* 获取当前节点的所以子节点可以自己实现和这个原理相同
* @param tree
* @param nodes 是数组需要获取上级节点的节点集合
* @param id 主键名称
* @param pid 对应node parentId
* @param rootValue tree 根节点的 parentId value
* @returns {[]}
*/
export function getParentIds(tree, nodes, id, pid, rootValue) {
const list = tree2List(tree) // 先把tree 转成 list
const newList = []
const queue = []
nodes.forEach(n => {
// 1. 对根节点的处理
// eslint-disable-next-line no-unused-vars
const { children, ...meta } = n // 去除子节点集合
const node = meta
// 把当前节点放入 新的list中
if (newList.findIndex(r => r[id] === node[id]) < 0) { newList.push(node) } // 目的是去重
// 如果当前节点有父节点,就把父节点放入队列中
if (node[pid] !== rootValue) {
queue.push(list.find(ele => ele[id] === node[pid]))
}
// 2. 对根节点以外的节点进行处理
// 遍历 队列 ,可以看出 队列的操作 边遍历,边放入新的元素
while (queue.length) {
const n = queue.pop() // 从队列里推出一个元素
// 以下是重复性操作
// eslint-disable-next-line no-unused-vars
const { children, ...meta } = n
const node = meta
if (newList.findIndex(r => r[id] === node[id]) < 0) { newList.push(node) } // 目的是去重
if (node[pid] !== rootValue) {
queue.push(list.find(ele => ele[id] === node[pid]))
}
}
})
return newList
}
/**
* 迭代tree
* @param tree
* @param handler 对每一个节点的处理函数
*/
export function treeIterator(tree, handler) {
const walk = (tree) => {
const queue = []
// 1. 对根节点的处理
const { children, ...meta } = tree // 去除子节点集合
handler(meta) // 对节点进行操作
// 把当前节点的子节点list放入队列中
if (children) {
queue.push(children)
}
// 2. 对根节点以外的节点进行处理
// 遍历 队列 ,可以看出 队列的操作 边遍历,边放入新的元素
while (queue.length) {
const nodes = queue.pop() // 从队列里推出一个元素
// 一下是重复性操作
nodes && nodes.forEach(node => {
const { children, ...meta } = node
handler(meta)
if (children) {
queue.push(children)
}
})
}
}
walk(tree)
}
/**
* tree 过滤
* @param tree
* @param handler 处理函数
* @param filter 过滤函数
* @returns {{[p: string]: *, [p: number]: *}}
*/
export function treeFilter(tree, handler, filter) {
const walkAndCopy = (tree) => {
const queue = []
// 1. 对根节点的处理
if (filter(tree)) {
let newTree = {}
const { children, ...meta } = tree
handler(meta) // 处理函数
newTree = meta // 新节点的元信息,除子节点外的
// 如果当前节点的存在子节点,就把 当前节点的子节点 和 新tree的子节点 放到队列里
// 如果原节点有子节点,那么新节点也应该有子节点
if (children) {
newTree.children = [] // 每一个节点生成时自添加一个子节点list 属性并把这个list属性放入到队列中
queue.push({
oldNodes: children,
newNodes: newTree.children // 新tree 的子节点集合的引用
})
}
// 2. 对根节点以外的节点进行处理
// 遍历 队列 ,可以看出 队列的操作 边遍历,边放入新的元素
while (queue.length) {
const item = queue.pop() // 从队列里推出一个元素
// 如果 节点中的子节点集合存在,就遍历子节点集合
item.oldNodes && item.oldNodes.forEach(node => {
if (filter(node)) {
// 以下是重复性操作
let newNode = {}
const { children, ...meta } = node
handler(meta)
newNode = meta
if (children) {
newNode.children = []
queue.push({
oldNodes: children,
newNodes: newNode.children
})
}
item.newNodes.push(newNode) // 把当前节点放入到子节点集合中
}
})
}
return newTree
}
}
return walkAndCopy(tree)
}

@ -0,0 +1,8 @@
//删除数组某一项
export const deleteArrayItem = (array, key) => {
let index = array.indexOf(key);
if (index != -1) {
array.splice(index, 1);
}
return array;
};

@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "esnext",
"useDefineForClassFields": true,
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"strictNullChecks": false,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"],
"types": ["element-plus/global"]
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
}

@ -0,0 +1,12 @@
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { mars3dPlugin } from "vite-plugin-mars3d"
import vueJsx from "@vitejs/plugin-vue-jsx"
export default defineConfig({
plugins: [
vue(),
mars3dPlugin(),
vueJsx()
]
});
Loading…
Cancel
Save