js室内地图开发_使用JS+Three.js+Echart开发商场室内地图客流信息统计功能

本文介绍了使用JS、Three.js和Echart开发的商场室内地图客流信息统计功能,包括饼状图展示客流量、线性图表展示流量趋势和人群密度,以及控制面板的实时视频和全景漫游功能,旨在提升商场管理效率。
摘要由CSDN通过智能技术生成

现在的商场管理者在管理商场的同时面临着一些无法避免的问题比如:人员监管不到位、效率低下、商场同质化严重,人流量少等。发现了这些问题作为开发人员的我们怎能视而不见,我们的责任就是发现问题解决问题,提供更好更智能的服务。因此就此问题我们想出了相应的解决办法,使用JS+Three.js+Echart开发了一个功能界面,为商场管理者提供更加高效的管理方法。

通过商场管理系统的相应界面,商场管理者可实时获取商场的人流数据、人流密度的热力分布、可实时查看商场各处的视频监控信息、安保人员的实时位置信息及运动轨迹。针对突发状况可以即时调度、快速处理。还可以依据大数据分析周边业态情况,为制定运营策略提供数据支持等。

就以上的市场实际情况需求,开始了我的功能开发之旅。

我使用ESMap的地图编辑器编辑好商场地图后,开始布局规划解决问题

开发流程如下:

首先,实现一个商场客流量信息的饼状统计表,还有各个时间点的流量趋势和人群密度的线性图表。再实现一个控制面板,可以通过控制面板根据地图的热力图查看商场各个位置客流量以及各个位置的实时视频等,情况一目了然;最后做一个可以搜索店铺客流量及营业额情况的搜索框。

1.方便开发,先使用模拟数据创建图表,投入使用后自行接入后台数据即可。

(1)使用Echart创建统计客流量的饼状图:

functioncircleSet() {

myChart1= echarts.init(document.getElementById('ec1'));

myChart2= echarts.init(document.getElementById('ec2'));var color= ['#b679fe', '#6271fd','#94d96c', '#0fbdd9','#f0f0f0'];var dataStyle ={

normal: {

label: {

show:false},

labelLine: {

show:false},

shadowBlur:40,

borderWidth:10,

shadowColor:'rgba(0, 0, 0, 0)' //边框阴影}

};//第一个饼状图

var optionCircleA ={

backgroundColor:'#fff',

title: {

text:'52452',

x:'center',

y:'center',

textStyle: {

fontWeight:'normal',

fontSize:14,

color:"#b679fe",

}

},

series: [{

name:'Line 1',

type:'pie',

clockWise:false,

radius: [37, 45],

center:['50%','50%'],

itemStyle: dataStyle,

hoverAnimation:false,

startAngle:90,

label:{

borderRadius:'10',

},

data: [{

value:54.6,

name:'外',

itemStyle: {

normal: {

color:new echarts.graphic.LinearGradient(0, 0, 0, 1, [{

offset:0,

color:color[0]

}, {

offset:1,

color: color[1]

}])

}

}

},

{

value:0,

name:'',

tooltip: {

show:false},

},

]

},

{

name:'Line 2',

type:'pie',

clockWise:false,

radius: [30, 32],

center:['50%','50%'],

itemStyle: dataStyle,

hoverAnimation:false,

startAngle:90,

data: [{

value:56.7,

name:'内',

itemStyle: {

normal: {

color:new echarts.graphic.LinearGradient(0, 0, 0, 1, [{

offset:0,

color: color[4]

}, {

offset:1,

color: color[4]

}])

}

}

},

{

value:0,

name:'',

tooltip: {

show:false},

},

]

},

]

};//第二个饼状图

var optionCircleB ={

backgroundColor:'#fff',

title: {

text:'15386',

x:'center',

y:'center',

textStyle: {

fontWeight:'normal',

fontSize:14,

color:"#94d96c",

}

},

series: [{

name:'Line 1',

type:'pie',

clockWise:false,

radius: [37, 45],

center:['50%','50%'],

itemStyle: dataStyle,

hoverAnimation:false,

startAngle:90,

label:{

borderRadius:'10',

},

data: [{

value:54.6,

name:'外',

itemStyle: {

normal: {

color:new echarts.graphic.LinearGradient(0, 0, 0, 1, [{

offset:0,

color:color[2]

}, {

offset:1,

color: color[3]

}])

}

}

},

{

value:0,

name:'',

tooltip: {

show:false},

},

]

},

{

name:'Line 2',

type:'pie',

clockWise:false,

radius: [30, 32],

center:['50%','50%'],

itemStyle: dataStyle,

hoverAnimation:false,

startAngle:90,

data: [{

value:56.7,

name:'内',

itemStyle: {

normal: {

color:new echarts.graphic.LinearGradient(0, 0, 0, 1, [{

offset:0,

color: color[4]

}, {

offset:1,

color: color[4]

}])

}

}

},

{

value:0,

name:'',

tooltip: {

show:false},

},

]

},

]

};

myChart1.setOption(optionCircleA);

myChart2.setOption(optionCircleB);

}

效果如下图:

(2)使用echart创建人群密度线性图表,封装在函数lineSetA()内:

//人群密度线性图表

functionlineSetA() {

myChart3= echarts.init(document.getElementById('ec3'));var colors = ['#12c3f8', '#4384d7'];

optionLineA={

color: colors,

visualMap: [{

show:false,

type:'continuous',

seriesIndex:0,

min:0,

max:600,

borderWidth:3,

color: colors,

}],

xAxis: {

type:'category',

data: ['0', '2', '4', '6', '8', '10', '12', '14', '16', '18', '20', '22'],

show:true,

position: {

bottom:10,

show:false,

},

onZero:false,

axisLine: {

lineStyle: {

width:0,

}

}

},

yAxis: {

type:'value',

axisLabel: {

formatter:'{value} 人',

fontSize:10,

},

axisLine: {

lineStyle: {

width:0,

}

},

minInterval:300,

},

grid: [{

top:'40',

bottom:'25',

left:'50',

right:'10'}],

series: [{

data: [0, 10, 20, 30, 40, 100, 600, 900, 880, 900, 1100, 1000],

type:'line',

smooth:true,

markPoint: {

data: [

{

name:'880',

coord: ['16','880'],

value:'880',

],

label: {

show:true,

},

}

}]

};

myChart3.setOption(optionLineA);

}

创建流量趋势线性图表,封装在函数lineSetB()内:

//流量趋势线性图表

functionlineSetB() {

myChart4= echarts.init(document.getElementById('ec3'));var colors = ['#12c3f8', '#4384d7'];var optionLineB ={

color: colors,

visualMap: [{

show:false,

type:'continuous',

seriesIndex:0,

min:0,

max:600,

borderWidth:3,

color: colors,

}],

xAxis: {

type:'category',

data: ['0', '2', '4', '6', '8', '10', '12', '14', '16', '18', '20', '22'],

show:true,

position: {

bottom:10,

show:false,

},

onZero:false,

axisLine: {

lineStyle: {

width:0,

}

}

},

yAxis: {

type:'value',

axisLabel: {

formatter:'{value} 人/平方米',

fontSize:10,

},

axisLine: {

lineStyle: {

width:0,

}

},

minInterval:0.5,

},

grid: [{

top:'40',

bottom:'25',

left:'70',

right:'10'}],

series: [{

data: [0, 1, 2, 3, 4, 3, 2, 3, 3.5, 2, 1, 3],

type:'line',

smooth:true,

markPoint: {

data: [

{

name:'4',

coord: ['14','3'],

value:'4',

}

],

label: {

show:true,

},

}

}]

};

myChart4.setOption(optionLineB);

}

切换线性图表数据显示实现:

//切换线性图表数据显示

$(".list-b .title-box .t-a").click(function() {//点击流量趋势

$(".list-b .title-box .t-b").removeClass('active');//移除当前样式

$(this).addClass('active');//给点击添加新样式

resizeLineA();

})

$(".list-b .title-box .t-b").click(function() {//点击人群密度

$(".list-b .title-box .t-a").removeClass('active');

$(this).addClass('active');

resizeLineA(1);

})

更换装图表的盒子(div)和线性图表信息:

functionresizeLineA(n) {

$(".line-cen").remove();//先移除原有的盒子

var aa = document.createElement('div');//在创建一个新盒子装图表

aa.id = 'ec3'aa.className= 'line-cen'$(".line-box").append(aa)if (n == 1) {

lineSetA();//显示人群密度图表

} else{

lineSetB();//显示流量趋势图表

}

}

效果如下图:

除此之外,还可以根据实际情况再添加相应的图表。

2.check控制面板

开发一个控制面板,对管理者来说可以更好的全局掌握控制商场情况我在控制面板上加了实时视频,全景漫游和客流分布,下面就这三个功能的实现过程做下介绍。

(1)客流分布热力图功能,以下载入的是模拟数据,投入使用后可直接载入实际数据,根据数据体现热力图的情况。

//添加热力图,根据json文件

functionaddHeatMap() {//创建热力图对象

if (!heatmapInstance)

heatmapInstance=esmap.ESHeatMap.create(map, {

radius:24, //热点半径

opacity: .5, //热力图透明度

max: 35, //热力点value的最大值

maxSize: 2048,

gradient: {//渐变色值,可配

0.35: "green",0.5: "yellow",0.7: "orange",0.85: "red"}

$.getJSON("data/003.json", function(data) { //数据载入

var datas =data.datas;var len =datas.length;

exec(datas[0]["data"][0]["fnum"], datas[0]["data"][0]["points"]);//绘制热力图

var index = 1;

timer1= setInterval(function() {if (index > 1) index = 0;for (var el of datas[0]["data"][0]["points"]) {switch(index) {case 0: el.value = el.value - 1;break;case 1: el.value = el.value + 1;break;

}

}

exec(datas[0]["data"][0]["fnum"], datas[0]["data"][0]["points"]);

index++;

},2000)return;

});function exec(fnum, points) {//绘制热力图函数

var floorLayer = map.getFloor(fnum);//获取应用楼层

heatmapInstance.clearPoints();//清除热力点

heatmapInstance.addPoints(points);//热力点添加到热力图

//热力图应用到哪一楼层

floorLayer.applyHeatMap(heatmapInstance);

}

}

热力图如下:

(2)实时视频及全景漫游的实现:

首先创建实时视频的摄像头图片标注和全景漫游的360°图片标注,标注实现后可在地图上点击相应的图片标注从而显示实时视频画面或360°全景画面,画面可拖拽可放大缩小。

各楼层实时视频的摄像头图片标注:

//创建各楼层摄像头标注

functionshowCameras() {var url = 'data/test666/model/camera1.js';//json数据,定义摄像头所在楼层和位置

var infos =[{

fnum:1,

cameras: [{

x:12683472.409512023,

y:2557870.1781415385,

},

{

x:12683450.258123305,

y:2557858.104209115},

{

x:12683430.863774385,

y:2557865.8999765064}

]

}, {

fnum:2,

cameras: [{

x:12683472.409512023,

y:2557870.1781415385,

},

{

x:12683450.258123305,

y:2557858.104209115},

{

x:12683430.863774385,

y:2557865.8999765064}

]

}, {

fnum:3,

cameras: [{

x:12683472.409512023,

y:2557870.1781415385,

},

{

x:12683450.258123305,

y:2557858.104209115},

{

x:12683430.863774385,

y:2557865.8999765064}

]

}];//创建三维模型标注 实时视频摄像头

var ang = 0;

infos.forEach(function(info) {var floorLayer =map.getFloor(info.fnum);var layer = floorLayer.getOrCreateLayerByName("cameras", esmap.ESLayerType.MODEL3D);var _id = 1;

info.cameras.forEach(function(camera) {var im = newesmap.ES3DMarker({

x: camera.x,

y: camera.y,

id: _id++,

name:"camera",

url: url,

size:44,

angle: ang,

height:3,

showLevel:16,

spritify:true});

ang+= 30;

layer.addMarker(im);//一个楼层共用一个图层

});

layer&&layer.show3D();

});

}

点击地图展示实时视频或全景漫游弹框(div)函数active():

//地图点击标注后 临时创建div盒子 放全景图或实时视频

function active(e, type) { //type: 1.pano; 0.video

var cc = $($(".drag")[0]).clone();var wid = $(".drag").width();

$("body").append(cc);

cc[0].style.display = "block";if (__xx

__xx=wid;

}

cc[0].style.left = (__xx - wid - 20).toString() + "px";

cc[0].style.top = (__yy - 25 / 2).toString() + "px";if (!type) {

cc.find('.content')[0].innerHTML = '';

cc.find('.title h2')[0].innerHTML = '实时视频';

createPopBox();

}else{

cc.find('.title h2')[0].innerHTML = '全景展示';var box = document.createElement('div');

cc.find('.content').append(box);

box.className= 'psv-box';

oPano= newCreatePanorama({

container: box,

panorama:'image/pano/' + e.id + '/',

six:1})

createPopBox(oPano);

}

}

展示的弹框可拖拽、大小可调整,功能实现如下函数:

/*可拖拽可放大缩小弹框*/

function createPopBox(pano) { //pano: 0.视频,1.全景

/*-------------------------- +

获取id, class, tagName 函数

+--------------------------*/

var get ={

byId:function(id) {return typeof id === "string" ?document.getElementById(id) : id;

},

byClass:function(sClass, oParent) {var aClass =[];var reClass = new RegExp("(^| )" + sClass + "( |$)");var aElem = this.byTagName("*", oParent);for (var i = 0; i < aElem.length; i++) reClass.test(aElem[i].className) &&aClass.push(aElem[i]);returnaClass

},

byTagName:function(elem, obj) {return (obj ||document).getElementsByTagName(elem);

}

};var dragMinWidth = 250;var dragMinHeight = 173;/*-------------------------- +

拖拽函数

+--------------------------*/

functiondrag(oDrag, handle) {var disX = dixY = 0;var oMax = get.byClass("max", oDrag)[0];//获取最大化div的 class

var oRevert = get.byClass("revert", oDrag)[0];//获取恢复div的 class

var oClose = get.byClass("close", oDrag)[0];//获取关闭div的 class

handle = handle ||oDrag;

handle.style.cursor= "move";

handle.οnmοusedοwn= function(event) {var event = event ||window.event;

disX= event.clientX -oDrag.offsetLeft;

disY= event.clientY -oDrag.offsetTop;

document.οnmοusemοve= function(event) {var event = event ||window.event;var iL = event.clientX -disX;var iT = event.clientY -disY;var maxL = document.documentElement.clientWidth -oDrag.offsetWidth;var maxT = document.documentElement.clientHeight -oDrag.offsetHeight;

iL<= 0 && (iL = 0);

iT<= 0 && (iT = 0);

iL>= maxL && (iL =maxL);

iT>= maxT && (iT =maxT);

oDrag.style.left= iL + "px";

oDrag.style.top= iT + "px";return false};

document.οnmοuseup= function() {

document.οnmοusemοve= null;

document.οnmοuseup= null;this.releaseCapture && this.releaseCapture()

};this.setCapture && this.setCapture();return false};//最大化按钮

oMax.onclick = function() {if (!pano) {

$(this).parents('.drag').find('.video_')[0].webkitEnterFullscreen(true);

}else{

fullPano= 1;

oDrag.classList.add('over-auto');var _box = $(oDrag).find('.psv-box')[0];

_box.classList.add('psv-full', 'over-auto');var _div = document.createElement('div');

document.body.append(_div);

_div.className= 'psv-full-btns';

_div.innerHTML= ''document.οnkeydοwn= function(e) {if (e.keyCode == 27 && fullPano == 1) {

fullPano= 0;

oDrag.classList.remove('over-auto');

_box.classList.remove('psv-full', 'over-auto');

_div.remove();

pano.onWindowResize();

}

}

$(_div).find('.full-revert').click(function() {

fullPano= 0;

oDrag.classList.remove('over-auto');

_box.classList.remove('psv-full', 'over-auto');

_div.remove();

pano.onWindowResize();

})

pano.onWindowResize();

}

};//还原按钮

oRevert.onclick = function() {

oDrag.style.width= dragMinWidth + "px";

oDrag.style.height= dragMinHeight + "px";

oDrag.style.left= (document.documentElement.clientWidth - oDrag.offsetWidth) / 2 + "px";

oDrag.style.top= (document.documentElement.clientHeight - oDrag.offsetHeight) / 2 + "px";this.style.display = "none";

oMax.style.display= "block";

pano&&pano.onWindowResize();

};//关闭按钮

oClose.onclick = function() {if (!pano) {

$(this).parents('.drag').remove();

}else{

oPano= null;

$(this).parents('.drag').remove();

}

};//阻止冒泡

oMax.onmousedown = oClose.onmousedown = function(event) {this.onfocus = function() {this.blur();

};

(event|| window.event).cancelBubble = true};

}/*-------------------------- +

改变大小函数

+--------------------------*/

functionresize(oParent, handle, isLeft, isTop, lockX, lockY) {

handle.οnmοusedοwn= function(event) {var event = event ||window.event;var disX = event.clientX -handle.offsetLeft;var disY = event.clientY -handle.offsetTop;var iParentTop =oParent.offsetTop;var iParentLeft =oParent.offsetLeft;var iParentWidth =oParent.offsetWidth;var iParentHeight =oParent.offsetHeight;

document.οnmοusemοve= function(event) {var event = event ||window.event;var iL = event.clientX -disX;var iT = event.clientY -disY;var maxW = document.documentElement.clientWidth - oParent.offsetLeft - 2;var maxH = document.documentElement.clientHeight - oParent.offsetTop - 2;var iW = isLeft ? iParentWidth - iL : handle.offsetWidth +iL;var iH = isTop ? iParentHeight - iT : handle.offsetHeight +iT;

isLeft&& (oParent.style.left = iParentLeft + iL + "px");

isTop&& (oParent.style.top = iParentTop + iT + "px");

iW< dragMinWidth && (iW =dragMinWidth);

iW> maxW && (iW =maxW);

lockX|| (oParent.style.width = iW + "px");

iH< dragMinHeight && (iH =dragMinHeight);

iH> maxH && (iH =maxH);

lockY|| (oParent.style.height = iH + "px");if ((isLeft && iW == dragMinWidth) || (isTop && iH == dragMinHeight)) document.onmousemove = null;

pano&&pano.onWindowResize();return false;

};

document.οnmοuseup= function() {

document.οnmοusemοve= null;

document.οnmοuseup= null;

};return false;

}

};functionaaa() {var dom = document.getElementsByClassName("drag");var oDrag = dom[dom.length - 1];var oTitle = get.byClass("title", oDrag)[0];var oL = get.byClass("resizeL", oDrag)[0];var oT = get.byClass("resizeT", oDrag)[0];var oR = get.byClass("resizeR", oDrag)[0];var oB = get.byClass("resizeB", oDrag)[0];var oLT = get.byClass("resizeLT", oDrag)[0];var oTR = get.byClass("resizeTR", oDrag)[0];var oBR = get.byClass("resizeBR", oDrag)[0];var oLB = get.byClass("resizeLB", oDrag)[0];

drag(oDrag, oTitle);//拉四角

resize(oDrag, oLT, true, true, false, false);

resize(oDrag, oTR,false, true, false, false);

resize(oDrag, oBR,false, false, false, false);

resize(oDrag, oLB,true, false, false, false);//拉四边

resize(oDrag, oL, true, false, false, true);

resize(oDrag, oT,false, true, true, false);

resize(oDrag, oR,false, false, false, true);

resize(oDrag, oB,false, false, true, false);

oDrag.style.left= (document.documentElement.clientWidth - oDrag.offsetWidth) / 2 + "px";

oDrag.style.top= (document.documentElement.clientHeight - oDrag.offsetHeight) / 2 + "px";

}

aaa();

}

功能都实现后投入使用,点击地图上的标注显示相应的实时视频,这里我使用了ESMap的地图点击事件map.on(“mapClickNode”,function(){});

map.on("mapClickNode", function(e) {

removeAll();if (e.nodeType && e.nodeType == 31 && e.name && e.name == 'myMarker') {//全景

active(e, 1);

}if (e.nodeType && e.nodeType == 6 && e.name && e.name == 'camera') {//视频

active(e)

}if (e.nodeType && e.nodeType == 5) {//点击地图商铺显示相应运营情况

if(e.name) {var obj ={

id: e.ID,

fnum: e.FloorNum,

x: e.x,

y: e.y,

name: e.name

}

searchClick(obj);// 函数如下

} } })

封装气泡标注函数searchClick(),显示商铺信息:

functionsearchClick(data, isAddImageMarker) {if (!data.name) return;//添加pop

removeAll();var floorLayer =map.getFloor(data.fnum);if(isAddImageMarker) {

floorControl.changeFocusFloor(data.fnum);

}if (data.name == '房间') {var dom = '

房间 ' + data.id + '

经度:' + data.x.toFixed(3) + '

纬度:' + data.y.toFixed(3) + '

';

}else{var shopDatas = getShopMsg(data.id);//数字number

var dom = '

' + data.name + '

人流量:' + shopDatas.msgA + '

营业额:' + shopDatas.msgB + '

'}//添加信息窗

popMarker = newesmap.ESPopMarker({

mapCoord: {//设置弹框的x轴

x: data.x,//设置弹框的y轴

y: data.y,

height:1, //控制信息窗的高度

//设置弹框位于的楼层

fnum: data.fnum

},//设置弹框的宽度

width: 200,//设置弹框的高度

height: 120,

marginTop:10,//设置弹框的内容

content: dom,//content: '',

closeCallBack: function() {//信息窗点击关闭操作

//alert('信息窗关闭了!');

},

});

$(".es-control-popmarker input").val('✖'); //手动添加close按钮value

}

效果图如下:

各楼层全景漫游的360°图片标注:

//创建360°图片标注到各层

functionshowImageMarker() {var _arr =[{

fnum:1,

node: [{

x:12683473.823037906,

y:2557891.805802924,

},

{

x:12683424.1333389,

y:2557880.7494297,

}

]

}, {

fnum:2,

node: [{

x:12683473.823037906,

y:2557891.805802924,

},

{

x:12683424.1333389,

y:2557880.7494297,

}

]

}, {

fnum:3,

node: [{

x:12683473.823037906,

y:2557891.805802924,

},

{

x:12683424.1333389,

y:2557880.7494297,

}

]

}]for (varel of _arr) {var floorLayer =map.getFloor(el.fnum);var im_layer = new esmap.ESLayer('imageMarker');//创建图层

im_layer.name = 'mylayer';//给图层命名

var index = 1;for (varel2 of el.node) {var im = newesmap.ESImageMarker({

x: el2.x,

y: el2.y,

url:'image/360.png',

id: index++,

size:50,

name:'myMarker',

zoom:2,

})

im_layer.addMarker(im);

floorLayer.addLayer(im_layer);

}

}

}

图片标注创建后,使用three.JS创建全景图,然后绑定鼠标事件

functionCreatePanorama(prop) {varcamera, scene, renderer, container, mesh;vartexture_placeholder,target= new THREE.Vector3();//创建3维向量

this.container =container;this.panorama =prop.panorama;this.camera =camera;this.scene =scene;this.renderer =renderer;this.mesh =mesh;functioninit() {

container=prop.container;

camera= new THREE.PerspectiveCamera(75, container.clientWidth / container.clientHeight, 1, 1100);

scene= newTHREE.Scene();

texture_placeholder= document.createElement('canvas');

texture_placeholder.width= 128;

texture_placeholder.height= 128;var context = texture_placeholder.getContext('2d');

context.fillStyle= 'rgb( 200, 200, 200 )';

context.fillRect(0, 0, texture_placeholder.width, texture_placeholder.height);if(prop.six) {var materials =[

loadTexture(prop.panorama+ 'r.jpg'), //right

loadTexture(prop.panorama + 'l.jpg'), //left

loadTexture(prop.panorama + 'u.jpg'), //top

loadTexture(prop.panorama + 'd.jpg'), //bottom

loadTexture(prop.panorama + 'b.jpg'), //back

loadTexture(prop.panorama + 'f.jpg') //front

];var matss = newTHREE.MultiMaterial(materials)

mesh= new THREE.Mesh(new THREE.BoxGeometry(300, 300, 300, 7, 7, 7), matss);

}else{var geometry = new THREE.SphereGeometry(100, 64, 64, -1.5707963267948966);var material = newTHREE.MeshBasicMaterial({

map:newTHREE.TextureLoader().load(prop.panorama),

})

mesh= newTHREE.Mesh(geometry, material);

}

mesh.scale.x= -1;

scene.add(mesh);

renderer= new THREE.WebGLRenderer({//创建一个webGL渲染器,renderer

antialias: true})

renderer.setPixelRatio(window.devicePixelRatio);//设备设置像素比

renderer.setSize(container.clientWidth, container.clientHeight);//调整输出canvas尺寸

container.appendChild(renderer.domElement);//监听鼠标各种事件

container.addEventListener('mousedown', onDocumentMouseDown, false);

container.addEventListener('mousemove', onDocumentMouseMove, false);

container.addEventListener('mouseup', onDocumentMouseUp, false);

container.addEventListener('wheel', onDocumentMouseWheel, false);

container.addEventListener('touchstart', onDocumentTouchStart, false);

container.addEventListener('touchmove', onDocumentTouchMove, false);

window.addEventListener('resize', onWindowResize, false);

}

}

全景漫游完成,在地图上点击、拖拽、缩放功能如实时视频一样,效果如下图:

3.创建一个搜索框,可以直接锁定目标,查看店铺运营情况

//通过店名搜索地图中店铺 搜索框函数

functionsearchByName(name) {

Listmodel.item=[];if (!name) return;var data = map.mapService.sourceData.floors;//获取地图信息

for (var ele of data) {//遍历获取到的信息

for (var i in ele.Rooms) { //遍历获取到数组里的Rooms

var el =ele.Rooms[i];if(el.name) {var a = el.name.indexOf(name);//查找输入的店名是否在地图内存在

if (a != -1) {//如果存在

var obj ={

x: el.CenX,

y: el.CenY,

id: el._id,

fnum: ele.floornum,

name: el.name

}

Listmodel.item.push(obj);//把输入的店名信息存入数组

}

}

}

}

}

效果如下图:

以上就是我就商场管理者在管理过程中所面临的一些问题,开发的商场管理系统的一个界面,当然我只是简单实现了一些功能,在实际开发过程可根据实际情况定制一些功能方案,从而达到管理者高效管理的目的。ESMap-SDK提供的免费地图开发和热力图、图片标注等功能实现的支持。

Thank you for reading!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好,针对您的问题,我可以为您提供一些思路和参考。 首先,您可以使用Mapbox GL JS库来创建室内地图。Mapbox GL JS是一个开源的JavaScript库,它可以帮助您创建交互式、高性能的地图应用程序。此外,Mapbox还提供了丰富的地图数据和API,可以帮助您快速构建地图应用。 其次,您可以使用Three.js库来创建3D模型和动画。Three.js是一个轻量级的JavaScript库,它可以帮助您在网页上呈现3D图形和动画。您可以使用Three.js来创建室内景和模型,然后将其集成到Mapbox GL JS地图中。 下面是一些具体的步骤和参考资料: 1. 创建Mapbox GL JS地图:您可以参考Mapbox官方文档来学习如何创建Mapbox GL JS地图。文档链接:https://docs.mapbox.com/mapbox-gl-js/api/ 2. 创建Three.js景和模型:您可以使用Three.js来创建室内景和模型。首先,您需要创建一个Three.js景,然后向其中添加模型和光源。您可以参考Three.js官方文档来学习如何创建景和模型。文档链接:https://threejs.org/docs/index.html#manual/en/introduction/Creating-a-scene 3. 将Three.js景和模型集成到Mapbox GL JS地图中:您可以使用Mapbox GL JS的自定义图层功能来将Three.js景和模型集成到地图中。首先,您需要创建一个自定义图层,并在其中嵌入Three.js景。然后,您可以使用Mapbox GL JS的渲染回调函数来更新景和模型。您可以参考Mapbox GL JS官方文档来学习如何创建自定义图层。文档链接:https://docs.mapbox.com/mapbox-gl-js/example/custom-style-layer/ 4. 其他参考资料:以下链接提供了一些关于Mapbox GL JSThree.js集成的示例和教程,您可以参考它们来学习如何使用这些库来创建室内地图。 - Mapbox GL JS + Three.js 实现室内地图:https://zhuanlan.zhihu.com/p/157280541 - Threebox:一个将Three.js集成到Mapbox GL JS的库:https://github.com/jscastro76/threebox - 在Mapbox GL JS使用Three.js来创建3D建筑物:https://blog.mapbox.com/using-three-js-to-build-complex-3d-buildings-in-mapbox-gl-js-8e7d3c444f4c 希望这些信息能够帮助到您!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值