d3.js 地铁轨道交通项目实战

上一章说了如何制作一个线路图,当然上一章是手写的JSON数据,当然手写的json数据有非常多的好处,例如可以应对客户的各种BT需求,但是大多数情况下我们都是使用地铁公司现成的JSON文件,话不多说我们先看一下百度官方线路图。

就是这样的,今天我们就来完成它的大部分需求,以及地铁公司爸爸提出来的需求。

需求如下:

1.按照不同颜色显示地铁各线路,显示对应站点。

2.用户可以点击手势缩放和平移(此项目为安卓开发)。

3.用户在线路menu里点击线路,对应线路平移值屏幕中心并高亮。

4.根据后台数据,渲染问题路段。

5.点击问题路段站点,显示问题详情。

大致需求就是这些,下面看看看代码

1.定义一些常量和变量

const dataset = subwayData; //线路图数据源
let subway = new Subway(dataset); //线路图的类文件
let baseScale = 2; //基础缩放倍率
let deviceScale = 1400 / 2640; //设备与画布宽度比率
let width = 2640; //画布宽
let height = 1760; //画布高
let transX = 1320 + 260; //地图X轴平移(将画布原点X轴平移)
let transY = 580; //地图X轴平移(将画布原点Y轴平移)
let scaleExtent = [0.8, 4]; //缩放倍率限制
let currentScale = 2; //当前缩放值
let currentX = 0; //当前画布X轴平移量
let currentY = 0; //当前画布Y轴平移量
let selected = false; //线路是否被选中(在右上角的线路菜单被选中)
let scaleStep = 0.5; //点击缩放按钮缩放步长默认0.5倍
let tooltip = d3.select('#tooltip'); //提示框
let bugArray = []; //问题路段数组
let svg = d3.select('#sw').append('svg'); //画布
let group = svg.append('g').attr('transform', `translate(${transX}, ${transY}) scale(1)`);//定义组并平移
let whole = group.append('g').attr('class', 'whole-line') //虚拟线路(用于点击右上角响应线路可以定位当视野中心,方法不唯一)
let path = group.append('g').attr('class', 'path'); //定义线路
let point = group.append('g').attr('class', 'point'); //定义站点
const zoom = d3.zoom().scaleExtent(scaleExtent).on("zoom", zoomed); //定义缩放事件

这就是我们需要使用的一些常量和变量。注意transX不是宽度的一半,是因为北京地铁线路网西线更密集。

2.读官方JSON

使用d3.js数据必不可少,然而官方的数据并不通俗易懂,我们先解读一下官方JSON数据。

每条线路对象都有一个l_xmlattr属性和一个p属性,l_xmlattr是整条线路的属性,p是站点数组,我们看一下站点中我们需要的属性。ex是否是中转站,lb是站名,sid是站的id,rx、ry是文字偏移量,st是是否为站点(因为有的点不是站点而是为了渲染贝塞尔曲线用的),x、y是站点坐标。

3.构造自己的类方法

官方给了我们数据,但是并不是我们能直接使用的,所以我们需要构造自己的方法类

class Subway {
 constructor(data) {
  this.data = data;
  this.bugLineArray = [];
 }
 getInvent() {} //获取虚拟线路数据
 getPathArray() {} //获取路径数据
 getPointArray() {} //获取站点数组
 getCurrentPathArray() {} //获取被选中线路的路径数组
 getCurrentPointArray() {} //获取被选中线路的站点数组
 getLineNameArray() {} // 获取线路名称数组
 getBugLineArray() {} //获取问题路段数组
}

下面是我们方法内容,里面的操作不是很优雅(大家将就看啦)

getInvent() {
 let lineArray = [];
 this.data.forEach(d => {
  let { loop, lc, lbx, lby, lb, lid} = d.l_xmlattr;
  let allPoints = d.p.slice(0);
  loop && allPoints.push(allPoints[0]);
  let path = this.formatPath(allPoints, 0, allPoints.length - 1);
  lineArray.push({
   lid: lid,
   path: path,
  })
 })
 return lineArray;
}
getPathArray() {
 let pathArray = [];
 this.data.forEach(d => {
  let { loop, lc, lbx, lby, lb, lid} = d.l_xmlattr;
  let allPoints = d.p.slice(0);
  loop && allPoints.push(allPoints[0])
  let allStations = [];
  allPoints.forEach((item, index) => item.p_xmlattr.st && allStations.push({...item.p_xmlattr, index}))
  let arr = [];
  for(let i = 0; i < allStations.length - 1; i++) {
   let path = this.formatPath(allPoints, allStations[i].index, allStations[i + 1].index);
   arr.push({
    lid: lid,
    id: `${allStations[i].sid}_${allStations[i + 1].sid}`,
    path: path,
    color: lc.replace(/0x/, '#')
   })
  }
  pathArray.push({
   path: arr,
   lc: lc.replace(/0x/, '#'),
   lb,lbx,lby,lid
  })
 })
 return pathArray;
}
getPointArray() {
 let pointArray = [];
 let tempPointsArray = [];
 this.data.forEach(d => {
  let {lid,lc,lb} = d.l_xmlattr;
  let allPoints = d.p;
  let allStations = [];
  allPoints.forEach(item => {
   if(item.p_xmlattr.st && !item.p_xmlattr.ex) {
    allStations.push({...item.p_xmlattr, lid, pn: lb, lc: lc.replace(/0x/, '#')})
   } else if (item.p_xmlattr.ex) {
    if(tempPointsArray.indexOf(item.p_xmlattr.sid) == -1) {
     allStations.push({...item.p_xmlattr, lid, pn: lb, lc: lc.replace(/0x/, '#')})
     tempPointsArray.push(item.p_xmlattr.sid);
    }
   }
  });
  pointArray.push(allStations);
 })
 return pointArray;
}
getCurrentPathArray(name) {
 let d = this.data.filter(d => d.l_xmlattr.lid == name)[0];
 let { loop, lc, lbx, lby, lb, lid} = d.l_xmlattr;
 let allPoints = d.p.slice(0);
 loop && allPoints.push(allPoints[0])
 let allStations = [];
 allPoints.forEach((item, index) => item.p_xmlattr.st && allStations.push({...item.p_xmlattr, index}))
 let arr = [];
 for(let i = 0; i < allStations.length - 1; i++) {
  let path = this.formatPath(allPoints, allStations[i].index, allStations[i + 1].index);
  arr.push({
   lid: lid,
   id: `${allStations[i].sid}_${allStations[i + 1].sid}`,
   path: path,
   color: lc.replace(/0x/, '#')
  })
 }
 return {
  path: arr,
  lc: lc.replace(/0x/, '#'),
  lb,lbx,lby,lid
 }
}
getCurrentPointArray(name) {
 let d = this.data.filter(d => d.l_xmlattr.lid == name)[0];
 let {lid,lc,lb} = d.l_xmlattr;
 let allPoints = d.p;
 let allStations = [];
 allPoints.forEach(item => {
  if(item.p_xmlattr.st && !item.p_xmlattr.ex) {
   allStations.push({...item.p_xmlattr, lid, pn: lb, lc: lc.replace(/0x/, '#')})
  } else if (item.p_xmlattr.ex) {
   allStations.push({...item.p_xmlattr, lid, pn: lb, lc: lc.replace(/0x/, '#')})
  }
 });
 return allStations;
}
getLineNameArray() {
 let nameArray = this.data.map(d => {
  return {
   lb: d.l_xmlattr.lb,
   lid: d.l_xmlattr.lid,
   lc: d.l_xmlattr.lc.replace(/0x/, '#')
  }
 })
 return nameArray;
}
getBugLineArray(arr) {
 if(!arr || !arr.length) return [];
 this.bugLineArray = [];
 arr.forEach(item => {
  let { start, end, cause, duration, lid, lb } = item;
  let lines = [];
  let points = [];
  let tempObj = this.data.filter(d => d.l_xmlattr.lid == lid)[0];
  let loop = tempObj.l_xmlattr.loop;
  let lc = tempObj.l_xmlattr.lc;
  let allPoints = tempObj.p;
  let allStations = [];
  allPoints.forEach(item => {
   if(item.p_xmlattr.st) {
    allStations.push(item.p_xmlattr.sid)
   }
  });
  loop && allStations.push(allStations[0]);
  for(let i=allStations.indexOf(start); i<=allStations.lastIndexOf(end); i++) {
   points.push(allStations[i])
  }
  for(let i=allStations.indexOf(start); i<allStations.lastIndexOf(end); i++) {
   lines.push(`${allStations[i]}_${allStations[i+1]}`)
  }
  this.bugLineArray.push({cause,duration,lid,lb,lines,points,lc: lc.replace(/0x/, '#'),start: points[0],end:points[points.length - 1]});
 })
 return this.bugLineArray;

这种方法大家也不必看懂,知道传入了什么,输入了什么即可,这就是我们的方法类。

4.d3渲染画布并添加方法

这里是js的核心代码,既然class文件都写完了,这里的操作就方便了很多,主要就是下面几个人方法,

renderInventLine(); //渲染虚拟新路
renderAllStation(); //渲染所有的线路名称(右上角)
renderBugLine(); //渲染问题路段
renderAllLine(); //渲染所有线路
renderAllPoint(); //渲染所有点
renderCurrentLine() //渲染当前选中的线路
renderCurrentPoint() //渲染当前选中的站点
zoomed() //缩放时执行的方法
getCenter() //获取虚拟线中心点的坐标
scale() //点击缩放按钮时执行的方法

下面是对应的方法体

svg.call(zoom);
svg.call(zoom.transform, d3.zoomIdentity.translate((1 - baseScale) * transX, (1 - baseScale) * transY).scale(baseScale));

let pathArray = subway.getPathArray();
let pointArray = subway.getPointArray();

renderInventLine();
renderAllStation();
renderBugLine();

function renderInventLine() {
 let arr = subway.getInvent();
 whole.selectAll('path')
 .data(arr)
 .enter()
 .append('path')
 .attr('d', d => d.path)
 .attr('class', d => d.lid)
 .attr('stroke', 'none')
 .attr('fill', 'none')
}

function renderAllLine() {
 for (let i = 0; i < pathArray.length; i++) {
  path.append('g')
  .selectAll('path')
  .data(pathArray[i].path)
  .enter()
  .append('path')
  .attr('d', d => d.path)
  .attr('lid', d => d.lid)
  .attr('id', d => d.id)
  .attr('class', 'lines origin')
  .attr('stroke', d => d.color)
  .attr('stroke-width', 7)
  .attr('stroke-linecap', 'round')
  .attr('fill', 'none')
  path.append('text')
  .attr('x', pathArray[i].lbx)
  .attr('y', pathArray[i].lby)
  .attr('dy', '1em')
  .attr('dx', '-0.3em')
  .attr('fill', pathArray[i].lc)
  .attr('lid', pathArray[i].lid)
  .attr('class', 'line-text origin')
  .attr('font-size', 14)
  .attr('font-weight', 'bold')
  .text(pathArray[i].lb)
 }
}

function renderAllPoint() {
 for (let i = 0; i < pointArray.length; i++) {
  for (let j = 0; j < pointArray[i].length; j++) {
   let item = pointArray[i][j];
   let box = point.append('g');
   if (item.ex) {
    box.append('image')
    .attr('href', './trans.png')
    .attr('class', 'points origin')
    .attr('id', item.sid)
    .attr('x', item.x - 8)
    .attr('y', item.y - 8)
    .attr('width', 16)
    .attr('height', 16)
   } else {
    box.append('circle')
    .attr('cx', item.x)
    .attr('cy', item.y)
    .attr('r', 5)
    .attr('class', 'points origin')
    .attr('id', item.sid)
    .attr('stroke', item.lc)
    .attr('stroke-width', 1.5)
    .attr('fill', '#ffffff')
   }
   box.append('text')
   .attr('x', item.x + item.rx)
   .attr('y', item.y + item.ry)
   .attr('dx', '0.3em')
   .attr('dy', '1.1em')
   .attr('font-size', 11)
   .attr('class', 'point-text origin')
   .attr('lid', item.lid)
   .attr('id', item.sid)
   .text(item.lb)
  }
 }
}

function renderCurrentLine(name) {
 let arr = subway.getCurrentPathArray(name);
 path.append('g')
 .attr('class', 'temp')
 .selectAll('path')
 .data(arr.path)
 .enter()
 .append('path')
 .attr('d', d => d.path)
 .attr('lid', d => d.lid)
 .attr('id', d => d.id)
 .attr('stroke', d => d.color)
 .attr('stroke-width', 7)
 .attr('stroke-linecap', 'round')
 .attr('fill', 'none')
 path.append('text')
 .attr('class', 'temp')
 .attr('x', arr.lbx)
 .attr('y', arr.lby)
 .attr('dy', '1em')
 .attr('dx', '-0.3em')
 .attr('fill', arr.lc)
 .attr('lid', arr.lid)
 .attr('font-size', 14)
 .attr('font-weight', 'bold')
 .text(arr.lb)
}

function renderCurrentPoint(name) {
 let arr = subway.getCurrentPointArray(name);
 for (let i = 0; i < arr.length; i++) {
  let item = arr[i];
  let box = point.append('g').attr('class', 'temp');
  if (item.ex) {
   box.append('image')
   .attr('href', './trans.png')
   .attr('x', item.x - 8)
   .attr('y', item.y - 8)
   .attr('width', 16)
   .attr('height', 16)
   .attr('id', item.sid)
  } else {
   box.append('circle')
   .attr('cx', item.x)
   .attr('cy', item.y)
   .attr('r', 5)
   .attr('id', item.sid)
   .attr('stroke', item.lc)
   .attr('stroke-width', 1.5)
   .attr('fill', '#ffffff')
  }
  box.append('text')
  .attr('class', 'temp')
  .attr('x', item.x + item.rx)
  .attr('y', item.y + item.ry)
  .attr('dx', '0.3em')
  .attr('dy', '1.1em')
  .attr('font-size', 11)
  .attr('lid', item.lid)
  .attr('id', item.sid)
  .text(item.lb)
 }
}

function renderBugLine(modal) {
 let bugLineArray = subway.getBugLineArray(modal);
 d3.selectAll('.origin').remove();
 renderAllLine();
 renderAllPoint();
 bugLineArray.forEach(d => {
  console.log(d)
  d.lines.forEach(dd => {
   d3.selectAll(`path#${dd}`).attr('stroke', '#eee');
  })
  d.points.forEach(dd => {
   d3.selectAll(`circle#${dd}`).attr('stroke', '#ddd')
   d3.selectAll(`text#${dd}`).attr('fill', '#aaa')
  })
 })
 d3.selectAll('.points').on('click', function () {
  let id = d3.select(this).attr('id');
  let bool = judgeBugPoint(bugLineArray, id);
  if (bool) {
   let x, y;
   if (d3.select(this).attr('href')) {
    x = parseFloat(d3.select(this).attr('x')) + 8;
    y = parseFloat(d3.select(this).attr('y')) + 8;
   } else {
    x = d3.select(this).attr('cx');
    y = d3.select(this).attr('cy');
   }
   let toolX = (x * currentScale + transX - ((1 - currentScale) * transX - currentX)) * deviceScale;
   let toolY = (y * currentScale + transY - ((1 - currentScale) * transY - currentY)) * deviceScale;
   let toolH = document.getElementById('tooltip').offsetHeight;
   let toolW = 110;
   if (toolY < 935 / 2) {
    tooltip.style('left', `${toolX - toolW}px`).style('top', `${toolY + 5}px`);
   } else {
    tooltip.style('left', `${toolX - toolW}px`).style('top', `${toolY - toolH - 5}px`);
   }
  }
 });
}

function judgeBugPoint(arr, id) {
 if (!arr || !arr.length || !id) return false;
 let bugLine = arr.filter(d => {
  return d.points.indexOf(id) > -1
 });
 if (bugLine.length) {
  removeTooltip()
  tooltip.select('#tool-head').html(`<span>${id}</span><div class="deletes" onclick="removeTooltip()">×</div>`);
  bugLine.forEach(d => {
   let item = tooltip.select('#tool-body').append('div').attr('class', 'tool-item');
   item.html(`
    <div class="tool-content">
     <div style="color: #ffffff;border-bottom: 2px solid ${d.lc};">
      <span style="background: ${d.lc};padding: 4px 6px;">${d.lb}</span>
     </div>
     <div>
      <div class="content-left">封路时间</div><div class="content-right">${d.duration}</div>
     </div>
     <div>
      <div class="content-left">封路原因</div><div class="content-right">${d.cause}</div>
     </div>
     <div>
      <div class="content-left">封路路段</div><div class="content-right">${d.start}-${d.end}</div>
     </div>
    </div>
   `)
  })
  d3.select('#tooltip').style('display', 'block');
  return true;
 } else {
  return false;
 }
}

function removeTooltip() {
 d3.selectAll('.tool-item').remove();
 d3.select('#tooltip').style('display', 'none');
}

function zoomed() {
 removeTooltip();
 let {x, y, k} = d3.event.transform;
 currentScale = k;
 currentX = x;
 currentY = y;
 group.transition().duration(50).ease(d3.easeLinear).attr("transform", () => `translate(${x + transX * k}, ${y + transY * k}) scale(${k})`)
}

function getCenter(str) {
 if (!str) return null;
 let x, y;
 let tempArr = [];
 let tempX = [];
 let tempY = [];
 str.split(' ').forEach(d => {
  if (!isNaN(d)) {
   tempArr.push(d)
  }
 })

 tempArr.forEach((d, i) => {
  if (i % 2 == 0) {
   tempX.push(parseFloat(d))
  } else {
   tempY.push(parseFloat(d))
  }
 })
 x = (d3.min(tempX) + d3.max(tempX)) / 2;
 y = (d3.min(tempY) + d3.max(tempY)) / 2;
 return [x, y]
}

function renderAllStation() {
 let nameArray = subway.getLineNameArray();
 let len = Math.ceil(nameArray.length / 5);
 let box = d3.select('#menu').append('div')
 .attr('class', 'name-box')
 for (let i = 0; i < len; i++) {
  let subwayCol = box.append('div')
  .attr('class', 'subway-col')
  let item = subwayCol.selectAll('div')
  .data(nameArray.slice(i * 5, (i + 1) * 5))
  .enter()
  .append('div')
  .attr('id', d => d.lid)
  .attr('class', 'name-item')
  item.each(function (d) {
   d3.select(this).append('span').attr('class', 'p_mark').style('background', d.lc);
   d3.select(this).append('span').attr('class', 'p_name').text(d.lb);
   d3.select(this).on('click', d => {
    selected = true;
    d3.selectAll('.origin').style('opacity', 0.1);
    d3.selectAll('.temp').remove();
    renderCurrentLine(d.lid);
    renderCurrentPoint(d.lid);
    let arr = getCenter(d3.select(`path.${d.lid}`).attr('d'));
    svg.call(zoom.transform, d3.zoomIdentity.translate((width / 2 - transX) - arr[0] - (arr[0] + transX) * (currentScale - 1), (height / 2 - transY) - arr[1] - (arr[1] + transY) * (currentScale - 1)).scale(currentScale));
   })
  })
 }
}

function scale(type) {
 if (type && currentScale + scaleStep <= scaleExtent[1]) {
  svg.call(zoom.transform, d3.zoomIdentity.translate((1 - currentScale - scaleStep) * transX - ((1 - currentScale) * transX - currentX) * (currentScale + scaleStep) / currentScale, (1 - currentScale - scaleStep) * transY - ((1 - currentScale) * transY - currentY) * (currentScale + scaleStep) / currentScale).scale(currentScale + scaleStep));
 } else if (!type && currentScale - scaleStep >= scaleExtent[0]) {
  svg.call(zoom.transform, d3.zoomIdentity.translate((1 - (currentScale - scaleStep)) * transX - ((1 - currentScale) * transX - currentX) * (currentScale - scaleStep) / currentScale, (1 - (currentScale - scaleStep)) * transY - ((1 - currentScale) * transY - currentY) * (currentScale - scaleStep) / currentScale).scale(currentScale - scaleStep));
 }
}

上面是大部分代码,想看全部的可以查看demo。

想查看demo或代码的朋友们,请移步至原文http://www.bettersmile.cn

总结

以上所述是小编给大家介绍的d3.js 地铁轨道交通项目实战,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

(0)

相关推荐

  • 使用D3.js+Vue实现一个简单的柱形图

    最近想在Vue的项目里尝试使用d3.js,封装一些常用的图表.这里记录一下自己搭建项目的过程,以及实现一个简单的柱形图.不了解D3的请移步D3 Data-Driven Documents,它是基于数据驱动文档工作方式的一款JavaScript函数库,主要用于网页作图.生成互动图形,是最流行的可视化库之一. 说明 采用Vue-cli脚手架快速搭建项目 npm 安装 D3 实现一个简单的柱形图 项目搭建 使用vue-cli搭建单页应用: # 安装 vue-cli $ npm install --gl

  • 基于 D3.js 绘制动态进度条的实例详解

    D3 是什么 D3 的全称是(Data-Driven Documents),顾名思义可以知道是一个被数据驱动的文档.听名字有点抽象,说简单一点,其实就是一个 JavaScript 的函数库,使用它主要是用来做数据可视化的.如果你不知道什么是 JavaScript ,请先学习一下 JavaScript,推荐阮一峰老师的教程. JavaScript 文件的后缀名通常为 .js,故 D3 也常使用 D3.js 称呼.D3 提供了各种简单易用的函数,大大简化了 JavaScript 操作数据的难度.由于

  • 使用D3.js制作图表详解

    D3是用于数据可视化的Javascript库.使用SVG,Canvas和HTML.结合强大的可视化技术和数据驱动的DOM操作方法. D3与JQuery的区别 D3是数据驱动的,JQuery不是:我们使用JQuery直接操纵元素:但是使用D3 时我们需要通过D3专有的data(),enter()和exit()方法提供数据和回调,然后D3操作元素. D3通常用于数据可视化:JQuery用于创建Web应用.D3有很多数据可视化扩展:JQuery有很多Web应用插件.两者都是Javascript DOM

  • D3.js实现简洁实用的动态仪表盘的示例

    本文介绍了D3.js实现简洁实用的动态仪表盘的示例,分享给大家,具体如下: 动态效果图: 仪表盘效果图 细看上面的动态效果图,可以发现: 一个值变换到一个新的值时,是一个渐变的过程: 圆弧末尾有一个竖线,作为仪表盘的指针,在仪表盘数值变化时,有一个弹性的动画效果. 一开始,我是用Echarts来实现仪表盘,但是它无法满足上面的两点需求.所以后来改成用D3.js. D3.js可以完美地实现图表的定制,从细节上,完美地满足我们的需求. 初始化仪表盘 1.首先定义一个svg元素: <svg id=&quo

  • d3.js 地铁轨道交通项目实战

    上一章说了如何制作一个线路图,当然上一章是手写的JSON数据,当然手写的json数据有非常多的好处,例如可以应对客户的各种BT需求,但是大多数情况下我们都是使用地铁公司现成的JSON文件,话不多说我们先看一下百度官方线路图. 就是这样的,今天我们就来完成它的大部分需求,以及地铁公司爸爸提出来的需求. 需求如下: 1.按照不同颜色显示地铁各线路,显示对应站点. 2.用户可以点击手势缩放和平移(此项目为安卓开发). 3.用户在线路menu里点击线路,对应线路平移值屏幕中心并高亮. 4.根据后台数据,

  • 原生js模拟淘宝购物车项目实战

    本文实例讲述了原生js模拟淘宝购物车实现代码.分享给大家供大家参考.具体如下: 通过JavaScript实现类似与淘宝的购物车效果,包括商品的单选.全选.删除.修改数量.价格计算.数目计算.预览等功能的实现.实现的效果图: 相应的代码: shoppingCart.html <!DOCTYPE html> <html> <head> <meta charset = "UTF-8"> <title>JavaScript实现购物车项

  • 在Vue项目中使用d3.js的实例代码

    之前写一个 Demo里面 有些东西要使用d3实现一些效果 但是在很多论坛找资源都找不到可以在Vue里面使用D3.js的方法,npm 上面的D3相对来说 可以说是很不人性化了 完全没有说 在webpack上怎么使用D3.js 最后折腾很久 看到某位外国大佬 看他的案例 成功的实现了在Vue项目里面实现D3的使用 首先安装 npm install d3 --save-dev 以防万一,然后看package.json 安装完成 在我们开始之前,让我们渲染一个Vue组件,它使用常规的D3 DOM操作呈现

  • Vue.js项目实战之多语种网站的功能实现(租车)

    首先来看一下网站效果,想写这个项目的读者可以自行下载哦,地址:https://github.com/Stray-Kite/Car: 在这个项目中,我们主要是为了学习语种切换,也就是右上角的 中文/English 功能的实现. 首先看一下模拟的后台数据src/config/modules/lang.js 文件中: 关键代码: export default { name: 'Homepage', components: { ScrollNumber }, data () { return { lan

  • angular2+node.js express打包部署的实战

    Angular2我自己还在摸索学习中,本文介绍了angular2+node.js express打包部署的实战,分享给大家,也给自己留个笔记 angular是客户端js,Node.js 是服务端JS,建立SPA 网站需要把这两者统一到一起. 1.angular2项目创建,使用angular-cli ng new mypos 2.使用express命令行工具创建express项目. express --view=hbs 3.angular2 中 需要引用到第三方库 例如 jQuery,bootst

  • D3.js实现饼状图的方法详解

    前言 小编在之前已经跟大家分享过关于怎样用柱状图和折线图这两种基本图表.这两种图表都是有坐标轴的,现在来说一种没有坐标轴的图表--饼图. 饼状图实现 还是和之前一样,我们先把简单的画图框架搭起来,添加SVG画布.但是这里需要注意的是,为了方便后面画饼图上的弧形,我们把组合这些元素的g元素移动到画布的中心: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"

  • d3.js中冷门却实用的内置函数总结

    前言 其实在d3.js的API文档中,提供了很多内置的函数,但是有些很有用的内置函数却被无情的忽略了,这篇博客就来整理整理这些被遗忘却很实用的函数.希望整理过后,他们不再被遗忘. selection.classed(name,[value]) value参数可选,如果没有指定,则返回与name参数匹配的第一个非空元素是否绑定了指定的CSS类,true表示绑定,false表示未绑定.如果value指定了的话,就是为selection添加/删除CSS类. 这点与selection.attr(name

  • 从javascript语言本身谈项目实战

    从javascript语言本身谈项目实战                                              dulao5  2005-1-15 随着ajax的升温,javascript越来越得到人们的重视.重要的是,ajax在一定程度上带来了web软件架构上的变化,人们把越来越多的功能分配到客户端实现,javascript子项目规模越来越大.如何更高效的使用javascript,如何更科学的组织javascript,如何更顺利的保证项目进展?我想就我的经验谈一点浅见. 一

  • vue-router项目实战总结篇

    今天来谈谈vue项目{vue,vue-router,component}三大神将之一的vue-router.作为我们前后端分离很重要的实践之一,router帮我们完成了SPA应用间的页面跳转. 并且,配合axios这样的第三方库,我们可以实现配合后台接口的拦截器功能. 对于一个小型项目而言,router这个文件夹里面就包含了一个router.js就足够了, 但是,当我们的页面比较多的时候,我们就需要分出两个文件出来:一个定义我们的路由和组件,另一个实例化组件,并将路由挂载到vue的实例上. 基本

  • vue项目实战总结篇

    这篇文章把小编前段时间做的vue项目,做个完整的总结,具体内容请参考本文. 这次算是详细总结,会从项目的搭建,一直到最后的服务器上部署. 废话不多说了.干货直接上. 一. 必须node环境, 这次就不写node环境的安装了.过两天我会写个node环境的安装随笔. 二. node环境配好后.开整vue. 1. 安装vue脚手架. npm install -g vue-cli 2. 用脚手架搭项目(只是一行命令) vue init webpack-simple (项目名字) 或 vue init w

随机推荐