导语

大数据呈现应用越来越广泛,支持大数据呈现的SDK,水平较高的有echarts、highchart、D3;然而在地图呈现的功能上,大都只能绘制矢量地图,而不能呈现具有真实效果的地图;鉴于此,本文重点在于如何制作一张,即可以看到真实效果,又能进行交互的矢量地图;

先睹为快

若有所思

技术选择

想实现上述效果,最先想到的SDK是TWaver,思路也非常的简单;

  1. 使用Node呈现一张地图背景图片,像素越大越好,缩放效果好;

  2. 使用ShapeNode加载地图数据,并设置好位置、缩放比例等因素,恰好与地图重叠;
    3.控制地图的Layer为底层,不可选中;ShapeNode为上层,可交互;

iChart & ZRender

本文使用ichart + zrender技术,绘制上述的效果;

为什么使用zrender呢?实际上zrender的功能比较简单,用于绘制基本的形状;其实细心的你会发现,echarts的底层就是使用了zrender;

有为什么使用ichart呢?ichart用于绘制常用的图表,底层基于Canvas绘制,也比较容易改造;而echarts使用的是SVG,修改起来就没那么容易啦!

实验天地

目标一:实现柱单节状图效果

实现柱状图效果,还真没那么容易!ichart不支持怎么办? 定制!
找到ichart的柱状图类:Cylinder.js,好就从改造他开始了!

找到绘制网元的方法buildPath

Cylinder.prototype = {type: 'cylinder',/*** 创建圆形路径* @param {CanvasRenderingContext2D} ctx* @param {module:zrender/shape/Cylinder~ICircleStyle} style*/buildPath : function (ctx, style) {//拿到你的画笔,我就随便画啦}
}

如上所言,获取了Canvas的画笔,自由的绘制一个矩形,上下各一个椭圆,不就完事了?

this.ellipse(ctx, style.x, style.y, style.a, style.b);
ctx.fillRect(style.x - style.a, style.y - a, style.a * 2 , d);
this.ellipse(ctx, style.x, style.y - a, style.a, style.b);

封装完毕,打包,混淆,加上测试代码,看效果;

<!DOCTYPE html>
<html>
<head><meta charset="utf-8" /><title>Cylinder</title><script type="text/javascript" src="../doc/asset/js/esl/esl.js"></script>
</head>
<body><script type="text/javascript">var fileLocation = '../build/zrender';require.config({paths:{ zrender: fileLocation,'zrender/shape/Circle': fileLocation,'zrender/shape/Cylinder': fileLocation,}});require(["zrender", 'zrender/shape/Circle','zrender/shape/Cylinder'], function(zrender,CircleShape,CylinderShape){var zr = zrender.init( document.getElementById("Main") );var shape = new CylinderShape({style: {x: 300,y: 300,a: 10,b: 5,height:200,brushType: 'both',color: 'orange',strokeColor: 'red',lineWidth: 1,text: 'Cylinder'},highlightStyle:{color: 'orange',strokeColor: 'red',lineWidth: 2,text: 'Cylinder'},draggable : true,hoverable:true,clickable:true,});zr.addShape(shape);})
</script>
<div id="Main" style="width:1000px;height:600px;"></div>
</body>
</html>

目标二:实现柱多节柱状图效果

问题来了,如果想实现多段的柱状图,如何是好呢?我想您自己都已经有思路了;多画几段不就完事了吗?

buildPath : function (ctx, style) {var rect = this.getRect(style);// ctx.strokeRect(rect.x,rect.y,rect.width,rect.height);// Better stroking in ShapeBundle// ctx.moveTo(style.x + style.a, style.y - style.height/2);// ctx.arc(style.x, style.y, style.r, 0, Math.PI * 2, true);// ctx.arc(style.x, style.y, style.a, 0, Math.PI * 2, true);// this.endDraw(style,ctx);var data = style.data, color = style.color, isPercent = style.isPercent || false, maxHeight = style.maxHeight || 100;if(isPercent) {if(data instanceof Array) {var data2 = [];var all = 0;for(var i = 0;i<data.length; i++) {all += data[i];}for(var i = 0;i<data.length; i++) {data2.push(maxHeight * data[i]/all);}data = data2;}}if(data instanceof Array){ctx.fillStyle = 'black';ctx.shadowBlur=15;ctx.shadowColor="black";ctx.strokeStyle = 'rgba(0,0,0,0.1)';ctx.lineWidth = 1;this.ellipse(ctx, style.x, style.y+1, style.a, style.b);ctx.fill();ctx.shadowBlur=0;ctx.lineWidth = 1;this.ellipse(ctx, style.x, style.y, style.a, style.b);var a = 0;for(var i = 0;i < data.length;i++){var d = data[i];if(color instanceof Array){ctx.fillStyle = color[i];ctx.strokeStyle = color[i];}this.endDraw(style,ctx);a += d;ctx.fillRect(style.x - style.a, style.y - a, style.a * 2 , d);this.ellipse(ctx, style.x, style.y - a, style.a, style.b);if(color instanceof Array){ctx.fillStyle = color[i];ctx.strokeStyle = color[i];}this.endDraw(style,ctx);}}else{this.ellipse(ctx, style.x, style.y + style.height/2, style.a, style.b);this.endDraw(style,ctx);ctx.fillRect(style.x - style.a, style.y - style.height/2, style.a * 2 , style.height);// ctx.strokeRect(style.x - style.a, style.y - style.height/2, style.a * 2 , style.height);this.ellipse(ctx, style.x, style.y - style.height/2, style.a, style.b);this.endDraw(style,ctx);ctx.moveTo(style.x - style.a, style.y - style.height/2);ctx.lineTo(style.x - style.a,style.y + style.height/2);ctx.fill();ctx.moveTo(style.x + style.a, style.y - style.height/2);ctx.lineTo(style.x + style.a,style.y + style.height/2);ctx.fill();}// ctx.strokeRect(style.x - style.a, style.y - style.height/2, style.lineWidth , style.height);// ctx.strokeRect(style.x + style.a, style.y - style.height/2, style.lineWidth , style.height);// this.ellipse(ctx, style.x, style.y+100, style.r, style.r/3);return;}

目标三:绘制地图

使用zrender的PolygonShape绘制矢量地图;但是前提是,和底图图片完全吻合的数据哪里来呢?

聪明的我想到了使用TWaver自带编辑器,完美扣除地图数据;得到结果,形如如下数据格式:

< px="1209.5549397107488" y="1242.081312831646"/>
< px="1209.5549397107488" y="1233.5993604641965"/>
< px="1179.8681064246748" y="1212.3944795455723"/>
< px="1184.1090826083996" y="1199.6715509943976"/>
< px="1171.3861540572252" y="1161.502765340874"/>
< px="1162.9042016897754" y="1157.2617891571492"/>

稍微加工处理下,得到如下数据:

{"type": "Feature","properties":{"id":"65","size":"550","name":"新疆","cp":[471.08525328117855,-97.6746544555845],"childNum":18},"geometry":{"type":"Polygon","coordinates":[[[1143.6222085570992,-80.96566177792188],[1131.0904640488523,-76.78841360850622],[1131.0904640488523,-93.49740628616884],[1126.9132158794366,-135.26988798032542],

开始加入数据,创建矢量地图;

var smoothLine = new PolylineShape({style : {pointList : points,smooth : 'spline',brushType : 'stroke',color : 'white',strokeColor : "white",lineWidth : 2,lineType : 'dotted'},zlevel:1,draggable : true,});zr.addShape(smoothLine);

最后附上完整代码:

<!DOCTYPE html>
<html>
<head><title></title><meta charset="utf-8"><style type="text/css">#bg{  z-index:1;  width:1300px;  height:700px;  position:absolute;  background-color: black,}  #chart{  z-index:2;  width:280px;  height:150px;  position:absolute;  -moz-border-radius: 15px; -webkit-border-radius: 15px; border-radius:15px;       }  </style>
</head>
<body><div id="bg" ></div><div id="chart" ></div><script type="text/javascript" src="esl.js"></script><script type="text/javascript" src="jquery.js"></script><script type="text/javascript" src="echarts-all.js"></script><script>var fileLocation = 'zrender';require.config({paths:{ zrender: fileLocation,'zrender/shape/Image': fileLocation,'zrender/shape/Polygon': fileLocation,'zrender/shape/Polyline': fileLocation,'zrender/shape/Circle': fileLocation,'zrender/shape/Cylinder': fileLocation,'zrender/shape/Text': fileLocation,}});var myChart = echarts.init(document.getElementById('chart'));$.getJSON('china.json', function(json, textStatus) {require(["zrender", 'zrender/shape/Image','zrender/shape/Polygon', "zrender/shape/Polyline",'zrender/shape/Circle','zrender/shape/Cylinder','zrender/shape/Text'], function(zrender, ImageShape,PolygonShape,PolylineShape,CircleShape, CylinderShape,TextShape){zr = zrender.init( document.getElementById("bg"));var config = require('zrender/config');zr.on(config.EVENT.CLICK,function(params) {if (!params.target) {$('#chart').css('z-index',-1);myChart.clear();}});zr.modLayer(0,{zoomable:true,panable:true,clearColor:'#cdcdcd',position:[160,50],rotation:[0,0],scale:[0.25,0.25],});zr.modLayer(1,{zoomable:true,panable:true,clearColor:'rgba(0,0,0,0)',position:[205.5,240.5],rotation:[0,0],scale:[0.25,0.25],});var image = new ImageShape({position : [0, 0],scale : [1, 1],style : {x : 0,y : 0,image : "bg_china3.png",},draggable : false,clickable: false,hoverable:false,zlevel:0,});zr.addShape( image );json.features.forEach(function (feature) {var points = [];if (feature.geometry.type === 'MultiPolygon') {feature.geometry.coordinates.forEach(function (polygon) {polygon.forEach(function (coordinate) {coordinate.forEach(function (point, i) {points.push(convertPoint(point));});});});} else if (feature.geometry.type === 'Polygon') {feature.geometry.coordinates.forEach(function (coordinate) {coordinate.forEach(function (point, i) {points.push(convertPoint(point));});});} else {console.log(feature.geometry.type);}var smoothLine = new PolylineShape({style : {pointList : points,smooth : 'spline',brushType : 'stroke',color : 'white',strokeColor : "white",lineWidth : 2,lineType : 'dotted'},zlevel:1,draggable : true,});zr.addShape(smoothLine);zr.addShape(new PolygonShape({style : {pointList : points,lineCape:'butt',// text:feature.properties.name,// textPosition:'inside',// textPosition:'inside',//'inside','top','bottom','left','right': // textColor:'black',// textAlign:'start',//// textBaseline:'hanging',//'hanging'// textFont:'bold 32px verdana',// smooth : 0.5,// smoothConstraint: [[-Infinity, -Infinity], [200, Infinity]],brushType : 'both',color : (feature.properties.name === '澳门' || feature.properties.name === '香港') ? '#578096' : 'rgba(220, 20, 60, 0)',strokeColor : "white",lineWidth : 1,},highlightStyle:{// strokeColor:'white',},draggable : true,zlevel:1,}));var cp = feature.properties.cp;zr.addShape(new TextShape({style: {text: feature.properties.name,x: cp[0],y: cp[1] + 30,textFont: 'bold 32px verdana',textColor:'black',},draggable : false,zlevel:1,}));// var color = ['#C1232B','#C46924','#FCCE10'];var color = ['#be1e20','#ff4e00','#ff8400','#ffce00','#c0b900','#94d600','#63ccca','#00a8e6','#005db9','#ac3c73','#853376'];var data = [Math.random() * 100,Math.random() * 100,Math.random() * 100];var shape = new CylinderShape({style: {x: cp[0],y: cp[1],a: 20,b: 10,brushType: 'both',color: color,data:data,strokeColor: color,lineWidth: 1,text: "流入" || feature.properties.name,textFont:'bold 32px verdana',},highlightStyle:{color: color,strokeColor: color,lineWidth: 2,text: '流入' || feature.properties.name,textFont:'bold 32px verdana',},hoverable:false,clickable:true,draggable: false,zlevel:1,onmousedown: function(e){if(e.event.detail == 2){option = {backgroundColor:'rgba(31,34,37,0.8)',title : {text:feature.properties.name +'(流入)',x:'left',textStyle:{color:'white',}},tooltip : {trigger: 'item',formatter: "{a} <br/>{b} : {c} ({d}%)"},color:['#be1e20','#ff4e00','#ff8400','#ffce00','#c0b900','#94d600','#63ccca','#00a8e6','#005db9','#ac3c73','#853376'],series : [{name:'北京人口',type:'pie',radius : '40%',center: ['50%', '60%'],data:[{value:100, name:'第一类人' + '(' + (100/2230 * 100).toFixed(0)+'%)'},{value:300, name:'第二类人' + '(' + (200/2230 * 100).toFixed(0)+'%)'},{value:400, name:'第三类人' + '(' + (400/2230 * 100).toFixed(0)+'%)'},{value:400, name:'第四类人' + '(' + (400/2230 * 100).toFixed(0)+'%)'},{value:300, name:'第五类人' + '(' + (300/2230 * 100).toFixed(0)+'%)'},{value:250, name:'第六类人' + '(' + (250/2230 * 100).toFixed(0)+'%)'},{value:200, name:'第七类人' + '(' + (200/2230 * 100).toFixed(0)+'%)'},{value:180, name:'第八类人' + '(' + (180/2230 * 100).toFixed(0)+'%)'},{value:100, name:'第九类人' + '(' + (100/2230 * 100).toFixed(0)+'%)'}]}]};var chartDiv = document.getElementById('chart');chart.style.left = e.event.clientX + 30 + "px";chart.style.top = e.event.clientY - 210/2 + "px";myChart.setOption(option);$('#chart').css('z-index',2);}}});zr.addShape(shape);var color = ['#B5C334','#F4E001','#F0805A'];var data = [Math.random() * 150,Math.random() * 150,Math.random() * 150];var shape = new CylinderShape({style: {x: cp[0] + 50,y: cp[1],a: 20,b: 10,data:data,brushType: 'both',color: color,strokeColor: color,lineWidth: 1,text: '流出'||feature.properties.name,textFont:'bold 32px verdana',},highlightStyle:{color: color,strokeColor: color,lineWidth: 2,text: '流出'||feature.properties.name,textFont:'bold 32px verdana',},hoverable:true,clickable:true,draggable: false,zlevel:1,onmousedown: function(e){if(e.event.detail == 2){option = {backgroundColor:'rgba(31,34,37,0.8)',title : {text:feature.properties.name + '(流出)',x:'left',textStyle:{color:'white',}},tooltip : {trigger: 'item',formatter: "{a} <br/>{b} : {c} ({d}%)"},color:['#be1e20','#ff4e00','#ff8400','#ffce00','#c0b900','#94d600','#63ccca','#00a8e6','#005db9','#ac3c73','#853376'],series : [{type:'pie',radius : '40%',center: ['50%', '60%'],data:[{value:100, name:'第一类人' + '(' + (100/2230 * 100).toFixed(0)+'%)'},{value:300, name:'第二类人' + '(' + (200/2230 * 100).toFixed(0)+'%)'},{value:400, name:'第三类人' + '(' + (400/2230 * 100).toFixed(0)+'%)'},{value:400, name:'第四类人' + '(' + (400/2230 * 100).toFixed(0)+'%)'},{value:300, name:'第五类人' + '(' + (300/2230 * 100).toFixed(0)+'%)'},{value:250, name:'第六类人' + '(' + (250/2230 * 100).toFixed(0)+'%)'},{value:200, name:'第七类人' + '(' + (200/2230 * 100).toFixed(0)+'%)'},{value:180, name:'第八类人' + '(' + (180/2230 * 100).toFixed(0)+'%)'},{value:100, name:'第九类人' + '(' + (100/2230 * 100).toFixed(0)+'%)'}]}]};var chartDiv = document.getElementById('chart');chart.style.left = e.event.clientX + 30 + "px";chart.style.top = e.event.clientY - 210/2 + "px";myChart.setOption(option);$('#chart').css('z-index',2);}}});zr.addShape(shape);});
zr.render();
});
});function randomColor(){return '#'+('00000'+(Math.random()*0x1000000<<0).toString(16)).substr(-6);
}
function convertPoint (point) {return point;
}
</script>
</body>
</html>

iChart--地图显示人口统计相关推荐

  1. Java黑皮书课后题第2章:2.11(人口统计)重写编程练习题1.11,提示用户输入年数,然后显示这个年数之后的人口值,将1.11中的提示用于这个程序

    2.11(人口统计)重写编程练习题1.11,提示用户输入年数,然后显示这个年数之后的人口值,将1.11中的提示用于这个程序 题目 题目描述 运行示例 涉及的1.11代码(非本题代码) 破题 代码块 题 ...

  2. 基于GIS的人口统计数据空间化解决方案

    ​  人口数据一般以各种级别的行政区域为统计单位,使用表格进行展示.常用的人口分布度量指标是人口密度,即行政区域内单位土地面积上的人口数量,这种以行政辖区为单位进行统计的方法,统计的结果是假定人口均匀 ...

  3. Excel聚类分析-人口统计模式下的分群算法

    原创 维希安 (微信公众号:南雨潇湘) 2021-07-27 00:28 收录于合集 #excel18个 #商业模式3个 #聚类分析1个 #算法9个 很多人觉得自己没有编程基础,例如Python,R, ...

  4. 第16章 人口统计

    <人口原理概论>第16章 人口统计 人口统计是人类历史上产生最早.历史最悠久的一种统计,它是适应社会发展和国家管理的需要而产生和发展的.尤其近一个世纪来,随着经济发展和科学技术的进步,人口 ...

  5. 【沃顿商学院学习笔记】宏观经济学——01全球趋势与人口统计Demography

    宏观经济学--一个快速变化的世界 本课主要是从全球政治趋势.全球社会走向进行分析.主要包含对人口.消费市场.劳动力市场.金融市场.地缘政治.自然资源及各国之间的国际关系来进行分析.全球化趋势既是机会也 ...

  6. 6-24 人口统计 (20 分)

    6-24 人口统计 (20 分) 本题运行时要求键盘输入10个人员的信息(每一个人信息包括:姓名,性别,年龄,民族),要求同学实现一个函数,统计民族是"汉族"的人数. 函数接口定义 ...

  7. 6-2 人口统计 (5 分)java

    6-2 人口统计 (5 分) 本题运行时要求键盘输入10个人员的信息(每一个人信息包括:姓名,性别,年龄,民族),要求同学实现一个函数,统计民族是"汉族"的人数. 函数接口定义: ...

  8. 6-2 人口统计 (20 分)

    6-2 人口统计 (20 分) 本题运行时要求键盘输入10个人员的信息(每一个人信息包括:姓名,性别,年龄,民族),要求同学实现一个函数,统计民族是"汉族"的人数. 函数接口定义: ...

  9. 【15】数据可视化:基于 Echarts + Vue 实现的大屏范例 - 世界人口统计大屏

    系列文章 https://blog.csdn.net/lildkdkdkjf/article/details/120705616 文末有免费福利,喜欢的小伙伴们一键三连支持下,关注收藏点赞~   目录 ...

  10. 数字营销:用好大数据,先从“人口统计数据”开始!

    人口统计范围包括年龄.性别.学历.收入.职业.婚姻生育状况.家庭成员和位置等生物特征和社会特征信息.这些信息通常用来识别商业机会和建立商业计划,被搜集,分析并被应用在任何可能有用的地方.在市场营销中, ...

最新文章

  1. redis 缓存过期默认时间_缓存的必知必会:一文搞懂Redis持久化和过期机制
  2. bat常用命令操作符列表
  3. 实验一 绘制金刚石图案
  4. SAP Commerce Cloud 导入消费OCC API需要使用的credentials
  5. C++STL与泛型编程(2) 第一个C++ STL Application
  6. php后端路由,laravel实现前后台路由分离的方法
  7. php fpm 内存增加,不断增加php-fpm的内存使用量?
  8. sql collection内容_非关系数据库复习|SQL到mongoDB查询语句转换
  9. 2021-2027全球与中国抽屉五金市场情况与未来趋势研究报告
  10. iOS使用masonry快速将一组view在superview中等宽排列
  11. 出谋划策 小型网吧组网方案精心推荐(转)
  12. 01炼数成金TensorFlow基本概念
  13. maven Web项目中POM的配置信息
  14. 科技对金融业的告白信,有百融云创的落款
  15. 每日启程——2019.12.15(纸上谈来终觉浅,绝知此事要躬行。)
  16. 第二次实验报告:使用Packet Tracer分析应用层协议
  17. 在元宇宙的概念之下,互联网与数字经济不再是水火不容的存在
  18. VB编写欧姆龙PLC和霍尼韦尔扫描枪 的串口调试程序,可供大家参考
  19. 商城类型app 英文名称
  20. parcelable接口实现

热门文章

  1. 全国大学生软件测试大赛Web应用测试(八)Web众包测试具体流程
  2. 物联网定位技术超全解析
  3. Fastjson blacklist
  4. 地籍测绘成图软件南方cass9.0支持AutoCad2010【安装文件和视频教程】
  5. 机器学习(一) Eviews下载及安装教程
  6. Mac-VMware-分辨率修改
  7. sentinel卫星_关于“哨兵6号”迈克尔弗里利希卫星的五条信息
  8. windows内核——基石
  9. 卫星移动通信系统的分类
  10. kali linux捉肉鸡教程,简单扫4899端口捉肉鸡菜鸟教程详细版