今天我们来仿echarts折线图,这个图在echarts是折线图堆叠,但是我用d3改造成了普通的折线图,只为了大家学习(其实在简单的写一个布局就可以)。废话不多说商行代码。

1 制作 Line 类

class Line {constructor() {this._width = 1100;this._height = 800;this._padding = 10;this._offset = 35;this._margins = {right: 50,bottom: 50,left: 70,top: 100};this._scaleX = d3.scaleBand().range([0, this.quadrantWidth()]).paddingInner(1).align(0);this._scaleY = d3.scaleLinear().range([this.quadrantHeight(), 0]);this._color = d3.scaleOrdinal(d3.schemeCategory10);this._dataX = [];this._series = [];this._svg = null;this._body = null;this._tooltip = null;this._transLine = null;this._activeR = 5;this._ticks = 5;}render() {if(!this._tooltip) {this._tooltip = d3.select('body').append('div').style('left', '40px').style('top', '30px').attr('class', 'tooltip').html('');}if(!this._svg) {this._svg = d3.select('body').append('svg').attr('width', this._width).attr('height', this._height).style('background', '#f3f3f3')this.renderAxes();this.renderClipPath();}this.renderBody();}renderAxes() {let axes = this._svg.append('g').attr('class', 'axes');this.renderXAxis(axes);this.renderYAxis(axes);}renderXAxis(axes) {let xAxis = d3.axisBottom().scale(this._scaleX).ticks(this._dataX.length);axes.append('g').attr('class', 'x axis').attr('transform', `translate(${this.xStart()}, ${this.yStart()})`).call(xAxis)d3.selectAll('g.x .tick text').data(this._dataX).enter()}renderYAxis(axes) {let yAxis = d3.axisLeft().scale(this._scaleY).ticks(this._ticks);axes.append('g').attr('class', 'y axis').attr('transform', `translate(${this.xStart()}, ${this.yEnd()})`).call(yAxis)d3.selectAll('.y .tick').append('line').attr('class', 'grid-line').attr('x1', 0).attr('y1', 0).attr('x2', this.quadrantWidth()).attr('y2', 0)}renderClipPath() {this._svg.append('defs').append('clipPath').attr('id', 'body-clip').append('rect').attr('x', 0 - this._activeR - 1).attr('y', 0).attr('width', this.quadrantWidth() + (this._activeR + 1) * 2).attr('height', this.quadrantHeight())}renderBody() {if(!this._body) {this._body = this._svg.append('g').attr('class', 'body').attr('transform', `translate(${this._margins.left},${this._margins.top})`).attr('clip-path', 'url(#body-clip)')this.renderTransLine()}this.renderLines();this.renderDots();this.listenMousemove();}renderTransLine() {this._transLine = this._body.append('line').attr('class', 'trans-line').attr('x1', 0).attr('y1', 0).attr('x2', 0).attr('y2', this._scaleY(0)).attr('stroke-opacity', 0)}renderLines() {let line = d3.line().x((d,i) => this._scaleX(this._dataX[i])).y(d => this._scaleY(d))let lineElements = this._body.selectAll('path.line').data(this._series);let lineEnter =  lineElements.enter().append('path').attr('class', 'line').attr('d', d => line(d.data.map(v => 0))).attr('stroke', (d,i) => this._color(i))let lineUpdate = lineEnter.merge(lineElements).transition().duration(100).ease(d3.easeCubicOut).attr('d', d => line(d.data))let lineExit = lineElements.exit().transition().attr('d', d => line(d.data)).remove();}renderDots() {this._series.forEach((d,i) => {let dotElements = this._body.selectAll('circle._' + i).data(d.data);let dotEnter =  dotElements.enter().append('circle').attr('class', (v, index) => 'dot _' + i + ' index_' + index).attr('cx', (d,i) => this._scaleX(this._dataX[i])).attr('cy', d => this._scaleY(d)).attr('r', 1e-6).attr('stroke', (d,i) => this._color(i))let dotUpdate = dotEnter.merge(dotElements).transition().duration(100).ease(d3.easeCubicOut).attr('cx', (d,i) => this._scaleX(this._dataX[i])).attr('cy', d => this._scaleY(d)).attr('r', 2)let dotExit = dotElements.exit().transition().attr('r', 0).remove();})this._dataX.forEach((d,i) => {d3.selectAll('circle._' + i).attr('stroke', this._color(i))})}listenMousemove() {this._svg.on('mousemove', () => {let px = d3.event.offsetX;let py = d3.event.offsetY;if(px < this.xEnd() && px > this.xStart() && py < this.yStart() && py > this.yEnd()) {this.renderTransLineAndTooltip(px, py, px - this.xStart());} else {this.hideTransLineAndTooltip();}})}renderTransLineAndTooltip(x, y, bodyX) {//鼠标悬浮的indexlet cutIndex = Math.floor((bodyX + this.everyWidth() / 2) / this.everyWidth());//提示线位置this._transLine.transition().duration(50).ease(d3.easeLinear).attr('x1', cutIndex * this.everyWidth()).attr('x2', cutIndex * this.everyWidth()).attr('stroke-opacity', 1);// dot圆圈动画d3.selectAll('circle.dot').transition().duration(100).ease(d3.easeCubicOut).attr('r', 2)d3.selectAll('circle.index_' + cutIndex).transition().duration(100).ease(d3.easeBounceOut).attr('r', this._activeR)//提示框位置和内容if(x > this.quadrantWidth() - this._tooltip.style('width').slice(0,-2) - this._padding * 2) {x = x - this._tooltip.style('width').slice(0,-2) - this._padding * 2 - this._offset * 2;}if(y > this.quadrantHeight() - this._tooltip.style('height').slice(0,-2) - this._padding * 2) {y = y - this._tooltip.style('height').slice(0,-2) - this._padding * 2 - this._offset * 2;}let str = `<div style="text-align: center">${this._dataX[cutIndex]}</div>`;this._series.forEach((d, i) => {str = str + `<div style="width: 15px;height: 15px;vertical-align: middle;margin-right: 5px;border-radius: 50%;display: inline-block;background: ${this._color(i)};"></div>${d.name}<span style="display: inline-block;margin-left: 20px">${d['data'][cutIndex]}</span><br/>`
        })this._tooltip.html(str).transition().duration(100).ease(d3.easeLinear).style('display', 'inline-block').style('opacity', .6).style('left', `${x + this._offset + this._padding}px`).style('top', `${y + this._offset + this._padding}px`);}hideTransLineAndTooltip() {this._transLine.transition().duration(50).ease(d3.easeLinear).attr('stroke-opacity', 0);d3.selectAll('circle.dot').transition().duration(100).ease(d3.easeCubicOut).attr('r', 2);this._tooltip.transition().duration(100).style('opacity', 0).on('end', function () {d3.select(this).style('display', 'none')});}everyWidth() {return this.quadrantWidth() / (this._dataX.length - 1);}quadrantWidth() {return this._width - this._margins.left - this._margins.right;}quadrantHeight() {return this._height - this._margins.top - this._margins.bottom;}xStart() {return this._margins.left;}xEnd() {return this._width - this._margins.right;}yStart() {return this._height - this._margins.bottom;}yEnd() {return this._margins.top;}scaleX(a) {this._scaleX = this._scaleX.domain(a);}scaleY(a) {this._scaleY = this._scaleY.domain(a)}selectMaxYNumber(arr) {let temp = [];arr.forEach(item => temp.push(...item.data));let max = d3.max(temp);let base = Math.pow(10, Math.floor(max / 4).toString().length - 1);//获取Y轴最大值return Math.floor(max / 4 / base) * 5 * base;}dataX(data) {if(!arguments.length) return this._dataX;this._dataX = data;this.scaleX(this._dataX);return this;}series(series) {if(!arguments.length) return this._series;this._series = series;let maxY = this.selectMaxYNumber(this._series);this.scaleY([0, maxY])return this;}
}

2 css 文件

.domain {stroke-width: 2;fill: none;stroke: #888;shape-rendering: crispEdges;
}
.tick text {font-size: 14px;
}
.grid-line {fill: none;stroke: #888;opacity: .4;shape-rendering: crispEdges;
}
.trans-line {fill: none;stroke: #666;opacity: .4;
}
.line {fill: none;stroke-width: 2;
}
.dot {fill: #fff;
}
.tooltip{font-size: 15px;width: auto;padding: 10px;height: auto;position: absolute;background-color: #000000;opacity: .6;border-radius:5px;color: #ffffff;display: none;
}

3 HTML 文件

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>$Title$</title><link rel="stylesheet" type="text/css" href="css/base.css"/><script type="text/javascript" src="js/d3.v4.js"></script><script type="text/javascript" src="js/line.js"></script>
</head>
<body>
<script>var dataX = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];var series = [{name: '邮件营销', data:[120, 132, 101, 134, 90, 230, 210]},{name: '联盟广告', data:[340, 314, 292, 368, 380, 560, 520]},{name: '视频广告', data:[490, 546, 493, 522, 570, 890, 930]},{name: '直接访问', data:[810, 878, 794, 856, 960, 1220, 1250]},{name: '搜索引擎', data:[1640, 1864, 1802, 1868, 2580, 2660, 2640]}]var line = new Line();line.dataX(dataX).series(series).render()setInterval(() => {series = series.map((d,i) => {return {name: d.name,data: new Array(7).fill(1).map((dd, ii) => {return Math.floor(Math.random() * 200) + i * 200})}})console.log(series);line.dataX(dataX).series(series).render()}, 4000)
</script>
</body>
</html>

想预览和下载demo的朋友可以移步原文

原文地址 http://www.bettersmile.cn

转载于:https://www.cnblogs.com/vadim-web/p/11463072.html

d3.js 教程 模仿echarts折线图相关推荐

  1. d3.js 教程 模仿echarts柱状图

    由于最近工作不是很忙,隧由把之前的charts项目用d3.js重写的一下,其实d3.js文档很多,但是入门不是很难,可是想真的能做一个完成的,交互良好的图还是要下一番功夫的.今天在echarts找到了 ...

  2. d3.js 教程 模仿echarts legend功能

    上一节记录没有加上echarts的legend功能,这一小节补一下. 1. 数据 我们可以从echarts中看出,折线数据并不是我们传进入的原始数据(多数情况下我们也不会修改原始数据),而是原始数组的 ...

  3. echarts折线图堆叠怎么设置_ECharts折线图堆叠设置为不堆叠的方法

    下图是ECharts折线图堆叠的官方源码,设置折线图不堆叠只需要将每一个stack的值设置为不一样的名称或者将stack属性删除即可. option = { title: { text: '折线图堆叠 ...

  4. Echarts 折线图完全配置指南 - 手把手教你设置 Echarts 折线图详细教程

    本文首发:<Echarts 折线图完全配置指南> Echarts 折线图是图表中最常用的显示形式之一.使用 Echarts 做出基本的折线图很简单,但要是想把多组数据放在一张图表中,展示的 ...

  5. 1、【Echarts系列】Vue中设置echarts折线图样式(图表、网格、标签、提示、标题、文字),手把手教程系列

    一.echarts 折线图(折线统计图) 折线图在我们也是我们的数据可视化图表中最常用的一种图表之一,是用折线将各个数据点标志连接起来的图表,不仅可以表示数量的多少,而且可以反映同一事物在不同时间里的 ...

  6. echarts折线图动态多条线

    echarts折线图配置项 由于工作中遇到的图表特别多,每次用过配置项总是想不起来,在这里记录一下,希望也可以帮到路过的你.话不多说我们上图: 左边的是设计稿,右边的是echarts的示例图,我们先找 ...

  7. vue echarts 折线图多Y轴显示,加动态配置Y轴颜色

    1.效果图 2.引入依赖 npm install echarts --save 3.在mian.js中引入 import * as echarts from 'echarts'; Vue.protot ...

  8. Echarts折线图和地图(个人总结)

    Echarts折线图和地图(个人总结) Echarts折线图和地图 ECharts,一个使用 JavaScript 实现的开源可视化库,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(I ...

  9. echarts折线图默认显示最后一个点的数据

    echarts折线图默认显示最后一个点的数据 想要达到这种效果图如下: 如果你给折线图设置数据显示,那么要不就全部隐藏,要不就全部显示在折线上.实现指定点的显示就需要你自己去处理这个数据了. 方式有两 ...

最新文章

  1. j2se学习中的一些零碎知识点2之基础知识
  2. VTK:PolyData之MergePoints
  3. gitpython git diff_Python全栈开发-git常用命令
  4. mac 终端提示_有用的终端提示
  5. 认识和学习orchestrator之基本使用篇
  6. table或者列表中超出的字用省略号代替的方法(支持IE6)
  7. python 原理 pdf_《深入浅出深度学习:原理剖析与Python实践》.pdf
  8. 整理发布一些关于VMware vSphere的文档
  9. 产品经理通用标准工作流程
  10. 凹点匹配分割 matlab,基于凹点和重心检测的粘连类圆形目标图像分割
  11. python 实现省全称和省的简称互相转换
  12. 分片(primary shard replica shard)
  13. 怎么给领导做项目汇报
  14. 什么是AWS Fargate
  15. MaxScript 设置 OBJ Import Options
  16. 【ThreeJs】(2)照相机 | 正交投影照相机 | 透视投影照相机
  17. VS2017 -error LNK1104: 无法打开文件“msvcprtd.lib”
  18. 诺基亚 java_诺基亚开放Symbian Javaapps了
  19. 洛谷:P6062 [USACO05JAN]Muddy Fields G
  20. P3646 [APIO2015]巴厘岛的雕塑

热门文章

  1. 火狐浏览器firefox adobe flash player 崩溃
  2. [机器学习]正则化方法 -- Regularization
  3. 【IT笔试面试题整理】有序数组生成最小高度二叉树
  4. 【IT笔试面试题整理】删除无序链表中重复的节点
  5. 用Microwindows(Nano-X)编写“hello world”
  6. Shady 深度学习课程
  7. 游牧大地的诗意:看龙力游的草原油画
  8. 贴几张最新最精彩的电影海报
  9. PIC32单片机harmony开发环境 - uart例程和代码分析
  10. java 数据库改操作_数据库的插入、修改、删除操作(java实现)