PHP 快递地图模式,使用D3.js创建物流地图的步奏详解

这次给大家带来使用D3.js创建物流地图的步奏详解,使用D3.js创建物流地图的注意事项有哪些,下面就是实战案例,一起来看一下。

制作思路需要绘制一张中国地图,做为背景。

需要主要城市的经纬坐标,以绘制路张起点和终点。

接收到物流单的城市,绘制一个闪烁的标记。

已经有过物流单的目标城市,不再绘制路线。

每次新产生一笔物流单,都有一个标记沿路线移向目标的动画效果。

绘制结束后的数据,需要清理掉,以减少对浏览器的资源占用。

开始撸码

1.创建网页模板

加载D3JS,为了方便调试,直接下载d3.js文件在本地,实际使用的时候,可以换成加载路径。注意,使用的是V4版的D3,和V3版有差异。

创建一个p块,准备绘图。

地图

创建SVG,以下所有代码放在中var width=1000 , height=800; // 定义SVG宽高

var svg = d3.select("body p.fxmap")

.append("svg")

.attr("width", "width)

.attr("height", height)

.style("background","#000"); //

创建SVG图形分组,以备调用gmp,保存背景地图和起点标记。

mline,保存起点和目标之间的连线,以及目标点。

buttion,测试用的按钮gmap = svg.append("g").attr("id", "map").attr("stroke", "white").attr("stroke-width",1);

mline = svg.append("g").attr("id", "moveto").attr("stroke", "#FFF").attr("stroke-width", 1.5).attr("fill","#FFF");

button = svg.append("g").attr("id", "button").attr("stroke", "white").attr("stroke-width", 1).attr("fill", "white");

创建投影函数经纬度不能直接用来绘图,需要转换成平面坐标。d3js提供了比较丰富的投影方法,本例中使用了geoEquirectangular()方法。

projection 是将经纬度转换为平面坐标的方法

path 是将经纬度转换为连线绘制点坐标的方法(省得自己再写函数构造path路径)var projection = d3.geoEquirectangular()

.center([465,395]) // 指定投影中心,注意[]中的是经纬度

.scale(height)

.translate([width / 2, height / 2]);

var path = d3.geoPath().projection(projection);

创建marker标记,以便多个连线终点调用由于会有多个物流连线的终点,所以都放在一个marker标记中调用。

这个标记是由中间的 圆形 + 外圈 构成。外圈的闪烁效果另外创建。marker = svg.append("defs")

.append("marker")

.append("marker")

.attr("id", "pointer")

.attr("viewBox","0 0 12 12") // 可见范围

.attr("markerWidth","12") // 标记宽度

.attr("markerHeight","12") // 标记高度

.attr("orient", "auto") //

.attr("markerUnits", "strokeWidth") // 随连接线宽度进行缩放

.attr("refX", "6") // 连接点坐标

.attr("refY", "6")

// 绘制标记中心圆

marker.append("circle")

.attr("cx", "6")

.attr("cy", "6")

.attr("r", "3")

.attr("fill", "white");

// 绘制标记外圆,之后在timer()中添加闪烁效果

marker.append("circle")

.attr("id", "markerC")

.attr("cx", "6")

.attr("cy", "6")

.attr("r", "5")

.attr("fill-opacity", "0")

.attr("stroke-width", "1")

.attr("stroke", "white");

绘制中国地图,并标记起点(长沙)

地图使用的经纬集为china.json,这个文件网上有很多// 记录长沙坐标

var changsha = projection([112.59,28.12]);

// 读取地图数据,并绘制中国地图

mapdata = [];

d3.json('china.json', function(error, data){

if (error)

console.log(error);

// 读取地图数据

mapdata = data.features;

// 绘制地图

gmap.selectAll("path")

.data(mapdata)

.enter()

.append("path")

.attr("d", path);

// 标记长沙

gmap.append("circle").attr("id","changsha")

.attr("cx", changsha[0])

.attr("cy", changsha[1])

.attr("r", "6")

.attr("fill", "yellow")

gmap.append("circle").attr("id","changshaC")

.attr("cx", changsha[0])

.attr("cy", changsha[1])

.attr("r", "10")

.attr("stroke-width", "2")

.attr("fill-opacity", "0");

});

创建方法,绘制一条从指定起点到终点的连线,并在络点绘制marker标记。方法需要输入终点城市名称(city)和经纬度(data)

调用之前建立的project()方法,将终点经纬度转换为平面坐标。

计算起点(长沙)和终点之前的距离,做为线条长度和动画时间参数。

在线条上绘制一个圆形标记,并实现从起点到终点的移动动画

标记移动到终点后,即删除,节省资源。

如果线点在之前已经绘制过,则不绘线条,只绘制移动标记。

每处理一次物流单,则城市记录+1。// 创建对象,保存每个城市的物流记录数量

var citylist = new Object();

// 创建方法,输入data坐标,绘制发射线

var moveto = function(city, data){

var pf = {x:projection([112.59,28.12])[0], y:projection([112.59,28.12])[1]};

var pt = {x:projection(data)[0], y:projection(data)[1]};

var distance = Math.sqrt((pt.x - pf.x)**2 + (pt.y - pf.y)**2);

if (city in citylist){

citylist[city]++;

}else{

mline.append("line")

.attr("x1", pf.x)

.attr("y1", pf.y)

.attr("x2", pt.x)

.attr("y2", pt.y)

.attr("marker-end","url(#pointer)")

.style("stroke-dasharray", " "+distance+", "+distance+" ")

.transition()

.duration(distance*30)

.styleTween("stroke-dashoffset", function(){

return d3.interpolateNumber(distance, 0);

});

citylist[city] = 1;

};

mline.append("circle")

.attr("cx", pf.x)

.attr("cy", pf.y)

.attr("r", 3)

.transition()

.duration(distance*30)

.attr("transform", "translate("+(pt.x-pf.x)+","+(pt.y-pf.y)+")")

.remove();

};

创建动画队例,实现标记外圈的闪烁效果var scale = d3.scaleLinear();

scale.domain([0, 1000, 2000])

.range([0, 1, 0]);

var start = Date.now();

d3.timer(function(){

var s1 = scale((Date.now() - start)%2000);

// console.log(s1);

gmap.select("circle#changshaC")

.attr("stroke-opacity", s1);

marker.select("circle#markerC")

.attr("stroke-opacity", s1);

});

创建测试按钮和测试的目标城市数据var cityordinate = {

'哈尔滨':[126.5416150000,45.8088260000],

'石家庄':[116.46,39.92],

'北京':[116.39564503787867,39.92998577808024],

'上海':[121.480539,31.235929],

'广州':[113.271431,23.135336],

'重庆':[106.558434,29.568996],

'青岛':[120.38442818368189,36.10521490127382],

'福州':[119.30347,26.080429],

'兰州':[103.840521,36.067235],

'贵阳':[106.636577,26.653325],

'成都':[104.081534,30.655822],

'西安':[108.946466,34.347269],

'长春':[125.3306020000,43.8219540000],

'台湾':[120.961454,23.80406],

'呼和浩特':[111.7555090000,40.8484230000],

'澳门':[113.5494640000,22.1929190000],

'武汉':[114.3115820000,30.5984670000],

'昆明':[102.71460113878045,25.049153100453159],

'乌鲁木齐':[87.56498774111579,43.84038034721766],

'益阳':[112.36654664522563,28.58808777988717],

'南京':[118.77807440802562,32.05723550180587],

'武昌':[114.35362228468498,30.56486029278519],

};

// 随机获得目标城市

var cityname = [], total = 0;

for (var key in cityordinate){

cityname[total++] = key;

};

// 创建操作按钮,每次点击发射一条物流线

button.append("circle")

.attr("cx", width*0.9)

.attr("cy", height*0.8)

.attr("r", width/20)

.attr("text","click")

.attr("fill", "grey");

button.append("text")

.attr("x", width*0.87)

.attr("y", height*0.81)

.style("font-size", "30px")

.text("click");

button.on("click", function(){

var _index = ~~(Math.random() * total);

moveto(cityname[_index], cityordinate[cityname[_index]]);

});

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值