时光荏苒、转瞬即逝,国家富强使得人们迈入幸福的新生活,随着时代的发展,人们对于事物的处理方式也发生了改变,从书信交流到如今视频通话,人们日常生活中的交流方式也发生了改变,尤其是人们对于图像的接受能力远远大于文字,很多时候,几十上百字的归纳说明还没有一张图给人带来的直观,这种将文字变成表格,表格变成图表的过程却并不算漫长,随着互联网的蓬勃生长、对于千万条乃至数百亿条数据的处理之后,如何让管理者更加直观便捷的查看出大数据下隐藏的信息,这就不仅仅是文字能够表述的清楚,或者这样说,在如今这个时代,任何可以被节约下来的时间都不能去浪费,以至于表格逐渐代替了文字账本,在互联网中使用图表来展示数据也逐渐成为了主流趋势,当我们把目光放向物联网时,其实也是这样,随着互联网的壮大,物联网也在迅速崛起,而物联网可视化的万物可视也成为了当前的一大需求,将三维实景与数据结合起来也成为了可视化的一大亮点。
物联网可视化是什么?可视化号称是物联网的最后一公里,那么,为什么会有这样的言论?物联网可视化通过3D实景模型,结合了各种传感技术、以互联网来传递数据,并且将数据传入到可视化应用中,变化成可直观查看的图表,如温度云图、信息报警、安防监控等等,将一系列的零散功能结合在一起,形成一个完整的可视化应用。这样不仅仅能够使用可视化应用来实现实时控制的功能,还能够让任何人员都能够看懂,并且还是非常直观、非常清晰的看懂,物联网可视化应用,不仅能完成使用者需要的功能,更是在此基础之上,强化了其“可视化”的能力,让使用者一览无“疑”。
在物联网可视化领域,如何将图表数据与三维场景进行交互呢?
使用ThingJS在线开发即可快速使用Echarts图表结合三维场景!进入到ThingJS网站的在线开发中去(https://www.thingjs.com/guide/?m=sample),使用QQ或者微信快速登录,找到官方示例中的界面(2D),点击“Echarts + 交互”,出现对应代码后点击运行(三角形图标),可以查看到图表和三维场景进行交互了,但是这四个图表都不是我想要的,我该如何去修改呢?
别急,慢慢看下来,你会发现,修改图表非常的简单!
如何修改图表样式?
如何使用Echarts的图表替换掉我们的图表?其实非常的简单,进入到Echarts官网,点击实例,选择其中的例子,将该例子中的代码复制出来,修改其中的数据,后期结合可以通过Ajax获取参数来动态的修改我们图表中的数据。(这一章节我们主要讲解如何修改图表,将图表与三维场景相结合)将数据放入到ThingJS的代码中去,具体位置是找到ThingJS要被替换的图表,将“XXXOption"或者是“Option”中的数据全部替换掉。完成后可以点击保存并且运行,查看是否修改成功。注意:最好是将“XXXOption"的名字保留,仅改变“XXXOption"后面的数据,或者将“XXXOption"改成你想要的变量名,那么在调用“XXXOption"的位置,也需要全部替换掉。
新加入的Echarts实例的代码如下:
// 车位占用情况 function occupyPark() { var colors = ['#5793f3', '#d14a61', '#675bba']; var occupyOption = { color: colors, tooltip: { trigger: 'none', axisPointer: { type: 'cross' } }, legend: { data: ['十月车位使用数', '十一月车位使用数'] }, grid: { top: 70, bottom: 50 }, xAxis: [ { type: 'category', axisTick: { alignWithLabel: true }, axisLine: { onZero: false, lineStyle: { color: colors[1] } }, axisPointer: { label: { formatter: function (params) { return '使用数 ' + params.value + (params.seriesData.length ? ':' + params.seriesData[0].data : ''); } } }, data: ["6:00", "7:00", "8:00", "9:00", "10:00", "11:00", "12:00", "13:00", "14:00", "15:00", "16:00", "17:00"] }, { type: 'category', axisTick: { alignWithLabel: true }, axisLine: { onZero: false, lineStyle: { color: colors[0] } }, axisPointer: { label: { formatter: function (params) { return '使用数 ' + params.value + (params.seriesData.length ? ':' + params.seriesData[0].data : ''); } } }, data: ["6:00", "7:00", "8:00", "9:00", "10:00", "11:00", "12:00", "13:00", "14:00", "15:00", "16:00", "17:00"] } ], yAxis: [ { type: 'value' } ], series: [ { name: '十月车位使用数', type: 'line', xAxisIndex: 1, smooth: true, data: [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3] }, { name: '十一月车位使用数', type: 'line', smooth: true, data: [3.9, 5.9, 11.1, 18.7, 48.3, 69.2, 231.6, 46.6, 55.4, 18.4, 10.3, 0.7] } ] };
在这里我将完整的代码贴出,大家可以复制该代码进入到ThingJS的在线开发平台中运行查看
/** * 说明:ECharts 整合例子 * 操作:点击图表,触发场景信息变化 * 交互图表:当前车位状态、车牌信息、车辆类型 * 难度:★★★☆☆ */ // 动态引入ECharts.js THING.Utils.dynamicLoad(['lib/echarts.min.js'], function () { /* *var app = new THING.App()一直作为ThingJS的启动来使用的,其中有url等信息需要填写 *url则是制作好的场景上传到ThingJS网站后的链接 */ var app = new THING.App({ url: 'https://www.thingjs.com/./client/ThingJS/10321/20190715145918010908508', // 场景地址 "skyBox": "Night" }); /** * app.on("load",function) 作为全局绑定事件,绑的的方法就是'load' 方法 */ app.on('load', function (ev) { showParkingInfo();// 车位信息 showTypeInfo();// 车辆类型信息 showLicenseInfo();// 车牌信息 occupyPark();// 车位占用 }) var timer = null; // 创建图表 function createChart(option, type) { var bottomBackground = document.createElement('div');// 创建背景 div var bottomDom = document.createElement('div');// 图表 div // 设置背景div和图表div的样式 if (type == "车位状态") { var backgroundStyle = 'position: absolute;top:3px;right:3px;height:300px;width:380px;background: rgba(22,24,63,0.3); border-radius:3px'; var chartsStyle = 'position: absolute;top:10px;right:0px;width:360px;height:250px;margin:0 10px;'; } else if (type == "车牌信息") { var backgroundStyle = 'position: absolute;top:306px;right:3px;height:300px;width:380px;background: rgba(22,24,63,0.3); border-radius:3px'; var chartsStyle = 'position: absolute;top:10px;right:0px;width:360px;height:300px;margin:0 10px;'; } else if (type == "车位占用情况") { var backgroundStyle = 'position: absolute;top:3px;left:3px;height:300px;width:380px;background: rgba(22,24,63,0.3); border-radius:3px'; var chartsStyle = 'position: absolute;top:10px;right:0px;width:360px;height:300px;margin:0 10px;'; } else if (type == "车辆类型") { var backgroundStyle = 'position: absolute;top:306px;left:3px;height:300px;width:380px;background: rgba(22,24,63,0.3); border-radius:3px'; var chartsStyle = 'position: absolute;top:10px;right:0px;width:360px;height:300px;margin:0 10px;'; } bottomBackground.setAttribute('style', backgroundStyle); bottomDom.setAttribute('style', chartsStyle); // echarts 初始化 var bottomCharts = window.echarts.init(bottomDom); bottomCharts.setOption(option); // 给图表添加'click'事件 当点击图图表时触发,params是点击位置信息参数 bottomCharts.on('click', function (params) { clearTimeout(timer); // 清除上次点击事件产生的场景变化 cancelOutline(); reset(); clearUIAnchorArr(); // 根据鼠标点击时的参数,控制场景中物体变化 if (params.name == "空置车位") { app.query("空置车位").style.outlineColor = "#4a8cff" } else if (params.name == "占用车位") { app.query("占用车位").style.outlineColor = "#ff6c00" } else if (params.name.indexOf("车") != -1) { var reg = new RegExp(params.name); var cars = app.query(reg); flash(cars); } else if (params.name == "京") { var cars = app.query('[area=京]'); for (var i = 0; i < cars.length; i++) { createUIAnchor(cars[i]); } } else if (params.name == "津") { var cars = app.query('[area=津]'); for (var i = 0; i < cars.length; i++) { createUIAnchor(cars[i]); } } else if (params.name == "冀") { var cars = app.query('[area=冀]'); for (var i = 0; i < cars.length; i++) { createUIAnchor(cars[i]); } } else if (params.name == "辽") { var cars = app.query('[area=辽]'); for (var i = 0; i < cars.length; i++) { createUIAnchor(cars[i]); } } // 场景中信息显示5s后消失 timer = setTimeout(function () { cancelOutline(); reset(); clearUIAnchorArr(); }, 5000) }); bottomBackground.appendChild(bottomDom); app.domElement.appendChild(bottomBackground);// 添加到app dom下 } // 取消所有物体钩边 function cancelOutline() { app.query(".Thing").style.outlineColor = null; } // 设置闪烁 function flash(cars) { cars.on('update', function (ev) { ev.object.style.opacity = 0.5 + 0.5 * Math.sin(2 * app.elapsedTime / 200); }, '每帧改变透明度'); } // 恢复设置 function reset() { var cars = app.query(/车/); cars.style.opacity = 1.0; cars.style.color = null; cars.off('update', null, '每帧改变透明度'); } // 存储所有UIAnchor var uiAnchorArr = []; // 创建UIAnchor function createUIAnchor(obj) { // 创建widget (绑定数据用) var panel = new THING.widget.Panel({ width: '100px', cornerType: 'polyline' }) panel.addString(obj.userData, 'id').caption(''); var uiAnchor = app.create({ type: 'UIAnchor', parent: obj, element: panel.domElement, localPosition: [0, 0, 0], pivot: [-0.1, 1.5] }); uiAnchorArr.push(uiAnchor); return uiAnchor; } // 删除所有顶牌 function clearUIAnchorArr() { for (var i = 0; i < uiAnchorArr.length; i++) { uiAnchorArr[i].destroy(); } uiAnchorArr = []; } // 当前停车位状态 function showParkingInfo() { var parkingTotalNum = 16; var emptyNum = 3; //parkOption数据可以使用Echarts中的示例数据进行替换,只需更改其中的数据信息即可 var parkOption = { title: { text: '当前车位状态', x: 'center', textStyle: { color: '#cccccc' } }, tooltip: { trigger: 'item', formatter: "{a} {b} : {c} ({d}%)" }, legend: { orient: 'vertical', top: 60, x: 'left', data: ['占用车位', '空置车位'], textStyle: { color: '#cccccc' } }, calculable: true, series: [ { name: '车位', type: 'pie', radius: '55%', center: ['50%', '60%'], data: [ { value: parkingTotalNum - emptyNum, name: '占用车位', itemStyle: { color: "#ff6c00" } }, { value: emptyNum, name: '空置车位', itemStyle: { color: "#4a8cff" } } ] } ] }; createChart(parkOption, "车位状态"); } // 车辆类型 function showTypeInfo() { var dataAxis = ["跑车", "轿车", "皮卡车", "面包车", "出租车"]; var data = [3, 6, 1, 1, 2]; var yMax = 7; var dataShadow = []; for (var i = 0; i < data.length; i++) { dataShadow.push(yMax); } var typeOption = { title: { text: '车辆类型', x: 'center', textStyle: { color: '#cccccc' } }, xAxis: { data: dataAxis, axisLabel: { inside: true, textStyle: { color: '#fff' } }, axisTick: { show: false }, axisLine: { show: false }, z: 10 }, yAxis: { axisLine: { show: false }, axisTick: { show: false }, axisLabel: { textStyle: { color: '#ccc' } } }, dataZoom: [ { type: 'inside' } ], series: [ { // For shadow type: 'bar', itemStyle: { normal: { color: 'rgba(0,0,0,0.05)' } }, barGap: '-100%', barCategoryGap: '40%', data: dataShadow, animation: false }, { type: 'bar', itemStyle: { normal: { color: new echarts.graphic.LinearGradient( 0, 0, 0, 1, [ { offset: 0, color: '#83bff6' }, { offset: 0.5, color: '#188df0' }, { offset: 1, color: '#188df0' } ] ) }, emphasis: { color: new echarts.graphic.LinearGradient( 0, 0, 0, 1, [ { offset: 0, color: '#2378f7' }, { offset: 0.7, color: '#2378f7' }, { offset: 1, color: '#83bff6' } ] ) } }, data: data } ] }; createChart(typeOption, "车辆类型"); } // 显示车牌信息 function showLicenseInfo() { var len_jing = app.query('[area=京]').length; var len_jin = app.query('[area=津]').length; var len_ji = app.query('[area=冀]').length; var len_liao = app.query('[area=辽]').length; var licenseOption = { title: { text: '车牌信息', x: 'center', textStyle: { color: '#cccccc' } }, tooltip: { trigger: 'item', formatter: "{a} {b}: {c} ({d}%)" }, legend: { orient: 'vertical', x: 'left', data: ['京', '津', '冀', '辽'], textStyle: { color: '#cccccc' } }, series: [ { name: '牌照', type: 'pie', radius: ['50%', '70%'], avoidLabelOverlap: false, label: { normal: { show: false, position: 'center' }, emphasis: { show: true, textStyle: { fontSize: '30', fontWeight: 'bold' } } }, labelLine: { normal: { show: false } }, data: [ { value: len_jing, name: '京' }, { value: len_jin, name: '津' }, { value: len_ji, name: '冀' }, { value: len_liao, name: '辽' }, ] } ] }; createChart(licenseOption, "车牌信息"); } // 车位占用情况 function occupyPark() { var colors = ['#5793f3', '#d14a61', '#675bba']; var occupyOption = { color: colors, tooltip: { trigger: 'none', axisPointer: { type: 'cross' } }, legend: { data: ['十月车位使用数', '十一月车位使用数'] }, grid: { top: 70, bottom: 50 }, xAxis: [ { type: 'category', axisTick: { alignWithLabel: true }, axisLine: { onZero: false, lineStyle: { color: colors[1] } }, axisPointer: { label: { formatter: function (params) { return '使用数 ' + params.value + (params.seriesData.length ? ':' + params.seriesData[0].data : ''); } } }, data: ["6:00", "7:00", "8:00", "9:00", "10:00", "11:00", "12:00", "13:00", "14:00", "15:00", "16:00", "17:00"] }, { type: 'category', axisTick: { alignWithLabel: true }, axisLine: { onZero: false, lineStyle: { color: colors[0] } }, axisPointer: { label: { formatter: function (params) { return '使用数 ' + params.value + (params.seriesData.length ? ':' + params.seriesData[0].data : ''); } } }, data: ["6:00", "7:00", "8:00", "9:00", "10:00", "11:00", "12:00", "13:00", "14:00", "15:00", "16:00", "17:00"] } ], yAxis: [ { type: 'value' } ], series: [ { name: '十月车位使用数', type: 'line', xAxisIndex: 1, smooth: true, data: [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3] }, { name: '十一月车位使用数', type: 'line', smooth: true, data: [3.9, 5.9, 11.1, 18.7, 48.3, 69.2, 231.6, 46.6, 55.4, 18.4, 10.3, 0.7] } ] }; createChart(occupyOption, "车位占用情况"); } })