1 Star 1 Fork 0

不务正业的程序猿/three.js项目

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
map.vue 21.93 KB
一键复制 编辑 原始数据 按行查看 历史
lichen 提交于 2022-01-10 19:41 . 提交文件
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
<template>
<div class="demoContent" ref="demoContent">
<div class="box_lcs" ref="box">
<div class="content_lc" ref="mapBox" :style="{top:boxPosition.top+'px',left:boxPosition.left+'px'}"></div>
<div class="mapInfoBox" ref="mapInfoBox" :style="{top:boxPosition.top+'px',left:boxPosition.left+'px'}">
<!-- agv小车 -->
<div v-for="item in AGVList" :key="item.name" class="agvImg" :style="{width:item.width+'px',height:item.height+'px',top:item.y+'px',left:item.x+'px',transform:'rotate(-'+item.angle+'deg)'}">
<div class="point" :style="{top:item.centerTop+'px',right:item.centerRight+'px'}"></div>
<div class="direction"></div>
<div class="name">{{item.name}}</div>
</div>
<div class="stateName" v-if="showName">
<div class="name" v-for="item in stateNameList" :key="item.name" :style="{top:item.y+'px',left:item.x+'px'}">{{item.name}}</div>
</div>
</div>
<div class="btn" @click="controlName">{{btnText}}</div>
</div>
</div>
</template>
<script>
import * as THREE from '@/utils/three.js'
import routeData from './mapData'
import agvData from './agvStatus'
export default {
data(){
return{
mapData:{//地图数据
maxY:1,
maxX:1,
minY:-30,
minX:-80,
maxW:0,
maxH:0,
centerX:0,
centerY:0,
},
scene:'',//场景
renderer:'',//渲染器
AGVobj:{},//agv列表
siteObj:{},//站点列表
routeObj:{},//路列表
ratio:1,//缩放比例
myWidth:0,//地图的宽度
myHeight:0,//地图的高度
k:0,//软件生成地图与three.js绘制地图之间的比例关系
AGVList:[],//agv小车列表
routeData:routeData.topograph,
stateGroup:'',//站点组
windowEventFlag:true,//window事件对象开关
scrollFlag:true,//滚轮控制开关
positionStart:{//开始位置记录
top:0,
left:0
},
boxPosition:{//地图的真实定位位置
top:0,
left:0
},
mouseStart:{//鼠标落下时的位置记录
clientX:0,
clientY:0
},
box_offsetTop:0,//地图盒子的上边距页面顶部的距离
box_offsetLeft:0,//地图盒子的左边距离页面左边的距离
mouse_offsetLeft:0,//光标距离地图盒子左边的距离
mouse_offsetTop:0,//光标距离地图盒子上边的距离
box_height:0,//地图盒子的高度
box_width:0,//地图盒子的宽度
scaleFlag:false,//是否缩放
btnText:'显示站点名称',//按钮文字
showName:false,//站点名称控制开关
stateNameList:[],//站点名称列表
}
},
watch:{
ratio(newVal,oldVal){
//渲染地图
this.initMap();
this.boxPosition.left = this.mouse_offsetLeft - (this.mouse_offsetLeft - this.boxPosition.left)*newVal/oldVal;
this.boxPosition.top = this.mouse_offsetTop - (this.mouse_offsetTop - this.boxPosition.top)*newVal/oldVal;
}
},
created(){
this.mapData.maxW = this.mapData.maxX - this.mapData.minX;
this.mapData.maxH = this.mapData.maxY - this.mapData.minY;
this.mapData.centerX = (this.mapData.maxX + this.mapData.minX)/2;
this.mapData.centerY = (this.mapData.maxY + this.mapData.minY)/2;
},
mounted(){
this.demoContent = this.$refs.demoContent;//整个子组件根标签
this.box = this.$refs.box;//地图和地图信息的大盒子
this.content = this.$refs.mapBox;//地图的盒子
this.mapInfoBox = this.$refs.mapInfoBox;//地图信息的盒子
//渲染地图
// this.initMap();
window.addEventListener('keydown',this.myKeydown,false)
window.addEventListener('keyup',this.myKeyup,false)
window.addEventListener('mousewheel',this.eventScroll,{passive:false})
this.onresize(this.demoContent,this.initMap)
},
beforeDestroy(){
setTimeout(()=>{
console.log('清理计时器')
clearInterval(window.timer)
},1000)
window.removeEventListener('keydown',this.myKeydown,false);
window.removeEventListener('keyup',this.myKeyup,false);
window.removeEventListener('mousewheel',this.eventScroll,{passive:false})
},
methods:{
controlName(){//按钮的点击事件
if(this.showName){
this.showName = false;
this.btnText = '显示站点名称'
}else{
this.showName = true;
this.btnText = '隐藏站点名称'
}
},
getAGVState(){//获取agv位置信息
// agvRunStates({
// ownerId:this.factoryId
// }).then((res)=>{
// this.renderAGV(agvData);
// })
},
transform_threeToHtml(data){
var newData = {};
newData.x = data.x + (this.myWidth)/2;
newData.y = -data.y + this.myHeight/2;
for(var key in data){
if(!(key=='x'||key=='y')){
newData[key] = data[key]
}
}
return newData
},
transform_yalmToThree(data){
var newData = {};
newData.x = (data.x - this.mapData.centerX)*this.k;
newData.y = (data.y-this.mapData.centerY)*this.k;
for(var key in data){
if(!(key=='x'||key=='y')){
newData[key] = data[key]
}
}
return newData
},
initMap(){
//放大时需要的数据
this.box_offsetTop = this.getAbsTop();
this.box_offsetLeft = this.getAbsLeft();
//初始化地图
var demoContent_height = this.demoContent.clientHeight;
var box_offsetTop = this.box.offsetTop;
this.box_height = demoContent_height-box_offsetTop;
this.box.style.height = this.box_height+'px';
this.content.innerHTML = '';
this.box_width = this.box.offsetWidth;
this.myWidth= this.box_width*this.ratio;
this.k = (this.myWidth)/(this.mapData.maxW+20);
this.myHeight = this.k*this.mapData.maxH + 50;
this.content.style.width = this.myWidth+'px';
this.content.style.height = this.myHeight+'px';
//场景
this.scene = new THREE.Scene();
//相机
this.camera = new THREE.OrthographicCamera(this.myWidth / -2, this.myWidth / 2, this.myHeight/ 2, this.myHeight/ -2, 0.1, 1000);
// camera.position.z = 5;
this.camera.position.set(0, 0, 1000);
this.camera.lookAt(0, 0, 0);
//渲染器
this.renderer = new THREE.WebGLRenderer({
precision: 'highp'
});
// 分辨率
this.renderer.setPixelRatio(window.devicePixelRatio)
this.renderer.setSize(this.myWidth, this.myHeight);
this.content.appendChild(this.renderer.domElement);
// 光源
// var light = new THREE.AmbientLight();
var light = new THREE.DirectionalLight(0xFFFFFF,1);
light.position.set(0,0,1000)
this.scene.add(light)
// 背景色
this.setBackground();
this.render();
},
render(){
//渲染agv
clearInterval(window.timer)
this.getAGVState()
window.timer = setInterval(()=>{
this.getAGVState()
},1000)
this.renderRoute();
this.renderPointer();
this.renderStateName();
this.renderAGV(agvData);
this.box.addEventListener('mouseleave', this.onMouseleave, false);
this.box.addEventListener('mousedown', this.onMousedown, false);
this.renderer.render(this.scene, this.camera);
},
renderAGV(AGVStatus){
var arr = [];
AGVStatus.forEach(item=>{
var obj = {
name:item.agvEntity.agvId,
angle:item.agvState.stateMessage.pose.degree,
};
var obj2 = this.transform_yalmToThree({x:item.agvEntity.agvContour.length,y:item.agvEntity.agvContour.width});
var obj3 = this.transform_yalmToThree({x:0,y:0});
var obj4 = this.transform_yalmToThree({x:item.agvEntity.agvContour.centerX,y:item.agvEntity.agvContour.centerY});
obj.width = obj2.x - obj3.x;
obj.height = obj2.y - obj3.y;
obj.centerTop = obj4.y - obj3.y;
obj.centerRight = obj4.x - obj3.x;
var position = this.transform_threeToHtml(this.transform_yalmToThree({x:item.agvState.stateMessage.pose.x,y:item.agvState.stateMessage.pose.y}));
obj.x = position.x;
obj.y = position.y;
arr.push(obj);
});
this.AGVList = arr;
},
renderRoute(){
var roudeGroup = new THREE.Group();
this.routeData.roads.forEach(item=>{
var start = this.transform_yalmToThree(item.keypoints_id[0]);
var end = this.transform_yalmToThree(item.keypoints_id[1]);
var geometry = new THREE.BufferGeometry()
if(item.road_type=='line'){
var pointsArray = new Array()
pointsArray.push(new THREE.Vector2(start.x, start.y))
pointsArray.push(new THREE.Vector2(end.x, end.y))
//用这个api传入顶点数组
geometry.setFromPoints(pointsArray)
}else if(item.road_type=='bspline'){
if(item.controlpoints.length==3){
var center = this.transform_yalmToThree(item.controlpoints[1]);
var curve = new THREE.QuadraticBezierCurve(
new THREE.Vector2(start.x , start.y),
new THREE.Vector2(center.x, center.y),
new THREE.Vector2(end.x, end.y));
var points = curve.getPoints(1000);
}else if(item.controlpoints.length!=3){
var control1 = this.transform_yalmToThree(item.controlpoints[1]);
var control2 = this.transform_yalmToThree(item.controlpoints[item.controlpoints.length-2]);
var curve = new THREE.CubicBezierCurve(
new THREE.Vector2(start.x , start.y),
new THREE.Vector2(control1.x, control1.y),
new THREE.Vector2(control2.x, control2.y),
new THREE.Vector2(end.x, end.y));
var points = curve.getPoints(1000);
}
geometry.setFromPoints(points);
}
var material = new THREE.LineBasicMaterial({
color: 0xCC5B5B,
});
var line = new THREE.Line(geometry, material);
roudeGroup.add(line);
})
this.scene.add(roudeGroup);
},
renderPointer(){
var pointGroup = new THREE.Group();
this.routeData.waypoints.forEach(item=>{
var obj = {
x:item.x/10,
y:item.y/10
}
var position = this.transform_yalmToThree(obj);
var geometry = new THREE.CircleBufferGeometry(2,6);
var material = new THREE.MeshBasicMaterial({//绿色
color:0x000000,
});
var plane = new THREE.Mesh(geometry, material);
plane.position.set(position.x,position.y,1);
pointGroup.add(plane);
})
this.scene.add(pointGroup);
},
renderStateName(){
var arr = [];
this.routeData.waypoints.forEach(item=>{
var obj = {
x:item.x/10,
y:item.y/10
}
// var obj = {
// x:item.x,
// y:item.y
// }
var position = this.transform_threeToHtml(this.transform_yalmToThree(obj));
position.name = item.id;
position.y = position.y-12;
position.x = position.x+3;
arr.push(position)
})
this.stateNameList = arr;
},
onMousedown(e){//鼠标按下,拖动开始
this.mouseStart.clientX = e.clientX;
this.mouseStart.clientY = e.clientY;
this.positionStart.top = this.boxPosition.top;
this.positionStart.left = this.boxPosition.left;
this.box.addEventListener('mousemove', this.onMousemove, false);
this.box.addEventListener('mouseup', this.onMouseup, false);
},
onMousemove(e){//拖动事件
var distance = {};
distance.x = e.clientX - this.mouseStart.clientX;
distance.y = e.clientY - this.mouseStart.clientY;
this.boxPosition.left = this.positionStart.left + distance.x;
this.boxPosition.top = this.positionStart.top + distance.y;
},
onMouseup(e){
this.box.removeEventListener('mousemove', this.onMousemove, false);
this.box.removeEventListener('mouseup', this.onMouseup, false);
},
myKeydown(e){//按键按下
if(this.windowEventFlag){
this.windowEventFlag = false;
if(e.keyCode==17){
this.scaleFlag = true;
}
}
},
eventScroll(e){
e.preventDefault();
//如果光标不在地图范围内,什么也不做
if(!(e.clientX>this.box_offsetLeft && e.clientY>this.box_offsetTop && e.clientX<(this.box_offsetLeft+this.box_width) && e.clientY<(this.box_offsetTop+this.box_height))){
return;
}
if(!this.scaleFlag){
return;
}
this.mouse_offsetLeft = e.clientX - this.box_offsetLeft;
this.mouse_offsetTop = e.clientY - this.box_offsetTop;
if(this.scrollFlag){
this.scrollFlag = false;
if(e.wheelDelta>0){
this.ratio = this.ratio + 0.3
}else{
var ratio = this.ratio - 0.3;
if(ratio>=1){
this.ratio = ratio
}else{
this.ratio = 1
}
}
setTimeout(()=>{
this.scrollFlag = true;
},10)
}
},
myKeyup(e){//按键抬起
this.windowEventFlag = true;
if(e.keyCode == 17){
this.scaleFlag = false;
}
},
//设置背景色
setBackground(){
// var geometry = new THREE.PlaneBufferGeometry(myWidth, myHeight, 1);
var geometry = new THREE.PlaneBufferGeometry(this.myWidth, this.myHeight, 1);
var material = new THREE.MeshBasicMaterial({
color:0xFFFFFF
});
var plane = new THREE.Mesh(geometry, material);
this.scene.add(plane);
},
//画站点
renderState(data){
// var stateGroup = new THREE.Group();
// var config = data;
var geometry = new THREE.CircleBufferGeometry(4,10);
var plane;
var material = new THREE.MeshBasicMaterial({//绿色
color:data.color,
opacity:data.opacity,
transparent:data.transparent
});
plane = new THREE.Mesh(geometry, material);
plane.position.set(data.position.x,data.position.y,data.position.z?data.position.z:12)
var obj = this.transform_threeToHtml(data.position);
data.positionTop = obj.y;
data.positionLeft = obj.x;
plane.config = data;
return plane
},
// 鼠标点击触发的方法
onMouseclick(event) {
clearTimeout(this.timer3);
this.timer3 = setTimeout(()=>{
// 获取 raycaster 和所有模型相交的数组,其中的元素按照距离排序,越近的越靠前
var intersects = this.getIntersects(event);
// 获取选中最近的 Mesh 对象
if (intersects.length != 0 && intersects[0].object instanceof THREE.Mesh) {
var selectObject = intersects[0].object;
if(selectObject.config){
if(selectObject.config.myType=='route'){
this.routeKey = selectObject.config.key;
}else{
this.routeKey = '';
if(selectObject.config.myType=='state'){
this.tip.state.show=true;
this.tip.state.left = selectObject.config.positionLeft+'px';
this.tip.state.top = (selectObject.config.positionTop-80)+'px';
this.tip.state.siteName = selectObject.config.siteName;
this.tip.state.siteCode = selectObject.config.siteCode;
this.tip.state.siteStatus = selectObject.config.siteStatus;
this.tip.state.mapNode = selectObject.config.mapNode;
}
}
}else{
this.routeKey = '';
}
} else {
this.routeKey = '';
}
},200)
},
getAbsTop(){
var t=this.box.offsetTop;
var obj = this.box;
while(obj.offsetParent != null){
obj = obj.offsetParent;
t += obj.offsetTop;
}
return t;
},
getAbsLeft(){
var l=this.box.offsetLeft;
var obj = this.box;
while(obj.offsetParent != null){
obj = obj.offsetParent;
l += obj.offsetLeft;
}
return l;
},
// 获取与射线相交的对象数组
getIntersects(event) {
event.preventDefault();
// 声明 raycaster 和 mouse 变量
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
// 通过鼠标点击位置,计算出 raycaster 所需点的位置,以屏幕为中心点,范围 -1 到 1
mouse.x = ((event.clientX - this.content.getBoundingClientRect().left)/ this.myWidth) * 2 - 1;
mouse.y = ((event.clientY - this.content.getBoundingClientRect().top)/-this.myHeight) * 2 + 1;
//通过鼠标点击的位置(二维坐标)和当前相机的矩阵计算出射线位置
raycaster.setFromCamera(mouse, this.camera);
// 获取与射线相交的对象数组,其中的元素按照距离排序,越近的越靠前
var intersects = raycaster.intersectObjects(this.scene.children);
//返回选中的对象
return intersects;
},
onresize(dom_elem, callback){
const resizeObserver = new ResizeObserver(() => callback() );
resizeObserver.observe(dom_elem);
}
},
filters:{
}
}
</script>
<style lang="scss">
.demoContent{
min-height: calc(100vh - 90px);
background: #0e1221;
position: relative;
}
.agvImg{
width: 60px;
height: 50px;
position: absolute;
z-index: 5;
border: 1px solid #cccccc;
background: rgba(204,204,204,0.3);
transform: translate(-50%,-50%);
.point{
width: 5px;
height: 5px;
border-radius: 50%;
background: #9be31c;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
}
.name{
position: absolute;
top: 50%;
transform: translateY(-50%);
right: 55%;
height: 12px;
font-size: 12px;
line-height: 12px;
text-align: right;
color: #24c0ff;
}
.direction{
display: block;
position: absolute;
top: 50%;
right: -10px;
width: 0;
height: 0;
border-left: 5px solid #9be31c;
border-top: 5px solid transparent;
border-right: 5px solid transparent;
border-bottom: 5px solid transparent;
transform: translateY(-50%);
}
}
.stateName{
position: absolute;
top: 0;
left: 0;
.name{
width: 20px;
height: 12px;
line-height: 12px;
text-align: center;
color: #24c0ff;
position: absolute;
}
}
.btn{
width: 120px;
height: 30px;
line-height: 30px;
text-align: center;
border-radius: 5px;
border: 1px solid #cccccc;
background: rgba(133,137,8,0.5);
color: #fff;
position: absolute;
top: 20px;
left: 20px;
}
.box_lcs{
// overflow: auto;
position: relative;
background: #ffffff;
// background: #0E1221;
overflow: hidden;
cursor: pointer;
.mapInfoBox{
position: absolute;
top: 0;
left: 0;
}
.content_lc{
position: relative;
}
}
</style>
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/a-derelict-programmer/three-js-project.git
git@gitee.com:a-derelict-programmer/three-js-project.git
a-derelict-programmer
three-js-project
three.js项目
master

搜索帮助