这是项目维护期中需要添加的功能模块:其实可以算是在原有的系统上添加一个小型的管理系统了;这里从文件上传、iframe页面数据访问,数据渲染部分总结一下;
数据渲染
地图区域线条绘制
在编辑的时候从服务端请求到的点坐标集合在地图渲染,和新增共用一个地图; 但是操作逻辑不同,在新增是靠点击事件触发加载(第一次为加载,之后为显示隐藏),编辑需要直接渲染;
$('#historyIllegaleModal').modal('show');
$('#historyIllegaleModal').on('shown.bs.modal', e => {
if (vm.state === 'Edit') {
if (!viewer) {
vm.initWebGl(); //初始加载
}
$.extend(vm.commitData, data); // 依据服务端进行数据替换
vm.initChooseHistoryIllegaleArea(); // 显示 canvas 部分
//加载完成的回调
viewer.onEndFrame = () => {
if (historyIllegaleTableEditState) {
drawMeshLine(data['XQWZ']); //调用绘制的方法
historyIllegaleTableEditState = false;
}
}
historyIllegaleTableEditState = true; //先执行
}
})
卫片对比区域渲染
在触发卫片对比功能中中依据主页面选中需要渲染的类型,其中绘制行政区划部分(为文字标注和区域划分两个部分);
构建标注图层
let shapeCommonConfig = {
width: "76px",
height: "24px",
padding: "0",
borderRadius: "2px",
color: "#ff0000",
opacity: 1,
backgroundColor: "none",
fontWeight: "900",
};
let shapeArr = [streetShape, streetShapeRight, communityShape, communityShapeRight, jurisdictionShape, jurisdictionShapeRight];
shapeArr.forEach((shapeArrItem, index) => {
shapeArrItem = new CSS2DLabelLayer();
Object.assign(shapeArrItem.css2DStyle, shapeCommonConfig);
index % 2 === 0 ? sceneRight.addCustomLayer(shapeArrItem) : sceneLeft.addCustomLayer(shapeArrItem);
})
利用数据集合渲染出边界线和其中的文字
// 边界线 && 文字 添加
CITY_SHAPE_DATA.forEach((ele, curNum) => {
// 根据主页 props 确定 那些需要加载;
let currentState = parent.document.querySelector(`#cityshapes${curNum}`).checked;
if (!currentState) {
return;
}
let sceneArr = [sceneRight, sceneLeft];
for (let i = 0; i < sceneArr.length; i++) {
const item = sceneArr[i];
var ftLayerPolygon = new tjh.ar.FeatureLayer(ele.url[0], "", false, item.terrainLayers, item.globalOffset);
ftLayerPolygon.loadAllOnce = true;
// polygon
ftLayerPolygon.regulator.isLoadFeature = true;// 是否加载矢量streetSurface
ftLayerPolygon.regulator.requestNum = 10;// 每帧加载数量
ftLayerPolygon.regulator.color.set(Number(ele.setColor[0]));// 矢量颜色
ftLayerPolygon.regulator.opacity = (ele.type === "community") ? 0.5 : 1;// 矢量透明度
ftLayerPolygon.regulator.size = 3.0;
// 矢量贴合方式--人工指定高层
ftLayerPolygon.regulator.fitPattern = tjh.ar.FeatureLayer.FIT_PATTERN.FIT_TERRIAN_LOW;
ftLayerPolygon.initMaterial();
item.addFeatureLayer(ftLayerPolygon); //向其中添加边界线
isRenderLabel = true; //触发封装库中的添加方法
let textConfig = [
{ type: "street", target: streetShape, target2: streetShapeRight },
{ type: "community", target: communityShape, target2: communityShapeRight },
{ type: "jurisdiction", target: jurisdictionShape, target2: jurisdictionShapeRight }
];
textConfig.forEach(element => {
if (ele.type === element.type) {
let { target, target2 } = element;
for (let num = 0; num < ele.centerPosition.length; num++) {
const { name, x, y } = ele.centerPosition[num];
target.addLabel(null, name, new THREE.Vector3(x, y, 50));
target2.addLabel(null, name, new THREE.Vector3(x, y, 50));
}
}
});
}
});
Vue数据响应式更新
由于 Vue 是在初始化实例时,将实例属性执行getter/settter
对于已经创建的vue
实例不允许动态添加跟级别的相应式属性。因为这样不会触发变化的监控,所以视图的更新无法自动刷新;
使用
Vue.set
或者vm.$set
运行时候进行动态添加;
vm.$set(object,propertyName,value);// 适用于后端数据返回后处理成自己需要的属性集合
//eg: 向每个item添加自定义属性
this.posts = res.map( item => {
return { ...item, //somepropertyName }
})
根节点数据初始化的时候全部添加
data() { // 当变量很多的时候,考虑分组后合并,避免混乱
const userInfo = { //....
};
const config = { //....
};
return { ...userInfo, ...config, }
}
文件上传
在使用过程中涉及到 Post 请求用于上传文件,,使用
FormData
进行文件上传;
<!-- type=file 代表上传文件 -->
<!-- accept='' 代表上传文件限制,这里 .xls, .xlsx 代表限定为 excel类型 -->
<input type="file" name="" id="" accept=".xls, .xlsx" >
FormData
对象用以将数据编译成键值对,以便用 XMLHttpRequest
来发送数据,其中如果表单 enctype
属性设为 multipart/form-data
,则会使用表单的 submit()
方法来发送数据;
var formData = new FormData();
formData.append("name", "tom");
formData.append("num", 123); //数字123会被立即转换成字符串 "123"
// 在jq使用 - 设置不处理数据及内容类型即可
var formData = new FormData(document.querySelector("form"));
formData.append("file", fileInputElement.files[0]);
$.ajax({
url: "stash.php",
type: "POST",
data: formData,
processData: false, // 不处理数据
contentType: false // 不设置内容类型
success(res){},
});
在 vue 模板配合 axios 使用如下:
<template>
<div id="app">
<input id="fileinput" @change="uploading($event)" type="file" accept="image/*">
<button @click.prevent="submit()"></button>
</div>
</template>
<script>
export default {
name: "#app",
data() {
return { file: "", src: "" };
},
methods: {
uploading(event) {
this.file = event.target.files[0]; //获取文件
var windowURL = window.URL || window.webkitURL;
this.file = event.target.files[0];
this.src = windowURL.createObjectURL(event.target.files[0]);//创建图片文件的url
},
submit() {
let formdata = new FormData();
formdata.append("file", this.file);
let config = {//此处必须设置为 multipart/form-data
headers: {
"Content-Type": "multipart/form-data" //之前说的以表单传数据的格式来传递fromdata
}
};
this.$http.post("/upload", formData, config)
.then(res => {
//do something
})
.catch(error => {});
}
}
};
</script>
iframe页面数据访问
由于三维地图浏览功能和其他大部分逻辑无关,所以放置在一个新的 iframe 中进行业务逻辑编写; 但是数据获取传入以及调用,需要调用方法和给变量赋值;
<!-- parent.html -->
<div class='iframeContainer'>
<iframe src='' id='myIframe'>
</div>
//iframe.js
var testValue; // 因为我们从主页面获取的是 window 对象,所以我们使用 var 声明变量,以便于直接进行获取;
function subFunction(){
//do something
}
// parent.js
let childWindow = document.querySelector('#myIframe').contentWindows; //获取到子页面的 window 对象
childWindow.testValue = 'changed' ; //修改
childWindow.subFunction(); //执行子页面的方法
// 对于子页面访问父页面则是可以通过`parent`即可访问到;