d3.js 教程 模仿echarts折線圖

今天我們來仿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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/248159.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/248159.shtml
英文地址,請注明出處:http://en.pswp.cn/news/248159.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

vue中v-for的使用

本人正在開始學習Vue,每天寫寫基礎的記錄,希望對大家有幫助,如有錯誤還望指出,我也是一個小白,也希望大家能一起進步 v-for指令的使用: 1.循環普通數組 item in list 中的item是自己個想寫什么名寫什么名 另一種寫法 i 表示索引值 2.循環對象數組 3.循環普通對象 4.迭代數字 注…

js高級第一天

JavaScript面向對象 1.1兩大編程思想&#xff1a; 1、面向過程 ? 面向過程&#xff1a;POP(Process-oriented programming) 面向過程就是分析出解決問題所需要的步驟&#xff0c;然后用函數把這些步驟一步一步實現&#xff0c;使用的時候再一個一個的依次調用就可以了。 ?…

d3.js 教程 模仿echarts legend功能

上一節記錄沒有加上echarts的legend功能&#xff0c;這一小節補一下。 1. 數據 我們可以從echarts中看出&#xff0c;折線數據并不是我們傳進入的原始數據&#xff08;多數情況下我們也不會修改原始數據&#xff09;&#xff0c;而是原始數組的一個備份而已。備份數組的方法有很…

小程序2-基本架構講解(一)WXSS樣式

項目里邊生成了不同類型的文件: .json 后綴的 JSON 配置文件.wxml 后綴的 WXML 模板文件.wxss 后綴的 WXSS 樣式文件.js 后綴的 JS 腳本邏輯文件WXSS 樣式 WXSS (WeiXin Style Sheets)是一套樣式語言&#xff0c;用于描述 WXML 的組件樣式。WXSS 具有 CSS 大部分的特性 新增了尺…

js高級—tab欄切換(面向對象做法)

<main><h4>Js 面向對象 動態添加標簽頁</h4><div class"tabsbox" id"tab"><!-- tab 標簽 --><nav class"fisrstnav"><ul><li class"liactive"><span>測試1</span><sp…

MFC的sendmessage和postmessage 以及sendmessagetimeout

PostMessage只負責將消息放到消息隊列中&#xff0c;不確定何時及是否處理&#xff0c;相當于異步操作&#xff0c;執行后馬上返回SendMessage要等到受到消息處理的返回碼&#xff08;DWord類型&#xff09;后才繼續&#xff0c;相當于同步操作&#xff0c;一直在等待&#xff…

python PIL圖像處理-框選

框選圖中位置 代碼 from PIL import Image,ImageDraw,ImageFont,ImageFilter import random#------------------------------------- #filepath,[837,103][942,208]#圖片處理&#xff0c;框選 def pic_rectangle(filepath,bound):image Image.open(filepath)draw ImageDraw.D…

Win10卸載python總是提示error2503失敗各種解決辦法

最近win10的電腦裝了python的3.4&#xff0c;然后想卸載&#xff0c;就總是提示error 2053&#xff0c;類似于這種&#xff1a; 下面是我的坎坷解決之路&#xff1a; 1、網上說&#xff0c;任務管理器 --> 詳細信息 --> explorer.exe結束任務&#xff0c;結束資源管理器&…

js高級—查詢商品案例

<div class"search">按照價格查詢&#xff1a;<input type"text" class"start"> - <input type"text" class"end"><button class"search-price">搜索</button> 按照商品名稱查詢&a…

[Codeforces702F]T-Shirts——非旋轉treap+貪心

題目鏈接&#xff1a; Codeforces702F 題目大意&#xff1a;有$n$種T恤&#xff0c;每種有一個價格$c_{i}$和品質$q_{i}$且每種數量無限。現在有$m$個人&#xff0c;第$i$個人有$v_{i}$元&#xff0c;每人每次會買他能買得起的品質最高的一件T恤(當兩件T恤品質相同時優先買價格…

js高級第二天

構造函數和原型 構造函數和原型 在典型的OOP 的語言中&#xff08;如Java&#xff09;&#xff0c;都存在類的概念&#xff0c;類就是對象的模板&#xff0c;對象就是類的實例&#xff0c;但在ES6之前&#xff0c;JS 中并沒用引入類的概念。ES6&#xff0c;全稱ECMAScript6.0…

操作系統原理之文件系統(第五章)

一、文件 1、?件系統的?戶接?包括?件的命名、類型、屬性和對?件的操作 2、?件命名&#xff1a;所有操作系統都允許?1&#xff5e;8個字?組成的字符串 3、?件擴展名&#xff1a;多數操作系統都?持?件名?圓點隔開分為兩部分&#xff0c;圓點后?的部分稱為?件擴展名…

第三次作業------52李金鎮

---恢復內容開始--- 習題1&#xff1a; **1.初始化一個數據集&#xff0c;包括5-10位同學的成績數據&#xff08;數據類型不限&#xff09;&#xff0c;數據格式如下&#xff1a; **學號 姓名 Java C語言 Python2017XXXX 小白 87 68 922017XXXX 小黃 80 76 832017XXXX 小王 75 …

js高級第三天

原型鏈 作用&#xff1a;提供一個成員的查找機制&#xff0c;或者查找規則含義&#xff1a;由原型所串聯起來的鏈裝結構JavaScript 的成員查找機制(規則) 當訪問一個對象的屬性&#xff08;包括方法&#xff09;時&#xff0c;首先查找這個對象自身有沒有該屬性。如果沒有就查…

為什么大學的計算機老師技術那么厲害,卻不愿意當程序員?

不知道大家有多少是從事跟計算機有關的工作的&#xff0c;每次想到大學時的計算機考試&#xff0c;都能令小小編心驚膽戰呀&#xff0c;各式代碼和計算機語言&#xff0c;真的是很令人頭痛了。不過呢&#xff0c;也有很多大神&#xff0c;大學學著其他的專業&#xff0c;卻在畢…

DDG全家桶之3022

本篇文章主要根據360Netlab新出的DDG分析文檔來復現新變種3022&#xff0c;會涉及部分分析和清除的方法&#xff0c;本篇文章只用于學習交流&#xff0c;為廣大受害者提供清除思路 &#xff0c;請勿用于非法用途&#xff0c;產生一切后果與作者無關 詳情請參考文檔&#xff1a;…

js高級第四天

課程回顧&#xff1a; ? 原型鏈&#xff1a;由原型構成鏈狀結構&#xff0c;提供成員查找機制 ? 繼承&#xff1a;組合繼承&#xff1a;構造函數和原型對象 ? 屬性&#xff1a;調用父構造函數的時候用call改變this指向 ? 方法&#xff1a;父實例對象賦值給子原型對象&a…

d3.js 制作簡單的俄羅斯方塊

d3.js是一個不錯的可視化框架&#xff0c;同時對于操作dom也是十分方便的。今天我們使用d3.js配合es6的類來制作一個童年小游戲--俄羅斯方塊。話不多說先上圖片。 1. js tetris類 由于方法拆分的比較細所以加上了一些備注&#xff08;這不是我的風格&#xff01;&#xff09; c…

Flask中路由系統以及藍圖的使用

一、Flask的路由系統 1.app.route()裝飾器中的參數 methods:當前URL地址&#xff0c;允許訪問的請求方式 app.route("/info", methods["GET", "POST"]) def student_info():stu_id int(request.args["id"])return f"Hello Old b…

js高級第五天

課程回顧&#xff1a; ? 原型鏈&#xff1a;由原型構成鏈狀結構&#xff0c;提供成員查找機制 ? 繼承&#xff1a;組合繼承&#xff1a;構造函數和原型對象 ? 屬性&#xff1a;調用父構造函數的時候用call改變this指向 ? 方法&#xff1a;父實例對象賦值給子原型對象&a…