如何利用d3.js绘制一条有多个节点的线段?

发布于 2022-09-07 22:40:54 字数 252 浏览 21 评论 0

clipboard.png
想利用D3.JS实现上图的效果,对应选择时间段展示其他数据。
但是因为第一次用D3,不太清楚该选择什么样的布局。
看了相关的文档,首先想到的是只有一条分枝的树布局,
但是因为给出的时间段并不是固定的,树节点的children要根据后台传值动态生成,很不方便。
有没有什么布局比较适合这种需求呢?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

洒一地阳光 2022-09-14 22:40:54

花了两天啃了一点D3.JS的书,
基本实现过程就是绘制画布,在画布中确定各个点的位置,然后利用线段生成器连线,在各个点上添加p和text标签,绘制原点,加入日期和xxxx内容。

// dataset格式
var dataset = [{
    {
        count: 0,
        data: [
            {
                fieldValue: ''
            },
            {
                fieldValue: ''
            },
            {
                fieldValue" ''
            },
            ...
        ],
        time: ''
    }]


// 绘制画布
var svg = d3.select("#relevanceRuleConfig").append("svg")
        .attr('id','PathId')  
        .attr("width", function(){
            if(dataset.length > 6 ){
                return (80 + dataset.length * 150);        // 元素过多超出画布时修改画布长度
            }else{
                return 960;                                // 画布默认宽度
            }
        })
        .attr("height", height-80)  
        .append("g")

// 线段点的数据
var lines = [];
var x = 60;
var y = 180;
for(var index in dataset){
    lines.push([x,y]);
    x += 150;        // 点与点之间间隔150px
}

// 创建线段生成器
var linePath = d3.svg.line();

// 添加路径
svg.append('path')
        .attr('d', linePath(lines))        // 使用了线段生成器
        .attr('stroke', '#666')
        .attr('stroke-width', '1px')
        .attr('fill', 'none');
                        
var addNode = function(i){
    var self = this;
    var nodeData = [dataset[i]];
    var siteSave = [];
    var node = svg.selectAll()
    .data(nodeData)
    .enter()
    .append('g')
    .attr('transform',function(d){
        var x = 60 + 150 * i;
        var y = 180;
        return 'translate(' + x + ',' + y +')'
    })

    // 添加节点图标  
    node.append("circle")
        .attr("r", 5)
        .attr('fill','#f4952d');

    // 添加日期文本
    node.append("text")
        .attr("dx", -30)        //定义文本显示x轴偏移量  
        .attr("dy", function(d){ return i%2?-42:50})        //定义文本显示y轴偏移量  
        .attr('fill','#f4952d')
        .style("text-anchor", 'start')//文字对齐显示
        .style('font-family','Times New Roman')
        .text(function(d) { return d.date; });
                    
    // 添加日期外矩形
    node.append("rect")
        .attr('width',85)
        .attr('height',25)
        .attr("x", -40)        //定义矩形x轴偏移量  
        .attr("y", function(d){ return i%2?-60:31})        //定义矩形y轴偏移量
        .attr("rx", 5)        //圆角  
        .attr("ry",5)        //圆角
        .attr('fill','none')
        .attr("stroke", '#f4952d')

    for(var j in nodeData[0].name){
        //显示前五家媒体
        node.append("text")
            .attr("dx", -30)
            .attr("dy", function(d){
                if(!(i%2)){
                    if(d.count > 5){
                        return -60 + -25 * j;
                    }else{
                        return -15 - 25 * j;
                    }
                }else{
                    return 25 + 25*j;
                }
            })
            .attr('class','siteName')
            .attr('value',function(d){ return d.date})
            .attr('class',function(d){ return d.date})
            .style("text-anchor", 'start')        //文字对齐显示  
            .text(function(d) { return d.name[j]; })
            //这两个交互事件是用于将同一天的所有网站统一样式的,如果之后需要每个网站单独添加点击事件可以直接删除
            .on('mouseover',function(){
                var className = $(this).attr("value");
                $('.' + className).css({'font-size':'16px','fill':'#f4952d','cursor':'pointer','transition':'all 0.5s ease','-moz-transition': 'all 0.5s ease','-webkit-transition':' all 0.5s ease','-o-transition':'all 0.5s ease'})
            })
            .on('mouseout',function(){
                var className = $(this).attr("value");
                $('.' + className).css({'font-size':'14px','fill':'#333','transition':'all 0.2s ease','-moz-transition': 'all 0.2s ease','-webkit-transition':' all 0.2s ease','-o-transition':'all 0.2s ease'})
            })
            .on('click',getData);
    }

    if(nodeData[0].count == 0){
        node.append("text")
            .attr("dx", -25)
            .attr("dy",function(){
                if(!(i%2)){
                    return -15;
                }else{
                    return 25;
                }
            })
            .text('暂无数据')
            .style('fill','#999')
            .style('font-size','14px')
            .style('font-family','Microsoft Yahei')
    }

    if(nodeData[0].count > 5){
        // 媒体大于五家加入“...”
        node.append("text")
            .attr("dx", -30)
            .attr("dy", function(d){
                if(!(i%2)){
                    return -40;
                }else{
                    return 145;
                }
            })
            .attr('value',function(d){ return d.date})
            .attr('class',function(d){ return d.date})
            .style("text-anchor", 'start')//文字对齐显示  
            .text('...')
            .on('click',getData);
                            
        // 显示媒体参与数量
        node.append("text")
            .attr("dx", -30)
            .attr("dy", function(d){
                if(!(i%2)){
                    return -15;
                }else{
                    return 170;
                }
            })
            .attr('fill','#666')
            .attr('class','mediaJoin')
            .attr('value',function(d){ return d.date})
            .style("text-anchor", 'start')//文字对齐显示  
            .text(function(d) {  return ('共' + d.count + '家媒体参与'); })
            .on('click',getData);
    }

}
for(var index in dataset){
    addNode(index)
}
if (dataset.length == 1){
    svg.attr('transform','translate(400,0)')
}else if (dataset.length == 2){
    svg.attr('transform','translate(320,0)')
}else if (dataset.length == 3){
    svg.attr('transform','translate(240,0)')
}else if (dataset.length == 4){
    svg.attr('transform','translate(160,0)')
}else if (dataset.length == 5){
    svg.attr('transform','translate(80,0)')
}else{
    svg.attr('transform','translate(0,0)')
}

clipboard.png

这是最后实现的鱼骨图效果

起风了 2022-09-14 22:40:54

@StupidBear 我想问一下,如果有的节点还有子节点,最后画的如同一棵树一样,你知道怎么写代码码?谢谢

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文