d3 javascript系列图表

时间:2017-03-28 02:26:39

标签: javascript d3.js series

enter image description here

我正在尝试创建这个特定的d3应用程序,其中可以像这样动态显示一系列数据。每个段包含两个数据。

第一步是打印圆圈,使系列之间有足够的空间,但最大的圆圈总是在较小的圆圈下。

// 版本3 - 包含正确的标签和图例 http://jsfiddle.net/0ht35rpb/33/

// ******版本2小提琴****** http://jsfiddle.net/1oka61mL/10/

enter image description here

- 如何正确设置对角线标签 - 相同角度,正确对齐? - 添加传奇? - 以相反的颜色掩盖底部指针然后以不同的颜色继续线?

// ******最新Jsfiddle ****** http://jsfiddle.net/0ht35rpb/26/

var width = 600;
var height = 400;
var svg = d3.select('svg').attr("width", width).attr("height", height);

//Count
//Checkins
//Popularity

var data = [{
  "name": "Twitter",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 200
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 1000
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 30
  }]
}, {
  "name": "Facebook",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 500
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 300
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 740
  }]
}, {
  "name": "Ebay",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 4000
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 1000
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 40
  }]
}, {
  "name": "Foursquare",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 2000
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 3000
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 4500
  }]
}];


var outerRadius = [];
// organise the data. 
// Insert indices and sort items in each series
// keep a running total of max circle size in each series
// for later positioning
var x = 0;
var totalWidth = d3.sum(
  data.map(function(series) {
    series.items.forEach(function(item, i) {
      item.index = i;
    });
    series.items.sort(function(a, b) {
      return b.value - a.value;
    });
    var maxr = Math.sqrt(series.items[0].value);
    outerRadius.push(maxr);
    x += maxr;
    series.xcentre = x;
    x += maxr;
    return maxr * 2;
  })
);

// make scales for position and colour
var scale = d3.scale.linear().domain([0, totalWidth]).range([0, width]);
//var colScale = d3.scale.category10();

function colores_google(n) {
  var colores_g = ["#f7b363", "#448875", "#c12f39", "#2b2d39", "#f8dd2f"];
  return colores_g[n % colores_g.length];
}


// add a group per series, position the group according to the values and position scale  we calculated above
var groups = svg.selectAll("g").data(data);
groups.enter().append("g");
groups.attr("transform", function(d) {
  return ("translate(" + d.xcentre + ",0)");
});


// then add circles per series, biggest first as items are sorted
// colour according to index (the property we inserted previously so we can
// keep track of their original position in the series)
var circles = groups.selectAll("circle").data(function(d) {
  return d.items;
}, function(d) {
  return d.index;
});
circles.enter().append("circle").attr("cy", height / 2).attr("cx", 0);

circles
  .attr("r", function(d) {
    return Math.sqrt(d.value);
  })
  .style("fill", function(d) {
    return colores_google(d.index);
  });



var labelsgroups = svg.selectAll("text").data(data);
labelsgroups.enter().append("text");
labelsgroups
  .attr("y", function(d, i) {
    d.y = 300;
    d.cy = 200;
    return 300;
  })
  .attr("x", function(d) {
    d.x = d.xcentre;
    d.cx = d.xcentre;
    return d.xcentre;
  })
  .text(function(d) {
    return d.name;
  })
  .each(function(d) {
    var bbox = this.getBBox();
    d.sx = d.x - bbox.width / 2 - 2;
    d.ox = d.x + bbox.width / 2 + 2;
    d.sy = d.oy = d.y + 5;
  })
  .attr("text-anchor", "middle");



var pointersgroups = svg.selectAll("path.pointer").data(data);
pointersgroups.enter().append("path");
pointersgroups
  .attr("class", "pointer")
  .attr("marker-end", "url(#circ)");

pointersgroups
  .attr("d", function(d) {
    return "M" + (d.xcentre) + "," + (d.oy - 25) + "L" + (d.xcentre) + "," + (d.sy - 25) + " " + d.xcentre + "," + (d.cy);
  })



function fetchValue(items, label) {
  for (i = 0; i <= items.length; i++) {
    if (items[i].label == label) {
      return items[i].value;
    }
  }
}


function fetchRadius(items, label) {
  for (i = 0; i <= items.length; i++) {
    if (items[i].label == label) {
      return Math.sqrt(items[i].value);
    }
  }
}

/*
var labels1groups = svg.selectAll(".label1").data(data);
labels1groups.enter().append("text");
labels1groups
  .attr("class", "label1")
  .attr("y", function(d, i) {
    d.y = 100;
    d.cy = 100;
    return 100;
  })
  .attr("x", function(d) {
    d.x = d.xcentre;
    d.cx = d.xcentre+50;
    return d.xcentre+50;
  })
  .text(function(d) {
    return fetchValue(d.items, "Count");
  })
  .attr("transform", function(d, i) {
            return "translate(" + (15 * i) + "," + (i * 45) + ") rotate(-45)";

  })
  .each(function(d) {
    var bbox = this.getBBox();
    d.sx = d.x - bbox.width / 2 - 2;
    d.ox = d.x + bbox.width / 2 + 2;
    d.sy = d.oy = d.y ;
  })
  .attr("text-anchor", "left");

*/


var gridSize = 100;

var labels1groups = svg.selectAll(".label2")
  .data(data)
  .enter().append("text")
  .text(function(d) {
    return fetchValue(d.items, "Count");
    //return d; 
  })
  .attr("x", function(d, i) {

    d.x = i * gridSize + 50;
    d.cx = i * gridSize + 50;

    return i * gridSize;
  })
  .attr("y", function(d, i) {
    d.y = 105;
    d.cy = 50;
    return 0;
  })
  .attr("transform", function(d, i) {
    return "translate(" + gridSize / 2 + ", -6)" +
      "rotate(-45 " + ((i + 0.5) * gridSize) + " " + (-6) + ")";
  })
  .each(function(d) {
    var bbox = this.getBBox();
    d.sx = d.x - bbox.width / 2 - 2;
    d.ox = d.x + bbox.width / 2 + 2;
    d.sy = d.oy = d.y;
  })
  .style("text-anchor", "end")
  .attr("class", function(d, i) {
    return ((i >= 8 && i <= 16) ?
      "timeLabel mono axis axis-worktime" :
      "timeLabel mono axis");
  });




var pointers1groups = svg.selectAll("path.pointer1").data(data);
pointers1groups.enter().append("path");
pointers1groups
  .attr("class", "pointer1")
  .attr("marker-end", "url(#circ)");

pointers1groups
  .attr("d", function(d, i) {

    //d.y = outerRadius[i];
    //d.y = d.oy - d.cy;
    //fetchRadius(d.items, "Count");    

    //(d.xcentre+100)
    // + " " + d.cx + "," + d.cy

    //return "M "+ (d.xcentre) +" 25 ,L "+ dist +" 75";

    return "M" + (d.xcentre) + "," + (d.y + d.oy - fetchRadius(d.items, "Count") - 10) + "L" + (d.xcentre + 80) + "," + d.cy;


  })

//年长的Jsfiddle http://jsfiddle.net/59bunh8u/51/

var rawData = [{
    "name": "Twitter",
    "items" : [
        {
            "label" : "15 billion",
            "unit" : "per day",
            "value" : 1500
        },
        {
            "label" : "450 checkins",
            "unit" : "per day",
            "value" : 450
        }
    ]
}, 
{               
    "name": "Facebook",
    "items" : [
        {
            "label" : "5 billion",
            "unit" : "per day",
            "value" : 5000
        },
        {
            "label" : "2000 checkins",
            "unit" : "per day",
            "value" : 2000
        }
    ]
}];


$.each(rawData, function(index, value) {
    var total = 0;
    var layerSet = [];
    var ratios = [25, 100];

    $.each(value["items"], function(i, v) {
        total += v["value"];
    });

    value["total"] = total;
});



var w = $this.data("width");
var h = $this.data("height");

var el = $this;

var margin = {
    top: 65,
    right: 90,
    bottom: 5,
    left: 150
};

var svg = d3.select(el[0]).append("svg")
    .attr("class", "series")
    .attr("width", w + margin.left + margin.right)
    .attr("height", h + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var defs = svg.append("svg:defs");


$.each(rawData, function(i, v) {
    circleDraw(i, v["items"]);
});



//calculates where each element should be placed
function calculateDistance (d, i, items) {
    var dcx = 0;
    for (var k = 0; k < i; k++) {
      dcx += Math.sqrt(items[k].value);
    }
    return dcx + 10 * i;
}

function getPercentage(value, total) {
    return ((value / total) * 100);
}

function circleDraw(index, data){
    data.sort(function(a, b) {
        return parseFloat(b.value) - parseFloat(a.value);
    });

    var circlelayer = svg.append("g")
      .attr("class", "circlelayer");

    var circle = circlelayer.selectAll("circle")
      .data(data);

    circle.enter().append("circle")
        .attr("class", function(d, i) {
            if (i == 0) {
              return "blue";
            }
            return "gold";
        })
        .attr("cy", 60)
        .attr("cx", function(d, i) {
            return calculateDistance(d, index, data);
        })
        .attr("r", function(d, i) {
            return Math.sqrt(d.value);
        });

    circle.exit().remove();
}

2 个答案:

答案 0 :(得分:0)

以下是绘制线条的方法:

float[] results = new float[1];
Location.distanceBetween(currentlatitude, currentlongitude, originLat, originLon, results);
float distanceInMeters = results[0];

更新了jsfiddle

答案 1 :(得分:0)

enter image description here

我设法将对角线标记和指针对齐,指向正确的圆形颜色来表示该组。我很想对这个图表进行微调,并且可以更好地控制填充和图表宽度/高度参数。该图表看起来很稳定,但会热衷于使用不同的值和大小的数据集进行测试。

/ <强>最新 / http://jsfiddle.net/0ht35rpb/33/

var width = 760;
var height = 400;

var svg = d3.select('#serieschart')
  .append("svg:svg")
  .attr("width", width)
  .attr("height", height);

//Count
//Checkins
//Popularity

var data = [{
  "name": "Twitter",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 200
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 1000
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 30
  }]
}, {
  "name": "Facebook",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 500
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 300
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 740
  }]
}, {
  "name": "Ebay",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 4000
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 1000
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 40
  }]
}, {
  "name": "Foursquare",
  "items": [{
    "id": 0,
    "label": "Count",
    "value": 2000
  }, {
    "id": 1,
    "label": "Checkins",
    "value": 3000
  }, {
    "id": 2,
    "label": "Popularity",
    "value": 4500
  }]
}];



var legend_group = svg.append("g")
  .attr("class", "legend")
  .attr("width", 80)
  .attr("height", 100)
  .append("svg:g")
  .attr("class", "legendsection")
  .attr("transform", "translate(0,30)");

var legend = legend_group.selectAll("circle").data(data[0].items);

legend.enter().append("circle")
  .attr("cx", 70)
  .attr("cy", function(d, i) {
    return 15 * i;
  })
  .attr("r", 7)
  .attr("width", 18)
  .attr("height", 18)
  .style("fill", function(d, i) {
    return colores_google(i);
  });

legend.exit().remove();





var legendtext = legend_group.selectAll("text").data(data[0].items);

legendtext.enter().append("text")
  .attr("class", "labels")
  .attr("dy", function(d, i) {
    return 15 * i;
  })
  .attr("text-anchor", function(d) {
    return "start";
  })
  .text(function(d) {
    return d.label;
  });

legendtext.exit().remove();

var m = [80, 20, 20, 10];
var w =+ width - m[0];
var h =+ height - m[1];

var chart = svg.append("g")
  .attr("class", "serieschart")
  .attr("width", w)
  .attr("height", h);

var outerRadius = [];
// organise the data. 
// Insert indices and sort items in each series
// keep a running total of max circle size in each series
// for later positioning
var x = 0;
var totalWidth = d3.sum(
  data.map(function(series) {
    series.items.forEach(function(item, i) {
      item.index = i;
    });
    series.items.sort(function(a, b) {
      return b.value - a.value;
    });
    var maxr = Math.sqrt(series.items[0].value);
    outerRadius.push(maxr);
    x += maxr;
    series.xcentre = x;
    x += maxr;
    return maxr * 2;
  })
);

// make scales for position and colour
var scale = d3.scale.linear().domain([0, totalWidth]).range([0, w]);
//var colScale = d3.scale.category10();

function colores_google(n) {
  var colores_g = ["#f7b363", "#448875", "#c12f39", "#2b2d39", "#f8dd2f"];
  return colores_g[n % colores_g.length];
}

function fetchValue(items, label) {
  for (i = 0; i <= items.length; i++) {
    if (items[i].label == label) {
      return items[i].value;
    }
  }
}

function fetchRadius(items, label) {
  for (i = 0; i <= items.length; i++) {
    if (items[i].label == label) {
      return Math.sqrt(items[i].value);
    }
  }
}


// add a group per series, position the group according to the values and position scale  we calculated above
var groups = chart.selectAll("g.seriesGroup").data(data);
var newGroups = groups.enter().append("g").attr("class", "seriesGroup");
newGroups.append("text")
  .attr("class", "seriesName")
  .attr("text-anchor", "middle");
newGroups.append("line")
  .attr("class", "seriesName")
  .attr("y1", h - 40)
  .attr("y2", h / 2);
newGroups.append("text")
  .attr("class", "datumValue")
  .attr("y", 10)
  //.attr("transform", "rotate(-45)")
;
newGroups.append("g").attr("class", "circleGroup");
newGroups.append("g").attr("class", "datumLine")
  .append("line")
  .attr("class", "datumValue")
  .attr("y2", 40);

var focus = "Count";
groups.attr("transform", function(d) {
  return "translate(" + scale(d.xcentre) + ",0)";
});

groups.select("text.seriesName")
  .text(function(d) {
    return d.name;
  })
  .attr("y", h - 20);

groups.select("text.datumValue")
  .text(function(d) {
    return fetchValue(d.items, focus);
  })
  .attr("transform", function(d) {
    return "translate(" + ((h / 2) - 20 - scale(fetchRadius(d.items, focus))) + ",20) rotate(-45)";
  });

groups.select("line.datumValue")
  .attr("y1", function(d) {
    return (h / 2) - scale(fetchRadius(d.items, focus));
  })
  .attr("x2", function(d) {
    return (h / 2) - scale(fetchRadius(d.items, focus) + 20);
  });

// then add circles per series, biggest first as items are sorted
// colour according to index (the property we inserted previously so we can
// keep track of their original position in the series)
var circles = groups
  .select(".circleGroup")
  .selectAll("circle").data(function(d) {
    return d.items;
  }, function(d) {
    return d.index;
  });
circles.enter().append("circle").attr("cy", h / 2).attr("cx", 0);

circles
  .attr("r", function(d) {
    return scale(Math.sqrt(d.value));
  })
  .style("fill", function(d) {
    return colores_google(d.index);
  });