vue+mars3d 组件封装与应用 +简单示例
前言很多朋友在学习和使用mars3d时,经常发现用的官方推荐组件,在实际应用中会出现很多问题。我用vuecli 4.0以上版本生成的vue项目,直接套用官方示例和官方组件会出现只显示地图,模型无法显示的问题。如图以下是我重构后的代码一、map.vue<template><div:id="`mars3d-container${mapKey}`":class="['mars3d-co
·
前言
很多朋友在学习和使用mars3d时,经常发现用的官方推荐组件,在实际应用中会出现很多问题。我用vuecli 4.0以上版本生成的vue项目,直接套用官方示例和官方组件会出现只显示地图,模型无法显示的问题。
如图
以下是我重构后的代码
一、map.vue
<template>
<div
:id="`mars3d-container${mapKey}`"
:class="['mars3d-container', customClass, { 'mars3d-container-compare-rh': compare }]"
></div>
</template>
<script>
import Vue from "vue";
// 使用免费开源版本
import "mars3d/dist/mars3d.css";
import * as mars3d from "mars3d";
// 导入插件(其他插件类似,插件清单访问:http://mars3d.cn/dev/guide/start/install.html)
// echarts插件
// import 'mars3d-echarts'
// 为了方便使用,绑定到原型链,在其他vue文件,直接 this.mars3d 来使用
Vue.prototype.mars3d = mars3d;
Vue.prototype.Cesium = mars3d.Cesium;
export default {
name: "mars3dViewer",
props: {
// 初始化配置参数
url: String,
// 地图唯一性标识
mapKey: {
type: String,
default: "",
},
// 自定义参数
options: Object,
// 是否分屏显示
compare: {
type: Boolean,
default: false,
},
// 是否插入到body元素上
appendToBody: {
type: Boolean,
default: false,
},
// 自定义css类名
customClass: {
type: String,
default: "",
},
},
mounted() {
if (this.appendToBody) {
document.body.appendChild(this.$el);
}
if (this.mapKey) {
this.initMars3d(this.options);
} else {
mars3d.Resource.fetchJson({ url: this.url }).then((data) => {
this.initMars3d(data.map3d); // 构建地图
});
}
},
beforeDestroy() {
this[`map${this.mapKey}`].destroy();
delete this[`map${this.mapKey}`];
},
methods: {
initMars3d(options) {
if (this[`map${this.mapKey}`]) {
this[`map${this.mapKey}`].destroy();
}
const mapOptions = {
...options,
...this.options,
};
// 创建三维地球场景
var map = new mars3d.Map(`mars3d-container${this.mapKey}`, mapOptions);
this[`map${this.mapKey}`] = map;
console.log(">>>>> 地图创建成功 >>>>", map);
// 挂载到全局对象下,所有组件通过 this.map 访问
Vue.prototype[`map${this.mapKey}`] = map;
// 绑定对alert的处理,右键弹出信息更美观。
// window.haoutil = window.haoutil || {}
// window.haoutil.msg = (msg) => {
// this.$message.success(msg)
// }
// window.haoutil.alert = (msg) => {
// this.$message.success(msg)
// }
// 抛出事件
this.$emit("onload", map);
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
.mars3d-container {
height: 100%;
overflow: hidden;
}
/* 重写Cesium的css */
/**cesium按钮背景色*/
.cesium-button {
background-color: #3f4854;
color: #e6e6e6;
fill: #e6e6e6;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
line-height: 32px;
}
.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: #3f4854;
}
.cesium-geocoder-searchButton {
background-color: #3f4854;
}
.cesium-infoBox-title {
background-color: #3f4854;
}
.cesium-infoBox {
background: rgba(63, 72, 84, 0.9);
}
.cesium-toolbar-button img {
height: 100%;
}
.cesium-performanceDisplay-defaultContainer {
top: auto;
bottom: 35px;
right: 50px;
}
.cesium-performanceDisplay-ms,
.cesium-performanceDisplay-fps {
color: #fff;
}
/**cesium工具栏位置*/
.cesium-viewer-toolbar {
top: auto;
left: auto;
right: 12px;
bottom: 35px;
}
.cesium-viewer-toolbar > .cesium-toolbar-button,
.cesium-navigationHelpButton-wrapper,
.cesium-viewer-geocoderContainer {
margin-bottom: 5px;
float: right;
clear: both;
text-align: center;
}
.cesium-baseLayerPicker-dropDown {
bottom: 0;
right: 40px;
max-height: 700px;
margin-bottom: 5px;
}
.cesium-navigation-help {
top: auto;
bottom: 0;
right: 40px;
transform-origin: right bottom;
}
.cesium-sceneModePicker-wrapper {
width: auto;
}
.cesium-sceneModePicker-wrapper .cesium-sceneModePicker-dropDown-icon {
float: left;
margin: 0 3px;
}
.cesium-viewer-geocoderContainer .search-results {
left: 0;
right: 40px;
width: auto;
z-index: 9999;
}
.cesium-infoBox-title {
background-color: #3f4854;
}
.cesium-infoBox {
top: 50px;
background: rgba(63, 72, 84, 0.9);
}
/**左下工具栏菜单*/
.toolbar-dropdown-menu-div {
background: rgba(43, 44, 47, 0.8);
border: 1px solid #2b2c2f;
z-index: 991;
position: absolute;
right: 60px;
bottom: 40px;
display: none;
}
.toolbar-dropdown-menu {
min-width: 110px;
padding: 0;
}
.toolbar-dropdown-menu > li {
padding: 0 3px;
margin: 2px 0;
}
.toolbar-dropdown-menu > li > a {
color: #edffff;
display: block;
padding: 4px 10px;
clear: both;
font-weight: normal;
line-height: 1.6;
white-space: nowrap;
text-decoration: none;
}
.toolbar-dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
color: #fff;
background-color: #444d59;
}
.toolbar-dropdown-menu > .active > a,
.dropdown-menu > .active > a:hover,
.dropdown-menu > .active > a:focus {
color: #fff;
background-color: #444d59;
}
.marsBlackPanel .mars3d-popup-close-button {
color: #fff ;
}
.toolbar-dropdown-menu i {
padding-right: 5px;
}
</style>
二、示例组件 map2.vue
<template>
<div class="mapcontainer web-map">
<div class="tip-box">
<button class="btn" @click="goto(1)">切换到化工厂</button>
<button class="btn" @click="goto(2)">切换到油站</button>
</div>
<Map :url="configUrl" @onload="onMapload" />
</div>
</template>
<style>
.tip-box {
width: auto;
height: auto;
position: absolute;
right: 10px;
top: 10px;
z-index: 999;
}
.btn {
color: #fff;
background-color: #3b61df;
border-color: #3b61df;
padding: 5px;
margin: 0 5px;
border-radius: 5px;
cursor: pointer;
}
.marsBlueGradientPnl {
text-align: center;
padding: 5px 30px;
margin: 0;
color: #fff;
background: linear-gradient(rgb(7 10 203 / 75%), rgb(16 238 220));
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
max-height: 130px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
white-space: nowrap;
}
.marsBlueGradientPnl:after {
content: "";
position: absolute;
bottom: -60px;
left: calc(50% - 3px);
display: block;
width: 3px;
height: 60px;
border-right: 3px solid #2bcdbb;
}
.marsBlueGradientPnl-err {
background: linear-gradient(rgb(203 7 7 / 75%), rgb(238 16 16));
}
.marsBlueGradientPnl-alarm {
background: linear-gradient(rgb(203 116 7 / 75%), rgb(238 149 16));
}
.marsBlueGradientPnl-offline {
background: linear-gradient(#303336cf, #aaa);
color: #ddd;
}
/* .marsBlueGradientPnl-err {
border: 2px solid #f00;
} */
.marsBlueGradientPnl-err:after {
border-right: 3px solid #f00;
}
.marsBlueGradientPnl-alarm:after {
border-right: 3px solid #ff8b0d;
}
.marsBlueGradientPnl-offline:after {
border-right: 3px solid #aaa;
}
</style>
<script>
import Map from "@/components/mars3d/Map.vue"; // 此处用的map在官网模板代码里有
const echarts = require('echarts');
import 'echarts-liquidfill'//在这里引入
export default {
components: {
Map,
},
data() {
return {
configUrl: "config/config.json", // mars3D配置文件
map: "",
graphicLayer: "",
arrData: [],
};
},
mounted() {},
methods: {
// 地图构造完成回调
onMapload(map) {
this.map = map;
//定位切换视角
this.map.setCameraView({
lat: 31.808039,
lng: 117.100629,
alt: 559,
heading: 329,
pitch: -28,
});
this.arrData = [
{
name: "油罐一",
position: [117.09521, 31.814404, 47.3],
state: "报警",
divice: "898600a6980349081601",
val: "0.4",
unit: "PPM",
bjcolor: "#f00",
online: "1",
err: "1",
projectname: "监控测试项目",
},
{
name: "油罐二",
position: [117.095206, 31.814878, 47.3],
state: "异常",
divice: "898600a6980349081602",
val: "0.4",
unit: "PPM",
bjcolor: "#ff8b0d",
online: "1",
err: "2",
projectname: "监控测试项目",
},
{
name: "油罐三",
position: [117.094653, 31.814428, 47.3],
state: "报警",
divice: "898600a6980349081603",
val: "0.4",
unit: "PPM",
bjcolor: "#f00",
online: "1",
err: "1",
projectname: "监控测试项目",
},
{
name: "发电机",
position: [117.093428, 31.816959, 31.8],
state: "异常",
divice: "898600a6980349081604",
val: "0.4",
unit: "PPM",
bjcolor: "#f00",
online: "1",
err: "2",
projectname: "监控测试项目",
},
{
name: "指挥室",
position: [117.093953, 31.814397, 36],
state: "正常",
divice: "898600a6980349081605",
val: "0.4",
unit: "PPM",
bjcolor: "#04ba19",
online: "1",
err: "3",
projectname: "监控测试项目",
},
{
name: "加热罐",
position: [117.09385, 31.815837, 36.9],
state: "正常",
divice: "898600a6980349081606",
val: "0.4",
unit: "PPM",
bjcolor: "#04ba19",
online: "1",
err: "3",
projectname: "监控测试项目",
},
{
name: "冷却室",
position: [117.094662, 31.816403, 32.9],
state: "正常",
divice: "898600a6980349081607",
val: "0.4",
unit: "PPM",
bjcolor: "#04ba19",
online: "2",
err: "3",
projectname: "监控测试项目",
},
];
this.graphicLayer = new this.mars3d.layer.DivLayer();
map.addLayer(this.graphicLayer);
//生成油站
let tiles3dLayer = new this.mars3d.layer.TilesetLayer({
pid: 2020,
type: "3dtiles",
name: "油田联合站",
url: "//data.mars3d.cn/3dtiles/max-ytlhz/tileset.json",
position: { lng: 117.094224, lat: 31.815859, alt: 26.4 },
rotation: { z: 116.2 },
highlight: { type: "click", color: "#00ffff" },
maximumScreenSpaceError: 1,
center: { lat: 32.407076, lng: 117.459703, alt: 3361, heading: 358, pitch: -51 },
popup: "all",
});
this.map.addLayer(tiles3dLayer);
this.divGraphicYellow();
// 加载石化工厂模型
let tiles3dLayer2 = new this.mars3d.layer.TilesetLayer({
name: "石化工厂",
url: "http://data.mars3d.cn/3dtiles/max-shihua/tileset.json",
position: { lng: 117.077158, lat: 31.659116, alt: 24.6 },
highlight: { type: "click", color: "#00ffff" },
maximumScreenSpaceError: 1,
maximumMemoryUsage: 1024,
popup: "all",
});
this.map.addLayer(tiles3dLayer2);
// 添加矢量数据
this.addDemoGraphic([117.077462, 31.657745, 60], { value: 0.53, color: "#fb980b" });
this.addDemoGraphic([117.079091, 31.65898, 90], { value: 0.45, color: "#00ff00" });
this.addDemoGraphic([117.079766, 31.658268, 70], { value: 0.35, color: "#00ffff" });
this.addDemoGraphic([117.07913, 31.655748, 80], { value: 0.21, color: "#ff0000" });
// 单击.事件
tiles3dLayer.on(mars3d.EventType.click, function (event) {
console.log("单击了3dtiles图层", event);
});
},
addDemoGraphic(position, attr) {
let that=this
const graphic = new this.mars3d.graphic.DivGraphic({
position: position,
style: {
html: `<div style="width: 80px;height:80px;"></div>`,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
},
attr: attr,
});
graphic.on(mars3d.EventType.add, function (e) {
let dom = e.target.container.firstChild;
let attr = e.target.attr;
let liquidfillchartChart = echarts.init(dom);
// 参考API:https://github.com/ecomfe/echarts-liquidfill
// 参考示例:https://www.makeapie.com/explore.html#tags=liquidFill~sort=rank~timeframe=all~author=all
let option = {
series: [
{
type: "liquidFill",
radius: "100%",
outline: { show: false },
color: [attr.color],
data: [attr.value],
label: {
color: "#294D99",
insideColor: "#fff",
fontSize: 20,
},
},
],
};
liquidfillchartChart.setOption(option);
});
that.graphicLayer.addGraphic(graphic);
},
//切换模型
goto(e) {
switch (e) {
case 1:
this.map.setCameraView({
lat: 31.647382,
lng: 117.084888,
alt: 719,
heading: 329,
pitch: -28,
});
break;
case 2:
this.map.setCameraView({
lat: 31.808039,
lng: 117.100629,
alt: 559,
heading: 329,
pitch: -28,
});
break;
}
},
//生成描述
divGraphicYellow() {
let arrData = this.arrData;
let that = this;
for (let i = 0; i < arrData.length; i++) {
let item = arrData[i];
var divGraphic = new this.mars3d.graphic.DivGraphic({
position: item.position,
style: {
html: that.addPoupTitle(item),
offsetY: -60,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BTOOM,
},
popup: that.addPoup(item),
popupOptions: {
offsetY: -150, // 显示Popup的偏移值,是DivGraphic本身的像素高度值
offsetX: -150,
scaleByDistance: true, //是否按视距缩放
template: `<div class="marsBlackPanel animation-spaceInDown">
<div class="marsBlackPanel-text">{content}</div>
<span class="mars3d-popup-close-button closeButton" >×</span>
</div>`,
horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
verticalOrigin: Cesium.VerticalOrigin.CENTER,
},
});
that.graphicLayer.addGraphic(divGraphic);
}
},
// 生成弹框标签
addPoupTitle(item) {
let colorclass = "";
switch (item.err) {
case "2":
colorclass = "marsBlueGradientPnl-alarm";
break;
case "1":
colorclass = "marsBlueGradientPnl-err";
break;
default:
colorclass = "";
break;
}
if (item.online != "1") {
colorclass = "marsBlueGradientPnl-offline";
}
let html = `<div class="marsBlueGradientPnl ${colorclass}">
<div>${item.name}</div>
</div>`;
return html;
},
//弹框html
addPoup(item) {
let html = `<ul class="rel-pop">
<li> 项目名称: <span > ${item.projectname}</span></li>
<li> 设备编号: <span > ${item.divice}</span></li>
<li> 检测值: <span > ${item.val}${item.unit}</span></li>
<li> 报警状态: <span style="color:${item.bjcolor}"> ${item.state}</span></li>
<li> 在线状态: <span > ${item.online == "1" ? "在线" : "离线"}</span></li>
</ul>
`;
return html;
},
removeLayer() {
if (this.layer) {
this.map.removeLayer(this.layer, true);
this.layer = null;
}
},
},
};
</script>
<style lang="scss" scoped>
.mapcontainer {
overflow: hidden;
height: 100vh;
.bottomLayer {
position: relative;
bottom: 150px;
text-align: center;
button {
font-size: 24px;
width: 90px;
background: rgba(63, 72, 84, 0.88);
/*border-color: #00ffff;*/
border: 0;
}
.activeBtn {
color: #00ffff;
}
}
.el-dialog__wrapper {
.el-dialog {
background: rgba(36, 45, 52, 0.9);
border: 1px solid #66b1ff;
.el-dialog__title {
color: #eee;
}
.el-dialog__body {
text-align: center;
}
}
}
}
</style>
效果如下
更多推荐
已为社区贡献1条内容
所有评论(0)