d3js 源码地址:: http://bl.ocks.org/brattonc/5e5ce9beee483220e2f6

官方提供的代码不能直接用,版本3.x 这是调整后v5能使用的。

<!DOCTYPE html>
<html><head><meta charset='utf-8'><meta http-equiv='X-UA-Compatible' content='ie=edge'><title>7</title><script src="https://d3js.org/d3.v5.min.js"></script><link rel="stylesheet" type="text/css" href="/css.css" />
</head><body><svg id="svg" width="300" height="300" onclick="javascript:gauge.update(NewValue())"></svg><span>点击SVG更新数据</span></body>
<script type='text/javascript'>var gauge = loadLiquidFillGauge("svg", 55, {circleColor: "#FF7777",textColor: "#FF4444",waveTextColor: "#FFAAAA",waveColor: "#FFDDDD",circleThickness: 0.02,circleFillGap: 0,textVertPosition: 0.2,waveAnimateTime: 1000,waveRiseTime: 3000});function NewValue() {if (Math.random() > .5) {return Math.round(Math.random() * 100);}return (Math.random() * 100).toFixed(1);}function loadLiquidFillGauge(elementId, value, config) {config = Object.assign({}, {minValue: 0, // 量规最小值.maxValue: 100, // 量规最大值.circleThickness: 0.05, // 外圆的厚度与半径的百分比.circleFillGap: 0.05, // 外圆与波圆之间的间隙大小与外圆半径的百分比.circleColor: "#178BCA", // 外圆的颜色.waveHeight: 0.05, // 波高与波圆半径的百分比.waveCount: 2, // 每波圈宽度的全波数.waveRiseTime: 1000, // 波从0上升到最终高度所需的时间,以毫秒为单位.waveAnimateTime: 18000, //  一个完整的波进入波圈的时间(以毫秒为单位).waveRise: true, // 控制波浪是否应该从0上升到它的全部高度,或从它的全部高度开始waveHeightScaling: true, // 控制波大小缩放在低和高填充百分比。当真值时,波高在50%填充时达到最大值,在0%和100%填充时达到最小值。这有助于防止波使波圈出现完全满或空时,接近它的最小或最大填充。waveAnimate: true, // 控制波形是滚动还是静态.waveColor: "#178BCA", // 填充波的颜色。waveOffset: 0, // 最初抵消波的量。0 = 无偏移。1 = 一个完整波的偏移量textVertPosition: .5, // 在波圈内显示百分比文本的高度。0 =下,1 =上.textSize: 1, // 要在波圈中显示的文本的相对高度。1 = 50%valueCountUp: true, // 如果为真,则显示的值从0计数到加载时的最终值。如果为false,则显示最终值。displayPercent: true, // 如果为真,值后面会显示%符号。textColor: "#045681", // 当波浪不重叠值文本时的颜色。waveTextColor: "#A4DBf8" // 当波浪与值文本重叠时的颜色.}, config);var gauge = d3.select("#" + elementId);var radius = Math.min(parseInt(gauge.style("width")), parseInt(gauge.style("height"))) / 2;var locationX = parseInt(gauge.style("width")) / 2 - radius;var locationY = parseInt(gauge.style("height")) / 2 - radius;var fillPercent = Math.max(config.minValue, Math.min(config.maxValue, value)) / config.maxValue;var waveHeightScale;if (config.waveHeightScaling) {waveHeightScale = d3.scaleLinear().range([0, config.waveHeight, 0]).domain([0, 50, 100]);} else {waveHeightScale = d3.scaleLinear().range([config.waveHeight, config.waveHeight]).domain([0, 100]);}var textPixels = (config.textSize * radius / 2);var textFinalValue = parseFloat(value).toFixed(2);var textStartValue = config.valueCountUp ? config.minValue : textFinalValue;var percentText = config.displayPercent ? "%" : "";var circleThickness = config.circleThickness * radius;var circleFillGap = config.circleFillGap * radius;var fillCircleMargin = circleThickness + circleFillGap;var fillCircleRadius = radius - fillCircleMargin;var waveHeight = fillCircleRadius * waveHeightScale(fillPercent * 100);var waveLength = fillCircleRadius * 2 / config.waveCount;var waveClipCount = 1 + config.waveCount;var waveClipWidth = waveLength * waveClipCount;// 四舍五入函数,以便在数值累计时始终显示正确的小数点后位数。var textRounder = (value) => Math.round(value);if (parseFloat(textFinalValue) != parseFloat(textRounder(textFinalValue))) {textRounder = (value) => parseFloat(value).toFixed(1);}if (parseFloat(textFinalValue) != parseFloat(textRounder(textFinalValue))) {textRounder = (value) => parseFloat(value).toFixed(2);}// 建立clip wave区域的数据。var data = Array.from({ length: 41 * waveClipCount }, (_, i) => ({ x: i / (40 * waveClipCount), y: (i / (40)) }));// 绘制外圆的比例。var gaugeCircleX = d3.scaleLinear().range([0, 2 * Math.PI]).domain([0, 1]);var gaugeCircleY = d3.scaleLinear().range([0, radius]).domain([0, radius]);// 用于控制剪切路径大小的尺度。var waveScaleX = d3.scaleLinear().range([0, waveClipWidth]).domain([0, 1]);var waveScaleY = d3.scaleLinear().range([0, waveHeight]).domain([0, 1]);// 用于控制裁剪路径位置的刻度。var waveRiseScale = d3.scaleLinear()// 剪辑区域的大小是填充圆的高度+波的高度,所以我们定位剪辑波这样,它将重叠填充圆在所有0%时,并将完全覆盖填充圆在100%。.range([(fillCircleMargin + fillCircleRadius * 2 + waveHeight), (fillCircleMargin - waveHeight)]).domain([0, 1]);var waveAnimateScale = d3.scaleLinear().range([0, waveClipWidth - fillCircleRadius * 2]) // 将夹子区域推一个完整的波,然后弹回来。.domain([0, 1]);// 用于控制文本在量规内的位置的刻度。var textRiseScaleY = d3.scaleLinear().range([fillCircleMargin + fillCircleRadius * 2, (fillCircleMargin + textPixels * 0.7)]).domain([0, 1]);// 在父SVG中居中测量。var gaugeGroup = gauge.append("g").attr('transform', `translate(${locationX},${locationY})`);// 画一个外圆。var gaugeCircleArc = d3.arc()({startAngle: gaugeCircleX(0),endAngle: gaugeCircleX(1),outerRadius: gaugeCircleY(radius),innerRadius: gaugeCircleY(radius - circleThickness),})gaugeGroup.append("path").attr("d", gaugeCircleArc).style("fill", config.circleColor).attr('transform', `translate(${radius},${radius})`);// 波不重叠的文本。var text1 = gaugeGroup.append("text").text(textRounder(textStartValue) + percentText).attr("class", "liquidFillGaugeText").attr("text-anchor", "middle").attr("font-size", textPixels + "px").style("fill", config.textColor).attr('transform', `translate(${radius},${textRiseScaleY(config.textVertPosition)})`);// 剪切波面积。var clipArea = d3.area().x(d => waveScaleX(d.x)).y0(d => waveScaleY(Math.sin(Math.PI * 2 * config.waveOffset * -1 + Math.PI * 2 * (1 - config.waveCount) + d.y * 2 * Math.PI))).y1(d => (fillCircleRadius * 2 + waveHeight));var waveGroup = gaugeGroup.append("defs").append("clipPath").attr("id", "clipWave" + elementId);var wave = waveGroup.append("path").datum(data).attr("d", clipArea).attr("T", 0);// 带有剪切波的内圆。var fillCircleGroup = gaugeGroup.append("g").attr("clip-path", "url(#clipWave" + elementId + ")");fillCircleGroup.append("circle").attr("cx", radius).attr("cy", radius).attr("r", fillCircleRadius).style("fill", config.waveColor);// 波重叠的文本。var text2 = fillCircleGroup.append("text").text(textRounder(textStartValue) + percentText).attr("class", "liquidFillGaugeText").attr("text-anchor", "middle").attr("font-size", textPixels + "px").style("fill", config.waveTextColor).attr('transform', `translate(${radius},${textRiseScaleY(config.textVertPosition)})`);// 把数值加起来。if (config.valueCountUp) {var textTween = function () {var i = d3.interpolate(this.textContent, textFinalValue);return function (t) {this.textContent = textRounder(i(t)) + percentText;}};text1.transition().duration(config.waveRiseTime).tween("text", textTween);text2.transition().duration(config.waveRiseTime).tween("text", textTween);}// 让波浪上升。波和波组是分开的,水平和垂直运动可以独立控制。var waveGroupXPosition = fillCircleMargin + fillCircleRadius * 2 - waveClipWidth;if (config.waveRise) {waveGroup.attr('transform', `translate(${waveGroupXPosition},${waveRiseScale(0)})`).transition().duration(config.waveRiseTime).ease(d3.easeLinear).attr('transform', `translate(${waveGroupXPosition},${waveRiseScale(fillPercent)})`).on("start", function () {// 当wave Rise = true和 wave Animate=false时,这个变换是必要的,以使剪辑波正确定位。如果没有这个,波将无法正确定位,但我们不清楚为什么这是必要的.wave.attr('transform', 'translate(1,0)');});} else {waveGroup.attr('transform', `translate(${waveGroupXPosition},${waveRiseScale(fillPercent)}`);}if (config.waveAnimate) animateWave();function animateWave() {wave.attr('transform', `translate(${waveAnimateScale(wave.attr('T'))},0)`);wave.transition().duration(config.waveAnimateTime * (1 - wave.attr('T'))).ease(d3.easeLinear).attr("transform", `translate(${waveAnimateScale(1)},0)`).attr('T', 1).on('end', function () {wave.attr('T', 0);animateWave();});}function GaugeUpdater() {this.update = function (value) {var newFinalValue = parseFloat(value).toFixed(2);var textRounderUpdater = (value) => Math.round(value);if (parseFloat(newFinalValue) != parseFloat(textRounderUpdater(newFinalValue))) {textRounderUpdater = (value) => parseFloat(value).toFixed(1);}if (parseFloat(newFinalValue) != parseFloat(textRounderUpdater(newFinalValue))) {textRounderUpdater = (value) => parseFloat(value).toFixed(2);}var textTween = function () {var interpolate = d3.interpolate(this.textContent, parseFloat(value).toFixed(2));return function (t) {this.textContent = textRounderUpdater(interpolate(t)) + percentText;}};text1.transition().duration(config.waveRiseTime).tween("text", textTween);text2.transition().duration(config.waveRiseTime).tween("text", textTween);var fillPercent = Math.max(config.minValue, Math.min(config.maxValue, value)) / config.maxValue;var waveHeight = fillCircleRadius * waveHeightScale(fillPercent * 100);var waveRiseScale = d3.scaleLinear()// 剪辑区域的大小是填充圆的高度+波的高度,所以我们定位剪辑波这样,它将重叠填充圆在所有0%时,并将完全覆盖填充圆在100%..range([(fillCircleMargin + fillCircleRadius * 2 + waveHeight), (fillCircleMargin - waveHeight)]).domain([0, 1]);var newHeight = waveRiseScale(fillPercent);var waveScaleX = d3.scaleLinear().range([0, waveClipWidth]).domain([0, 1]);var waveScaleY = d3.scaleLinear().range([0, waveHeight]).domain([0, 1]);var newClipArea;if (config.waveHeightScaling) {newClipArea = d3.area().x(d => waveScaleX(d.x)).y0(d => waveScaleY(Math.sin(Math.PI * 2 * config.waveOffset * -1 + Math.PI * 2 * (1 - config.waveCount) + d.y * 2 * Math.PI))).y1(d => (fillCircleRadius * 2 + waveHeight));} else {newClipArea = clipArea;}var newWavePosition = config.waveAnimate ? waveAnimateScale(1) : 0;wave.transition().duration(0).transition().duration(config.waveAnimate ? (config.waveAnimateTime * (1 - wave.attr('T'))) : (config.waveRiseTime)).ease(d3.easeCircle).attr('d', newClipArea).attr('transform', `translate(${newWavePosition},0)`).attr('T', '1').on("end", function () {if (config.waveAnimate) {wave.attr('transform', `translate(${waveAnimateScale(0)},0)`)animateWave();}});waveGroup.transition().duration(config.waveRiseTime).attr('transform', `translate(${waveGroupXPosition},${newHeight})`)}}return new GaugeUpdater();}
</script></html>

d3js 实现水球图相关推荐

  1. python画动图-Python绘制动态水球图过程详解

    先来看看绘制的动态水球图: 没有安装PyEcharts的,先安装PyEcharts: # 安装pyecharts模块,直接安装就是最新的版本pip install pyecharts 安装好PyEch ...

  2. Pyecharts:pyecharts(图文+代码)实战(柱状图/条形图/散点图、漏斗图、仪表盘、折线/面积图、水球图、地图、平行坐标系、饼图、极坐标系、雷达图、词云图)之绘制各种吊炸天的图表

    Pyecharts:pyecharts(图文+代码)实战(柱状图/条形图/散点图.漏斗图.仪表盘.折线/面积图.水球图.地图.平行坐标系.饼图.极坐标系.雷达图.词云图)之绘制各种吊炸天的图表 目录 ...

  3. echarts代码格式化_echarts水球图格式化Format使用

    上周有一个需求,echarts的水球图要做展示,因为后台数据有可能值会返回'-' ,所以需要动态展示,首先返回值会有四个,分别表示本周/本月百分率以及本周/本月具体数值所以,产品提了一个需求当后端接口 ...

  4. 带着canvas去流浪系列之七 绘制水球图

    [摘要] 用原生canvasAPI实现百度echarts 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...

  5. vue使用echarts-liquidfill水球图不生效

    水球图官方链接: https://www.npmjs.com/package/echarts-liquidfill 安装命令: npm install echarts --save npm insta ...

  6. echaarts水滴(水球图)波浪效果

    效果图 首先放盒子 <div class="wtChartBall_box"><div class="d_flex"><div i ...

  7. Echarts 水球图设置基准线

    *前言:最近的项目需求中,要求在水球图中加一条标准线(作为报警提示线). 1.效果如下: 2.思路: 注意:如果是直接在水球图上画标线   是实现不了的. 所以我们换种思路(大佬指点了一下),在折线图 ...

  8. 可视化 | Python精美动态水球图

    文章目录 1. 准备工作 1.1 pyechars安装 1.2 导入模块 2. 绘制水球图 2.1 基本水球图 2.2 增加边框,改变形状 2.3 多波浪 2.4 增加标注,改变字体大小,改变填充颜色 ...

  9. ECHARTS 水球图

    转载编辑. 原作者链接地址:https://zhuanlan.zhihu.com/p/25353670?group_id=827655855632715776 水球图是一种适合于展现单个百分比数据的图 ...

最新文章

  1. 将毫秒转换_Matlab将Unix时间戳转为可读日期
  2. PS调出通透唯美阳光外景女生照片
  3. 轻轻的我走了,正如我轻轻的来…——ADO.NET核心类的灭度与SQLHelper的诞生——十八相送(下)...
  4. 10. Firewalls (防火墙 2个)
  5. 微信小程序多选取值判断显示内容
  6. 课时39.细线表格(理解)
  7. 服务器USB启动故障一例
  8. AR-关于几种特殊的收款方式说明
  9. lambert(兰伯特)投影 应用工具_全息投影技术,在哪些场地可以用到
  10. 毁掉孩子自信的10个杀手
  11. 关于改良报告与学习总结(Ⅰ)
  12. Sublime + Chrome 本地调试 CSS 选择器
  13. 文件服务器 选型,文件服务器选型
  14. 2022华中杯C题矿井提升机钢丝绳的缺陷分析思路讲解
  15. isupper函数用法
  16. 计算机历史记录无法删除,win10时间线灰色浏览记录删不掉怎么回事_win10时间线历史灰色无法删除的解决教程-win7之家...
  17. 通过爬虫获取免费IP代理,搭建自己的IP池(http)
  18. java se运行环境_Java运行环境Java SE Runtime Environment (JRE) 下载
  19. 一体机性能服务器图片介绍,浪潮发布AI一体机 整体性能较普通服务器提升10倍以上...
  20. 好玩的手机android游戏,好玩的android手机游戏2018_热门android游戏排行榜

热门文章

  1. 浏览DELPHI的源代码
  2. Linux下使用OpenSSL生成证书
  3. PCIe 5.0 spec学习1.1---均衡
  4. 计算机技术及其关系,计算机技术和自动化的关系.doc
  5. bartender 不打印文本内容的解决方法
  6. datatable invalid json format
  7. Latex表格固定列宽并设置靠左、居中或靠右
  8. 自制PLC—木牛流马PLC V1.1发布
  9. Kafka的高性能设计
  10. 有用的博客整理(Android系统编译相关)