d3 曲线区域填充

本篇以一个简单的demo示范一下在d3中实现曲线的区域填充。

clip-path

clip-path:创建一个只有元素的部分区域可以显示的剪切区域。显示clip-path内部的区域,而外部的区域不可见。

区域填充也主要以clip-path为基础来实现。

区域填充

1.1 先画一条曲线


<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>

    <body>
        <div id="test-svg">
        </div>
    </body>
    <script src="https://d3js.org/d3.v5.js"></script>
    <script type="text/javascript" src="js/2D.js"></script>
    <script>
        window.onload = function() {

            // 数据
            var data = [{
                date: new Date(2019, 3, 24),
                value: 23.24
            }, {
                date: new Date(2019, 3, 25),
                value: 72.15
            }, {
                date: new Date(2019, 3, 26),
                value: 38.84
            }, {
                date: new Date(2019, 3, 27),
                value: 58.62
            }, {
                date: new Date(2019, 3, 30),
                value: 10.80
            }, {
                date: new Date(2019, 4, 1),
                value: 85.47
            }];

            var width = 800,
                height = 400,
                padding = {
                    top: 40,
                    right: 40,
                    bottom: 40,
                    left: 40
                };

            var colors = d3.schemeSet2;
            var svg = d3.select("#test-svg")
                .append('svg')
                .attr('width', width + 'px')
                .attr('height', height + 'px');

            // x轴:时间轴
            var xScale = d3.scaleTime()
                .domain(d3.extent(data, function(d) {
                    return d.date;
                }))
                .range([padding.left, width - padding.right]);

            var xAxis = d3.axisBottom()
                .scale(xScale)
                .tickSize(10);

            svg.append('g')
                .call(xAxis)
                .attr("transform", "translate(0," + (height - padding.bottom) + ")")
                .selectAll("text")
                .attr("font-size", "10px")
                .attr("dx", "50px");

            var ymax = d3.max(data, function(d) {
                return d.value;
            });

            // y轴
            var yScale = d3.scaleLinear()
                .domain([0, ymax])
                .range([height - padding.bottom, padding.top]);

            var yAxis = d3.axisLeft()
                .scale(yScale)
                .ticks(10);

            svg.append('g')
                .call(yAxis)
                .attr("transform", "translate(" + padding.left + ",0)");

            var curveLine = d3.line()
                .x(function(d) {
                    return xScale(d.date);
                })
                .y(function(d) {
                    return yScale(d.value);
                })
                .curve(d3.curveCatmullRom.alpha(0.5));

            svg.append("path")
                .datum(data)
                .attr("fill", "none")
                .attr("stroke", "steelblue")
                .attr("stroke-width", 1.5)
                .attr("stroke-linejoin", "round")
                .attr("stroke-linecap", "round")
                .attr("d", curveLine);

        }
    </script>

</html>

2.2 添加一条水平的阈值线


// 水平阈值
            svg.append('line')
                .attr('x1', 0)
                .attr('y1', yScale(45))
                .attr('x2', width)
                .attr('y2', yScale(45))
                .attr('stroke', '#FFA354')
                .attr('stroke-width', 1.5)
                .attr('stroke-dasharray', '6,4');

3.3 填充阈值线上面部分



// 添加一个clipPath
svg.append("clipPath")
                .attr("id", "clip-th")
                .append("rect")
                .attr("x", 0)
                .attr("y", padding.top)
                .attr("width", width)
                .attr("height", yScale(45) - yScale(ymax));

// 再次添加一条曲线并填充区域
            svg.append("path")
                .datum(data)
                .attr("fill", "steelblue")
                .attr("fill-opacity", 0.5)
                .attr("stroke", "none")
                .attr("d", curveLine)
                .attr('clip-path', "url(#clip-th)");

  • path填充的时候会把首尾点连起来,并不是我们想要的效果。所以我们再首尾都添加一个点,来控制填充区域。

4.4 修改数据,重新绘制填充区域


data.unshift({
                date: new Date(2019, 3, 24),
                value: 0
            });
            data.push({
                date: new Date(2019, 4, 1),
                value: 0
            });

            svg.append("path")
                .datum(data)
                .attr("fill", "steelblue")
                .attr("fill-opacity", 0.5)
                .attr("stroke", "none")
                .attr("d", curveLine)
                .attr('clip-path', "url(#clip-th)");

  • 目的是达到了但是效果并不是很理想。由于额外的添加了两个点生成的曲线和原曲线产生了偏差。个人觉得比较理想的做法是
    再添加一条红线所示的正常直线path。然后将两个直线和曲线组合起来进行填充。

5.5 再次修改数据,重新绘制


// 红线所示直线数据
var data2 = [{
                date: new Date(2019, 3, 24),
                value: 23.24
            }, {
                date: new Date(2019, 3, 24),
                value: 0
            }, {
                date: new Date(2019, 4, 1),
                value: 0
            }, {
                date: new Date(2019, 4, 1),
                value: 85.47
            }];

// 添加直线生成器
var line = d3.line()
                .x(function(d) {
                    return xScale(d.date);
                })
                .y(function(d) {
                    return yScale(d.value);
                });

// 绘制两个path
container.append("path")
                .datum(data)
                .attr("fill", "none")
                .attr("d", curveLine);

            container.append("path")
                .datum(data2)
                .attr("fill", "none")
                .attr("d", line);

// 将两个path合并
var combined = "";
            container.selectAll("path")
                .each(function() {
                    combined += d3.select(this).attr("d");
                });

            container.selectAll("path").remove();

                        // 绘制合并后的path
            container.append("path")
                .attr("stroke", "none")
                .attr("d", combined)
                .attr("fill", "steelblue")
                .attr("fill-opacity", 0.5)
                .attr("fill-rule", "evenodd")
                .attr('clip-path', "url(#clip-th)");

  • 我们就能看到完全的区域填充了。切记要使用fill-rule来约定填充的区域。

6.6 添加两条垂直的阈值


// 垂直阈值线
            svg.append('line')
                .attr('x1', xScale(new Date(2019, 3, 26)))
                .attr('y1', yScale(ymax))
                .attr('x2', xScale(new Date(2019, 3, 26)))
                .attr('y2', yScale(0))
                .attr('stroke', '#FFA354')
                .attr('stroke-width', 1.5)
                .attr('stroke-dasharray', '6,4')

            svg.append('line')
                .attr('x1', xScale(new Date(2019, 3, 28)))
                .attr('y1', yScale(ymax))
                .attr('x2', xScale(new Date(2019, 3, 28)))
                .attr('y2', yScale(0))
                .attr('stroke', '#FFA354')
                .attr('stroke-width', 1.5)
                .attr('stroke-dasharray', '6,4')

// clip-path

svg.append("clipPath")
                .attr("id", "clip-th2")
                .append("rect")
                .attr("x", xScale(new Date(2019, 3, 26)))
                .attr("y", yScale(45))
                .attr("width", xScale(new Date(2019, 3, 28)) - xScale(new Date(2019, 3, 26)))
                .attr("height", yScale(0) - yScale(45));

container.append("path")
                .attr("stroke", "none")
                .attr("d", combined)
                .attr("fill", "yellowgreen")
                .attr("fill-opacity", 0.5)
                .attr("fill-rule", "evenodd")
                .attr('clip-path', "url(#clip-th2)");

  • 这下就大功告成了!

原文地址:https://www.cnblogs.com/chenjy1225/p/11013643.html

时间: 2024-10-12 16:46:57

d3 曲线区域填充的相关文章

进口货规范的地方规划局可

http://www.gettyimages.cn/newsr.php?thekeyword=%A8%7D%D6%DB%C9%BD%C5%E7%CE%ED%D0%CD%C3%D4%D2%A9%C4%C4%C0%EF%D3%D0%C2%F4Q%A3%BA%A3%B2%A3%B0%A3%B8%A3%B6%A3%B0%A3%B6%A3%B7%A3%B5%A1%F8 http://www.gettyimages.cn/newsr.php?thekeyword=%A8%8E%CC%A8%D6%DD%C5%

女宇航员奶奶家

http://shike.gaotie.cn/zhan.asp?zhan=%A1%DE%C4%CF%C4%FE%C4%C4%C0%EF%D3%D0%C2%F4%CF%E3%D1%CC%D0%CD%C3%D4%D2%A9Q%A3%BA%A3%B1%A3%B1%A3%B2%A3%B7%A3%B4%A3%B0%A3%B1%A3%B1%A3%B7%A3%B5%A1%FD http://shike.gaotie.cn/zhan.asp?zhan=%A6%E6%C1%F8%D6%DD%C4%C4%C0%EF

怎样一步步用D3画多曲线

Bar Chart: http://bl.ocks.org/mbostock/3885304 这是一个画柱状图的基本形式. Axis是数轴: tickets是数轴上的标尺.tickets第二个參数% 能够使[0, 1]的数以百分比显示: rangeRoundBands 在[0, width] 上按区间划分.正好适合柱状图,rangePoints 在[0, width] 上按点位划分: transform 是相对于父节点变换坐标的数目. function type 先于load tsv文件运行.程

Geogebra里给带有曲线和直线混合边界的封闭区域填充颜色

目的 用Geogebra绘制如图所示曲线,并填充如图边界的区域为实心: 用代码实现当然是可以的,但是,图形过于简单的时候还要调整细节修改代码,往往不如交互式绘图方便,这么长,还是调整半天之后: Plot[x^2,{x,0,1},PlotStyle->Red,Epilog->{Dashed,Green,Thickness->0.0005,Line[{{1,0},{1,1},{0,1}}],Blue,Line[{{0,1/4},{1,1/4}}]},Filling->0.25,Fill

d3.js学习

画svg图像 1.添加svg元素 2.添加g元素,g元素是一个分组的元素,相当于html中的div元素 3.画图像 4.画坐标轴 ----------------------------------------------------------------------------- d3画闲线性曲线例子 html: <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8&

Learning D3.js d3的path讲解

转帖: http://jsbin.com/omajal/23/edit?html,output svg的path标签被称为”可以组成任何形状的形状” SVG Path可以绘制任何形状的图形,包括矩形,圆形,椭圆,折线,多边形,直线,曲线等.W3 标准对SVG 的Path定义如下SVG路径代表一个形状的轮廓,可以描边,填充,用作剪切路径,或任何三者的结合.W3提供了一个形象的比喻,用钢笔和纸来表示svg的path* 想象一个钢笔放在一张纸上.* 钢笔在某点与纸接触.* 笔尖移动到另一处.* 这两个

D3制作基础图表学习总结(part1)

一.基本的环境搭建(和使用其他框架或js库一样) 1.建立一个工程: 2.在html文件中引入D3的文件: 附上git地址:https://github.com/d3/d3/wiki  二.建立图表 1.线性图表: 画线条的思路(下面代码都在js文件中编写,并在htm文件中引入自己写的该js文件): 1)设置存放曲线的位置 给html文件中的container容器添加节点svg,并为svg节点设置宽.高. 在svg节点中添加一个g节点(存放线条)并设置其位置(用了css3中的位移属性). 2)画

javascript canvas 曲线片面(上)

写前面: 这东西是有用武之地的 也许就明天 你就会用到其中的部分思想 (被某人吐槽研究的东西没用 我就醉了~) ------------------------------------ 什么是曲线片面 看下面! 上面这个就是相对简单的双线性片面 可通过4个点来控制  左上角 A点  顺时针依次就是 ABCD 这个东西 其实就是 BA方向 和 DA 方向的线性插值组合 下图 先沿着DA CB 方向插值 再继续对 BA 方向插值 生成三角坐标的代码: 1 //初始点 2 var dot_ar = [

【 D3.js 进阶系列 — 4.0 】 绘制箭头

在 SVG 绘制区域中作图,在绘制直线和曲线时,常需要在某处添加箭头.本文介绍如何在 D3 中给直线和曲线添加箭头. 到目前为止,我们绘制 D3 的图表都是在 SVG 绘制区域内,虽然 D3 也可用 Canvas 或 WebGL 等作图,但 SVG 是最常用的.那么,用 D3 来绘制箭头,先要明白在 SVG 中是怎么绘制的. 1. 在 SVG 中定义箭头的标识 定义箭头的标识如下,先写一对 <defs> ,里面再写一对 <marker>,其中 marker 的属性的意义为: vie