How Can I Use Symbols With a Legend

2019-06-11 03:16发布

I've got a legend, with colored rectangles...

enter image description here

I'd like to replace the rectangles with symbols (i.e., circle, cross, diamond, square). I can't figure out how to do that.

I've been using variations of .attr("d", d3.svg.symbol().type('circle'). For instance, I tried:

        legendRect
            .attr("d", d3.svg.symbol().type(function (d) { return d[2] })

and I tried:

        legendRect.append("svg:path")
            .attr("d", d3.svg.symbol().type((d: any) => { return d[2] }))

d[2] is "supposed to be" pulling from legendData, as shown in the below code example...like it does with d[1] for the fill.

But I don't ever see anything change.

Here's the code I'm using for the legend, without the symbol stuff, below. What am I doing wrong and how can I change the rectangles to symbols? Where do I need to add what?

        var legendData = [["OA", "yellow", "circle"], ["OI", "blue", "cross"], ["RARC", "green", "diamond"], ["CAPE", "red", "square"], ["Other", "black", "triangleDown"]];

        var legend = this.svg.append("g")
            .attr("class", "legend")
            .attr("height", 0)
            .attr("width", 0)
            .attr('transform', 'translate(-20,250)');

        var legendRect = legend.selectAll('rect').data(legendData);

        legendRect.enter()
            .append("rect")
            .attr("x", width - 65)
            .attr("width", 10)
            .attr("height", 10)
            ;

        legendRect
            .attr("y", function (d, i) {
                return i * 20;
            })
            .style("fill", function (d) {
                return d[1];
            })

        var legendText = legend.selectAll('text').data(legendData);

        legendText.enter()
            .append("text")
            .attr("x", width - 52);

        legendText
            .attr("y", function (d, i) {
                return i * 20 + 9;
            })
            .text(function (d) {
                return d[0];
            });

标签: d3.js svg
3条回答
狗以群分
2楼-- · 2019-06-11 03:37

Here's how I would code it. Notice, that I data-bind to a wrapper g element and then place the symbol and text into it for each legend item. You can then position the g instead of positioning the text and "symbol" separately. This also removes the need for double-binding the data.

var legendData = [["OA", "yellow", "circle"], ["OI", "blue", "cross"], ["RARC", "green", "diamond"], ["CAPE", "red", "square"], ["Other", "black", "triangleDown"]];

var svg = d3.select('body').append('svg').attr('width', 500).attr('height', 500);

var legend = svg.append('g')
    .attr("class", "legend")
    .attr("height", 0)
    .attr("width", 0)
    .attr('transform', 'translate(20,20)');

var legendRect = legend
    .selectAll('g')
    .data(legendData);

var legendRectE = legendRect.enter()
    .append("g")
    .attr("transform", function(d,i){
      return 'translate(0, ' + (i * 20) + ')';
    });
    
legendRectE
    .append('path')
    .attr("d", d3.svg.symbol().type((d) => { return d[2] })) 
    .style("fill", function (d) {
        return d[1];
    });

legendRectE
    .append("text")
    .attr("x", 10)
    .attr("y", 5)
    .text(function (d) {
        return d[0];
    });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

查看更多
干净又极端
3楼-- · 2019-06-11 03:38

For adding image icons, you can use below code.

legend.append("**image**")
        .attr("x", 890)
        .attr("y", 70)
        .attr("width", 20)
        .attr("height", 18)
        .attr("xlink:href",function (d) {
            **return "../assets/images/dev/"+d+".png";**
        })

This works for me..

查看更多
时光不老,我们不散
4楼-- · 2019-06-11 03:47

This is a implementation which uses symbols for your legend. You can use the symbols like the following:

   svg.selectAll('.symbol')
     .data(legendData)
     .enter()
     .append('path')
     .attr('transform', function(d, i) {
       return 'translate(' + (20) + ',' + ((i * 20) + 10) + ')';
     })
     .attr('d', d3.symbol().type(function(d, i) {
         if (d[2] === "circle") {
           return d3.symbolCircle;
         } else if (d[2] === "cross") {
           return d3.symbolCross;
         } else if (d[2] === "diamond") {
           return d3.symbolDiamond;
         } else if (d[2] === "square") {
           return d3.symbolSquare;
         } else {
           return d3.symbolTriangle;
         }
       })
       .size(100))
     .style("fill", function(d) {
       return d[1];
     });

Then you can set your legend labels like the following:

   svg.selectAll('.label')
     .data(legendData)
     .enter()
     .append('text')
     .attr("x", "40")
     .attr("y", function(d, i){ return ((i * 20)+15);})
     .text(function(d) {
       return d[0];
     });

Check fiddle here - https://jsfiddle.net/zoxckLe3/

P.S. - Above solution uses d3 v4. To achieve the same in v3, use the following line .attr('d', d3.svg.symbol().type(function(d){return d[2];})) instead of the part where I match d[2] to the symbol name.

查看更多
登录 后发表回答