Fill not working with areaRadial() generated shape - d3.js
I'm currently working on a thing which is supposed to look like a lava lamp later. Unfortunately, I'm already failing at the beginning:
I managed to create randomly generated blobs, but I just can't apply a fill. The stroke works just fine.
here is the relevant code which creates the blobs:
var ctx = this; // context
this.path = d3.areaRadial()
.angle(function(d) {return d.theta})
.radius(function(d) {return d.r})
.curve(d3.curveCatmullRomClosed.alpha(1));
// create the blob
this.create = function() {
var anchors = [];
for (var i = 0; i < ctx.options.anchors; i++) {
var currTheta = i * (360 / ctx.options.anchors) + rand(ctx.options.spread.theta);
var currRadians = Math.radians(currTheta);
var currRadius = ctx.options.radius + rand(ctx.options.spread.r);
anchors.push({theta: currRadians, r: currRadius});
}
var pathData = ctx.path(anchors);
d3.select(ctx.options.target).append('path')
.attr('d', pathData)
.attr('class', 'blob')
.style('opacity', ctx.options.opacity)
.style('transform', 'translate(' + ctx.x + 'px, ' + ctx.y + 'px)')
.attr('transform', 'translate(' + ctx.x + 'px, ' + ctx.y + 'px)');
console.log(pathData);
}
function rand(x) // creates a random number between -0.5 * x and 0.5 * x
Full code: https://codepen.io/normanwink/pen/BrMVrE
Thanks!
That's the expected behaviour, since you're using radius, which is:
Equivalent to area.y, except the accessor returns the radius: the distance from the origin ⟨0,0⟩.
And for area.y:
If y is specified, sets y0 to y and y1 to null and returns this area generator. If y is not specified, returns the current y0 accessor. (emphasis mine)
Therefore, you probably want outerRadius here.
this.path = d3.areaRadial()
.angle(function(d) {
return d.theta
})
.outerRadius(function(d) {
return d.r
})
.curve(d3.curveCatmullRomClosed.alpha(1));
This is your code with that change only:
(function() {
"use strict";
// window size
var windowX = window.innerWidth;
var windowY = window.innerHeight;
var svgX = windowX;
var svgY = windowY;
var blobCount = 1;
function init() {
// console.log(new Blob());
var svg = d3.select('#svg')
.attr('viewBox', '0 0 ' + svgX + ' ' + svgY)
.attr('preserveAspectRatio', 'xMinYMin meet');
for (var i = 0; i < blobCount; i++) {
var newBlob = new Blob(svgX * 0.5, svgY * 0.5);
}
}
function Blob(x, y) {
var ctx = this; // context
this.options = {
anchors: 8,
breathe: 30,
fill: '#ffffff',
opacity: 0.5,
radius: 150,
spread: {
theta: 10, // angle
r: 300 // radius
},
target: '#svg',
};
this.x = x || 0;
this.y = y || 0;
this.path = d3.areaRadial()
.angle(function(d) {return d.theta})
.outerRadius(function(d) {return d.r})
.curve(d3.curveCatmullRomClosed.alpha(1));
// create the blob
this.create = function() {
var anchors = [];
for (var i = 0; i < ctx.options.anchors; i++) {
var currTheta = i * (360 / ctx.options.anchors) + rand(ctx.options.spread.theta);
var currRadians = Math.radians(currTheta);
var currRadius = ctx.options.radius + rand(ctx.options.spread.r);
anchors.push({theta: currRadians, r: currRadius});
}
var pathData = ctx.path(anchors);
d3.select(ctx.options.target).append('path')
.attr('d', pathData)
.attr('class', 'blob')
.style('opacity', ctx.options.opacity)
.style('transform', 'translate(' + ctx.x + 'px, ' + ctx.y + 'px)')
.attr('transform', 'translate(' + ctx.x + 'px, ' + ctx.y + 'px)');
}
// update position and anchor movement
this.update = function() {
}
// apply changes
this.render = function() {
}
this.create();
}
function rand(i) {
return (Math.random()-0.5) * (i || 1);
}
Math.radians = function(degrees) {
return degrees * Math.PI / 180;
};
// init when ready
init();
})();
#svg {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.blob {
fill: blue; /* why is this not working? */
stroke: red;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg id="svg"></svg>
Your problem is your pathData , because if you replace your .attr('d', pathData) with .attr('d', 'M37,17v15H14V17z M50,0H0v50h50z') which is a valid path, your fill is working properly.
I will continue searching the issue, just want to give you a hint, maybe you will find the issue faster then me. :)
Related
D3 x3dom - 3d scatter plot
I'm trying to reproduce an 3d-ScatterPlot using the d3 library. The example is written in v3 and I'm having difficulties to recreate it in v5. The issue is that the axis don't get drawn. function drawAxis( axisIndex, key, duration ) { var scale = d3.scaleLinear() .domain( [-5,5] ) // demo data range .range( axisRange ) scales[axisIndex] = scale; var numTicks = 8; var tickSize = 0.1; var tickFontSize = 0.5; // ticks along each axis var ticks = scene.selectAll( "."+axisName("Tick", axisIndex) ) .data( scale.ticks( numTicks )); var newTicks = ticks.enter() .append("transform") .attr("class", axisName("Tick", axisIndex)); newTicks.append("shape").call(makeSolid) .append("box") .attr("size", tickSize + " " + tickSize + " " + tickSize); // enter + update ticks.attr("translation", function(tick) { return constVecWithAxisValue( 0, scale(tick), axisIndex ); }) ticks.exit().remove(); // tick labels var tickLabels = ticks.selectAll("billboard shape text") .data(function(d) { return [d]; }); var newTickLabels = tickLabels.enter() .append("billboard") .attr("axisOfRotation", "0 0 0") .append("shape") .call(makeSolid) newTickLabels.append("text") .attr("string", scale.tickFormat(10)) .attr("solid", "true") .append("fontstyle") .attr("size", tickFontSize) .attr("family", "SANS") .attr("justify", "END MIDDLE" ); tickLabels // enter + update .attr("string", scale.tickFormat(10)) tickLabels.exit().remove(); // base grid lines if (axisIndex==0 || axisIndex==2) { var gridLines = scene.selectAll( "."+axisName("GridLine", axisIndex)) .data(scale.ticks( numTicks )); gridLines.exit().remove(); var newGridLines = gridLines.enter() .append("transform") .attr("class", axisName("GridLine", axisIndex)) .attr("rotation", axisIndex==0 ? [0,1,0, -Math.PI/2] : [0,0,0,0]) .append("shape") newGridLines.append("appearance") .append("material") .attr("emissiveColor", "gray") newGridLines.append("polyline2d"); gridLines.selectAll("shape polyline2d").attr("lineSegments", "0 0, " + axisRange[1] + " 0") gridLines.attr("translation", axisIndex==0 ? function(d) { return scale(d) + " 0 0"; } : function(d) { return "0 0 " + scale(d); } ) } } My guess is that the issue is in this method. I created a full example here: https://codepen.io/anon/pen/aevWQX Thanks for your help!
From v4 onward, you need to .merge() your newly added .enter() selection and your existing selection, otherwise the result is an empty selection - which is why the code was executed, only not applied to any elements. var x3d = d3.select("#divPlot") .append("x3d") .style("width", "500px") .style("height", "500px") .style("border", "none") var scene = x3d.append("scene") scene.append("orthoviewpoint") .attr("centerOfRotation", [5, 5, 5]) .attr("fieldOfView", [-5, -5, 15, 15]) .attr("orientation", [-0.5, 1, 0.2, 1.12 * Math.PI / 4]) .attr("position", [8, 4, 15]) var rows = initializeDataGrid(); var axisRange = [0, 10]; var scales = []; var initialDuration = 0; var defaultDuration = 800; var ease = 'linear'; var time = 0; var axisKeys = ["x", "y", "z"] // Helper functions for initializeAxis() and drawAxis() function axisName(name, axisIndex) { return ['x', 'y', 'z'][axisIndex] + name; } function constVecWithAxisValue(otherValue, axisValue, axisIndex) { var result = [otherValue, otherValue, otherValue]; result[axisIndex] = axisValue; return result; } // Used to make 2d elements visible function makeSolid(selection, color) { selection.append("appearance") .append("material") .attr("diffuseColor", color || "black") return selection; } // Initialize the axes lines and labels. function initializePlot() { initializeAxis(0); initializeAxis(1); initializeAxis(2); } function initializeAxis(axisIndex) { var key = axisKeys[axisIndex]; drawAxis(axisIndex, key, initialDuration); var scaleMin = axisRange[0]; var scaleMax = axisRange[1]; // the axis line var newAxisLine = scene.append("transform") .attr("class", axisName("Axis", axisIndex)) .attr("rotation", ([ [0, 0, 0, 0], [0, 0, 1, Math.PI / 2], [0, 1, 0, -Math.PI / 2] ][axisIndex])) .append("shape") newAxisLine .append("appearance") .append("material") .attr("emissiveColor", "lightgray") newAxisLine .append("polyline2d") // Line drawn along y axis does not render in Firefox, so draw one // along the x axis instead and rotate it (above). .attr("lineSegments", "0 0," + scaleMax + " 0") // axis labels var newAxisLabel = scene.append("transform") .attr("class", axisName("AxisLabel", axisIndex)) .attr("translation", constVecWithAxisValue(0, scaleMin + 1.1 * (scaleMax - scaleMin), axisIndex)) var newAxisLabelShape = newAxisLabel .append("billboard") .attr("axisOfRotation", "0 0 0") // face viewer .append("shape") .call(makeSolid) var labelFontSize = 0.6; newAxisLabelShape .append("text") .attr("class", axisName("AxisLabelText", axisIndex)) .attr("solid", "true") .attr("string", key) .append("fontstyle") .attr("size", labelFontSize) .attr("family", "SANS") .attr("justify", "END MIDDLE") } // Assign key to axis, creating or updating its ticks, grid lines, and labels. function drawAxis(axisIndex, key, duration) { var scale = d3.scaleLinear() .domain([-5, 5]) // demo data range .range(axisRange) scales[axisIndex] = scale; var numTicks = 8; var tickSize = 0.1; var tickFontSize = 0.5; // ticks along each axis var ticks = scene.selectAll("." + axisName("Tick", axisIndex)) .data(scale.ticks(numTicks)); var newTicks = ticks.enter() .append("transform") .attr("class", axisName("Tick", axisIndex)); newTicks.append("shape").call(makeSolid) .append("box") .attr("size", tickSize + " " + tickSize + " " + tickSize); // enter + update ticks.attr("translation", function(tick) { return constVecWithAxisValue(0, scale(tick), axisIndex); }) ticks.exit().remove(); // tick labels var tickLabels = ticks.selectAll("billboard shape text") .data(function(d) { return [d]; }); var newTickLabels = tickLabels.enter() .append("billboard") .attr("axisOfRotation", "0 0 0") .append("shape") .call(makeSolid) newTickLabels.append("text") .attr("string", scale.tickFormat(10)) .attr("solid", "true") .append("fontstyle") .attr("size", tickFontSize) .attr("family", "SANS") .attr("justify", "END MIDDLE"); tickLabels // enter + update .attr("string", scale.tickFormat(10)) tickLabels.exit().remove(); // base grid lines if (axisIndex == 0 || axisIndex == 2) { debugger; var gridLines = scene.selectAll("." + axisName("GridLine", axisIndex)) .data(scale.ticks(numTicks)); gridLines.exit().remove(); var newGridLines = gridLines.enter() .append("transform") .attr("class", axisName("GridLine", axisIndex)) .attr("rotation", axisIndex == 0 ? [0, 1, 0, -Math.PI / 2] : [0, 0, 0, 0]) .append("shape") newGridLines.append("appearance") .append("material") .attr("emissiveColor", "gray") newGridLines.append("polyline2d"); gridLines = newGridLines .merge(gridLines); gridLines.selectAll("shape polyline2d").attr("lineSegments", "0 0, " + axisRange[1] + " 0") gridLines.attr("translation", axisIndex == 0 ? function(d) { return scale(d) + " 0 0"; } : function(d) { return "0 0 " + scale(d); } ) } } // Update the data points (spheres) and stems. function plotData(duration) { if (!rows) { console.log("no rows to plot.") return; } var x = scales[0], y = scales[1], z = scales[2]; var sphereRadius = 0.2; // Draw a sphere at each x,y,z coordinate. var datapoints = scene.selectAll(".datapoint").data(rows); datapoints.exit().remove() var newDatapoints = datapoints.enter() .append("transform") .attr("class", "datapoint") .attr("scale", [sphereRadius, sphereRadius, sphereRadius]) .append("shape"); newDatapoints .append("appearance") .append("material"); newDatapoints .append("sphere") // Does not work on Chrome; use transform instead //.attr("radius", sphereRadius) datapoints.selectAll("shape appearance material") .attr("diffuseColor", 'steelblue') datapoints.transition().ease(d3.easeLinear).duration(duration) .attr("translation", function(row) { return x(row[axisKeys[0]]) + " " + y(row[axisKeys[1]]) + " " + z(row[axisKeys[2]]) }) } function initializeDataGrid() { var rows = []; // Follow the convention where y(x,z) is elevation. for (var x = -5; x <= 5; x += 1) { for (var z = -5; z <= 5; z += 1) { rows.push({ x: x, y: 0, z: z }); } } return rows; } function updateData() { time += Math.PI / 8; if (x3d.node() && x3d.node().runtime) { for (var r = 0; r < rows.length; ++r) { var x = rows[r].x; var z = rows[r].z; rows[r].y = 5 * (Math.sin(0.5 * x + time) * Math.cos(0.25 * z + time)); } plotData(defaultDuration); } else { console.log('x3d not ready.'); } } initializeDataGrid(); initializePlot(); setInterval(updateData, defaultDuration); .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } .axis text { font: 10px sans-serif; } <html> <head> <meta http-equiv="X-UA-Compatible" content="chrome=1" /> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <title>3D Scatter Plot</title> <!--<script type="text/javascript" src="http://d3js.org/d3.v5.min.js"></script>--> <script type="text/javascript" src="http://d3js.org/d3.v5.js"></script> <script type="text/javascript" src="http://x3dom.org/x3dom/dist/x3dom-full.js"></script> <link rel="stylesheet" type="text/css" href="http://www.x3dom.org/download/dev/x3dom.css" /> </head> <body> <div id="divPlot" style="width: 500px; height: 500px;"></div> </body> </html> The only change I made is the call to .merge somewhere inside the if statement in drawAxis. Hope this helps!
Unable to see charts for the d3 code. Error in console 't.apply is not a function'
I am trying to use crossfilter.js and d3.js to generate brushes and charts to filter my data. The dates are in the format "2019-04-08T09:07:22.512Z" . I tried different ways to parse through the date and to generate the charts but am unable to do so . I get the following error in the console 't.apply is not a function'. Looking at the error I presume there is a problem with the render and renderAll functions. d3 version 5.7.0 var cf = crossfilter(json); var all = cf.groupAll(); var byAlertType = cf.dimension(function(p) {return p['alertType'];}); var byDate = cf.dimension(function (p) { return p['created'].substring(0,10);}); var byHour = cf.dimension(function (p) { return p['created'].substring(11,13);}); var byTimezone = cf.dimension(function (p) { return p['created'].substring(30,39);}); var groupByAlertType = byAlertType.group(); var groupByDate = byDate.group(); var groupByHour = byHour.group(); var groupByTimezone = byTimezone.group(); //data selected, counts by day date hour groupByAlertType.top(Infinity).forEach(function(p,i){ console.log(p.key + ":" + p.value); }); groupByDate.top(Infinity).forEach(function(p,i){ console.log(p.key + ":" + p.value); }); groupByTimezone.top(Infinity).forEach(function(p,i){ console.log(p.key + ":" + p.value); }); groupByHour.top(Infinity).forEach(function(p,i){ console.log(p.key + ":" + p.value); }); var charts = [ barChart() .dimension(byHour) .group(groupByHour) .x(d3.scaleLinear() .domain([0,24]) .rangeRound([0, 10*24])), barChart() .dimension(byDate) .group(groupByDate) .round(d3.timeDay.round) .x(d3.scaleTime() .domain([new Date(2019,4,1),new Date(2019,5,1)]) .rangeRound([0,10*30])), barChart() .dimension(byAlertType) .group(groupByAlertType) .x(d3.scaleLinear() .domain([0,24]) .rangeRound([0, 10*24])), barChart() .dimension(byTimezone) .group(groupByTimezone) .x(d3.scaleLinear() .domain([0,24]) .rangeRound([0, 10*24])), ]; //charts as they appear in DOM const viz = d3.selectAll('.chart') .data([charts]) // render initial list const list = d3.selectAll('.list') .data([alertList]); d3.selectAll('#total') .text((cf.size())); renderAll(); function render(method){ d3.select(this).call(method); } function renderAll() { viz.each(render); list.each(render); d3.select('#active').text(all.value()); } window.filter = filters => { filters.forEach((d, i) => { charts[i].filter(d); }); renderAll(); }; window.reset = i => { charts[i].filter(null); renderAll(); }; function alertList(div) { } function barChart() { if (!barChart.id) barChart.id = 0; let margin = { top: 10, right: 13, bottom: 20, left: 10 }; let x; let y = d3.scaleLinear().range([100, 0]); const id = barChart.id++; const axis = d3.axisBottom(); const brush = d3.brushX(); let brushDirty; let dimension; let group; let round; let gBrush; function chart(div) { const width = x.range()[1]; const height = y.range()[0]; brush.extent([[0, 0], [width, height]]); y.domain([0, group.top(1)[0].value]); div.each(function () { const div = d3.select(this); let g = div.select('g'); // Create the skeletal chart. if (g.empty()) { div.select('.title').append('a') .attr('href', `javascript:reset(${id})`) .attr('class', 'reset') .text('reset') .style('display', 'none'); g = div.append('svg') .attr('width', width + margin.left + margin.right) .attr('height', height + margin.top + margin.bottom) .append('g') .attr('transform', `translate(${margin.left},${margin.top})`); g.append('clipPath') .attr('id', `clip-${id}`) .append('rect') .attr('width', width) .attr('height', height); g.selectAll('.bar') .data(['background', 'foreground']) .enter().append('path') .attr('class', d => `${d} bar`) .datum(group.all()); g.selectAll('.foreground.bar') .attr('clip-path', `url(#clip-${id})`); g.append('g') .attr('class', 'axis') .attr('transform', `translate(0,${height})`) .call(axis); // Initialize the brush component with pretty resize handles. gBrush = g.append('g') .attr('class', 'brush') .call(brush); gBrush.selectAll('.handle--custom') .data([{ type: 'w' }, { type: 'e' }]) .enter().append('path') .attr('class', 'brush-handle') .attr('cursor', 'ew-resize') .attr('d', resizePath) .style('display', 'none'); } // Only redraw the brush if set externally. if (brushDirty !== false) { const filterVal = brushDirty; brushDirty = false; div.select('.title a').style('display', d3.brushSelection(div) ? null : 'none'); if (!filterVal) { g.call(brush); g.selectAll(`#clip-${id} rect`) .attr('x', 0) .attr('width', width); g.selectAll('.brush-handle').style('display', 'none'); renderAll(); } else { const range = filterVal.map(x); brush.move(gBrush, range); } } g.selectAll('.bar').attr('d', barPath); }); function barPath(groups) { const path = []; let i = -1; const n = groups.length; let d; while (++i < n) { d = groups[i]; path.push('M', x(d.key), ',', height, 'V', y(d.value), 'h9V', height); } return path.join(''); } function resizePath(d) { const e = +(d.type === 'e'); const x = e ? 1 : -1; const y = height / 3; return `M${0.5 * x}, ${y}A6,6 0 0 ${e} ${6.5 * x}, ${y + 6}V${2 * y - 6}A6,6 0 0 ${e} ${0.5 * x},${2 * y}ZM${2.5 * x},${y + 8}V${2 * y - 8}M${4.5 * x},${y + 8}V${2 * y - 8}`; } } brush.on('start.chart', function () { const div = d3.select(this.parentNode.parentNode.parentNode); div.select('.title a').style('display', null); }); brush.on('brush.chart', function () { const g = d3.select(this.parentNode); const brushRange = d3.event.selection || d3.brushSelection(this); // attempt to read brush range const xRange = x && x.range(); // attempt to read range from x scale let activeRange = brushRange || xRange; // default to x range if no brush range available const hasRange = activeRange && activeRange.length === 2 && !isNaN(activeRange[0]) && !isNaN(activeRange[1]); if (!hasRange) return; // quit early if we don't have a valid range // calculate current brush extents using x scale let extents = activeRange.map(x.invert); // if rounding fn supplied, then snap to rounded extents // and move brush rect to reflect rounded range bounds if it was set by user interaction if (round) { extents = extents.map(round); activeRange = extents.map(x); if ( d3.event.sourceEvent && d3.event.sourceEvent.type === 'mousemove' ) { d3.select(this).call(brush.move, activeRange); } } // move brush handles to start and end of range g.selectAll('.brush-handle') .style('display', null) .attr('transform', (d, i) => `translate(${activeRange[i]}, 0)`); // resize sliding window to reflect updated range g.select(`#clip-${id} rect`) .attr('x', activeRange[0]) .attr('width', activeRange[1] - activeRange[0]); // filter the active dimension to the range extents dimension.filterRange(extents); // re-render the other charts accordingly renderAll(); }); brush.on('end.chart', function () { // reset corresponding filter if the brush selection was cleared // (e.g. user "clicked off" the active range) if (!d3.brushSelection(this)) { reset(id); } }); chart.margin = function (_) { if (!arguments.length) return margin; margin = _; return chart; }; chart.x = function (_) { if (!arguments.length) return x; x = _; axis.scale(x); return chart; }; chart.y = function (_) { if (!arguments.length) return y; y = _; return chart; }; chart.dimension = function (_) { if (!arguments.length) return dimension; dimension = _; return chart; }; chart.filter = _ => { if (!_) dimension.filterAll(); brushDirty = _; return chart; }; chart.group = function (_) { if (!arguments.length) return group; group = _; return chart; }; chart.round = function (_) { if (!arguments.length) return round; round = _; return chart; }; chart.gBrush = () => gBrush; return chart; } }; };
Continent zoom topojson
I'm trying to make the map able to zoom in on continenents on mouseclick. The code is based on Mike Bostock's tutorial on making maps and uses a CSV dataset to bind some values to the countries. https://bost.ocks.org/mike/map/. I've tried to use various examples like this one: https://bl.ocks.org/mbostock/2206590 but nothing seems to work. The map just dissapears when I try to add a .onclick attribute. Does anyone have an idea how I can make the zoom work? HTML <!DOCTYPE html> <meta charset="utf-8"> <style> body { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; width: 960px; height: 500px; position: relative; } #canvas { } #canvas-svg { } .land { fill: #222; } .boundary { fill: none; stroke: #fff; stroke-width: 1px; } #tooltip-container { position: absolute; background-color: #fff; color: #000; padding: 10px; border: 1px solid; display: none; } .tooltip_key { font-weight: bold; } .tooltip_value { margin-left: 20px; float: right; } </style> <div id="tooltip-container"></div> <div id="canvas-svg"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/1.6.20/topojson.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script> <script> d3.csv("import.csv", function(err, data) { var config = {"data0":"Country","data1":"Total","label0":"label 0","label1":"label 1","color0":"#99ccff","color1":"#0050A1","width":800,"height":400} var width = 960, height = 960; var COLOR_COUNTS = 9; function Interpolate(start, end, steps, count) { var s = start, e = end, final = s + (((e - s) / steps) * count); return Math.floor(final); } function Color(_r, _g, _b) { var r, g, b; var setColors = function(_r, _g, _b) { r = _r; g = _g; b = _b; }; setColors(_r, _g, _b); this.getColors = function() { var colors = { r: r, g: g, b: b }; return colors; }; } function clicked(d) { var x, y, k; if (d && centered !== d) { var centroid = path.centroid(d); x = centroid[0]; y = centroid[1]; k = 4; centered = d; } else { x = width / 2; y = height / 2; k = 1; centered = null; } g.selectAll("path") .classed("active", centered && function(d) { return d === centered; }); g.transition() .duration(750) .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")scale(" + k + ")translate(" + -x + "," + -y + ")") .style("stroke-width", 1.5 / k + "px"); } function hexToRgb(hex) { var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : null; } function valueFormat(d) { if (d > 1000000000) { return "$" + Math.round(d / 1000000000 * 10) / 10 + "M"; } else if (d > 1000000) { return "$" + Math.round(d / 1000000 * 10) / 10 + "M"; } else if (d > 1000) { return "$" + Math.round(d / 1000 * 10) / 10 + "B"; } else { return "$" + d + "M"; } } var COLOR_FIRST = config.color0, COLOR_LAST = config.color1; var rgb = hexToRgb(COLOR_FIRST); var COLOR_START = new Color(rgb.r, rgb.g, rgb.b); rgb = hexToRgb(COLOR_LAST); var COLOR_END = new Color(rgb.r, rgb.g, rgb.b); var startColors = COLOR_START.getColors(), endColors = COLOR_END.getColors(); var colors = []; for (var i = 0; i < COLOR_COUNTS; i++) { var r = Interpolate(startColors.r, endColors.r, COLOR_COUNTS, i); var g = Interpolate(startColors.g, endColors.g, COLOR_COUNTS, i); var b = Interpolate(startColors.b, endColors.b, COLOR_COUNTS, i); colors.push(new Color(r, g, b)); } var MAP_KEY = config.data0; var MAP_VALUE = config.data1; var projection = d3.geo.mercator() .scale((width + 1) / 2 / Math.PI) .translate([width / 2, height / 2]) .precision(.1); var path = d3.geo.path() .projection(projection); var graticule = d3.geo.graticule(); var svg = d3.select("#canvas-svg").append("svg") .attr("width", width) .attr("height", height); svg.append("path") .datum(graticule) .attr("class", "graticule") .attr("d", path); var valueHash = {}; function log10(val) { return Math.log(val); } data.forEach(function(d) { valueHash[d[MAP_KEY]] = +d[MAP_VALUE]; }); var quantize = d3.scale.quantize() .domain([0, 1.0]) .range(d3.range(COLOR_COUNTS).map(function(i) { return i })); quantize.domain([d3.min(data, function(d){ return (+d[MAP_VALUE]) }), d3.max(data, function(d){ return (+d[MAP_VALUE]) })]); d3.json("./world-topo-min.json", function(error, world) { var countries = topojson.feature(world, world.objects.countries).features; svg.append("path") .datum(graticule) .attr("class", "choropleth") .attr("d", path); var g = svg.append("g"); g.append("path") .datum({type: "LineString", coordinates: [[-180, 0], [-90, 0], [0, 0], [90, 0], [180, 0]]}) .attr("class", "equator") .attr("d", path); var country = g.selectAll(".country").data(countries); country.enter().insert("path") .attr("class", "country") .attr("d", path) .attr("id", function(d,i) { return d.id; }) .attr("title", function(d) { return d.properties.name; }) .style("fill", function(d) { if (valueHash[d.properties.name]) { var c = quantize((valueHash[d.properties.name])); var color = colors[c].getColors(); return "rgb(" + color.r + "," + color.g + "," + color.b + ")"; } else { return "#ccc"; } }) .on("mousemove", function(d) { var html = ""; html += "<div class=\"tooltip_kv\">"; html += "<span class=\"tooltip_key\">"; html += d.properties.name; html += "</span>"; html += "<span class=\"tooltip_value\">"; html += (valueHash[d.properties.name] ? valueFormat(valueHash[d.properties.name]) : ""); html += ""; html += "</span>"; html += "</div>"; $("#tooltip-container").html(html); $(this).attr("fill-opacity", "0.8"); $("#tooltip-container").show(); var coordinates = d3.mouse(this); var map_width = $('.choropleth')[0].getBoundingClientRect().width; if (d3.event.pageX < map_width / 2) { d3.select("#tooltip-container") .style("top", (d3.event.layerY + 15) + "px") .style("left", (d3.event.layerX + 15) + "px"); } else { var tooltip_width = $("#tooltip-container").width(); d3.select("#tooltip-container") .style("top", (d3.event.layerY + 15) + "px") .style("left", (d3.event.layerX - tooltip_width - 30) + "px"); } }) .on("mouseout", function() { $(this).attr("fill-opacity", "1.0"); $("#tooltip-container").hide(); }); g.append("path") .datum(topojson.mesh(world, world.objects.countries, function(a, b) { return a !== b; })) .attr("class", "boundary") .attr("d", path); }); function clicked(d) { if (active.node() === this) return reset(); active.classed("active", false); active = d3.select(this).classed("active", true); var bounds = path.bounds(d), dx = bounds[1][0] - bounds[0][0], dy = bounds[1][1] - bounds[0][1], x = (bounds[0][0] + bounds[1][0]) / 2, y = (bounds[0][1] + bounds[1][1]) / 2, scale = .9 / Math.max(dx / width, dy / height), translate = [width / 2 - scale * x, height / 2 - scale * y]; g.transition() .duration(750) .style("stroke-width", 1.5 / scale + "px") .attr("transform", "translate(" + translate + ")scale(" + scale + ")"); } function reset() { active.classed("active", false); active = d3.select(null); g.transition() .duration(750) .style("stroke-width", "1.5px") .attr("transform", ""); } d3.select(self.frameElement).style("height", height + "px"); }); </script> CSV ,Country,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,Total ,Afghanistan,,,34,,,35,3,41,150,344,377,660,521,235,288,74,2763 ,African Union**,,,,,,53,9,,10,,,,,2,,2,76 ,Albania,,,,2,,7,,5,,,,,15,7,7,7,50 ,Algeria,412,546,249,195,242,159,340,509,1529,1075,829,1115,889,373,487,636,9585 ,Angola,147,156,148,48,8,39,7,31,29,20,,,,31,2,61,726 ,Argentina,213,6,16,12,168,3,9,24,23,16,14,46,36,44,14,23,668 ,Armenia,,,,,118,,,1,,46,52,5,,16,,,238 ,Australia,338,1236,663,801,472,459,727,675,445,775,1507,1567,876,255,932,1574,13301 ,Austria,25,15,69,42,55,23,4,269,190,286,7,8,8,6,2,,1008 ,Azerbaijan,3,,89,,4,53,159,211,29,142,146,557,333,398,602,285,3012 ,Bahamas,33,,,,,3,,,,1,,,,,29,22,88 ,Bahrain,299,30,54,1,10,66,63,26,20,,103,1,26,78,10,,786 ,Bangladesh,203,266,41,8,32,10,221,88,13,,35,193,252,727,257,653,2997 ,Barbados,,,,,,,,10,10,10,,,,,,,29 ,Belarus,,,,,,6,140,,,3,,75,75,75,60,164,598 ,Belgium,35,29,56,21,15,3,27,174,203,90,32,21,32,46,103,49,934 ,Belize,1,,,,,,,,,,,,,,,,1 ,Benin,,,7,,,,,3,,1,0,0,20,2,,,33 ,Bhutan,,,,,0,,,,,,,,,,,1,1 ,Bolivia,19,,,5,1,1,9,2,3,5,1,25,12,1,46,7,136 ,Botswana,53,15,1,9,8,,,,,13,10,,,8,,,119 ,Brazil,122,626,213,100,81,224,179,189,179,189,318,312,311,223,284,289,3840 ,Brunei,,4,1,0,0,1,2,,,33,33,229,22,15,122,36,498 ,Bulgaria,,,,2,12,132,22,48,116,119,8,29,5,,,3,495 ,Burkina Faso,,,,,,12,1,4,,2,0,15,4,,5,6,48 ,Burundi,,1,3,,,,,,,1,2,,5,,,1,14 ,Cambodia,,,,,,,14,56,,4,34,,77,67,,,252 ,Cameroon,,7,6,,,5,2,,1,,10,,,39,107,2,177 ,Canada,570,538,428,152,352,124,104,456,408,106,236,351,211,194,306,395,4931 ,Cape Verde,1,,,,,,,,,2,,,10,,,,12 ,Central African Republic,,,,,,,9,,0,,,7,,,,,16 ,Chad,,16,,,,,17,20,75,35,38,1,4,59,57,,322 ,Chile,202,60,74,187,70,449,1095,662,397,335,475,316,62,51,125,114,4673 ,China,2552,2833,2891,2373,3316,3558,2900,1692,1892,1407,1045,1128,1703,1452,1184,1214,33140 ,Colombia,60,278,171,147,18,16,56,234,110,248,255,145,207,162,190,215,2510 ,Comoros,,,,,,,,,6,,,,1,,,,7 ,Democratic Republic of Congo,0,,,,,4,1,0,,1,27,,23,12,13,,81 ,Costa Rica,,,,,,,,,,,,,1,,1,,2 ,Cote d'Ivoire,0,,32,61,9,,,,,,,,,,6,6,113 ,Croatia,,57,2,24,8,,,15,99,4,10,17,17,,63,11,326 ,Cyprus,4,115,1,6,16,20,26,17,,,44,41,6,,,,295 ,Czech Republic,14,65,47,97,7,593,45,10,23,6,13,71,22,15,,0,1029 ,Denmark,50,153,51,54,228,120,83,146,95,129,17,,109,42,177,0,1455 ,Djibouti,1,,3,,4,7,,,,,,,6,5,12,7,44 ,Dominican Republic,13,5,0,8,35,2,,,,10,51,12,,,,1,137 ,DR Congo,88,15,12,,,19,17,,18,41,151,,10,1,,,374 ,Ecuador,,10,1,,15,48,17,2,102,77,90,68,88,11,53,1,583 ,Egypt,837,847,719,630,654,778,678,651,333,159,686,630,281,675,368,1475,10401 ,El Salvador,,,19,10,,,,,4,,,,2,,20,,55 ,Equatorial Guinea,,7,,,7,12,,28,30,68,3,82,65,2,92,,394 ,Eritrea,20,57,18,17,80,98,,4,,,,,,,,,293 ,Estonia,27,,1,13,8,23,7,19,29,43,13,1,2,18,2,22,228 ,Ethiopia,140,,20,174,239,,,,,,54,76,193,153,30,,1079 ,Finland,474,9,12,227,77,107,136,108,135,42,50,58,76,280,156,228,2172 ,France,107,66,43,57,93,2,67,74,5,76,103,33,91,107,17,34,976 ,Gabon,,,,,6,,20,18,,,22,5,1,2,,3,77 ,Gambia,,,,,5,,,,,16,,,,,,,21 ,Georgia,6,85,,1,37,92,97,155,91,36,,2,,5,1,,608 ,Germany,113,133,71,64,239,204,416,82,292,339,282,84,157,113,114,102,2804 ,Ghana,1,12,1,6,35,0,0,16,,11,2,76,39,63,14,13,290 ,Greece,708,787,400,2274,1368,405,731,1712,516,1229,652,80,37,52,199,762,11910 ,Guatemala,,,,,,,,,0,,,,2,,,33,35 ,Guinea,18,6,,2,,1,,0,,,4,1,4,,5,,40 ,Guyana,,7,3,,,,,,0,,,,,,,,10 ,Palestine,,,,,,,,,,,1,2,,,0,,3 ,Lebanon,0,0,3,0,1,0,9,,,20,20,,,,,,54 ,Honduras,,,,,,,,,0,,,0,0,20,13,6,39 ,Hungary,14,14,,,72,13,253,196,5,4,18,9,,2,7,,604 ,Iceland,,,,,,,,,,,,50,,,,,50 ,India,995,1321,1911,2878,2180,1161,1480,2299,1867,1945,3017,3706,4545,5291,3487,3078,41160 ,Indonesia,151,27,68,356,79,36,61,577,239,436,225,250,218,802,1136,683,5341 ,Iran,418,524,435,282,121,57,423,331,62,62,103,103,47,31,13,13,3025 ,Iraq,,,,,71,186,305,263,377,398,453,603,474,353,650,1215,5348 ,Ireland,0,45,22,,19,5,13,19,22,0,5,2,1,,40,41,232 ,Israel,368,131,349,189,852,1133,1122,862,676,153,67,85,120,153,510,617,7387 ,Italy,241,221,243,559,446,162,433,525,220,109,115,298,219,91,145,596,4623 ,Jamaica,,,,,,10,10,13,2,,1,,,1,,2,38 ,Japan,491,441,477,480,400,464,511,498,680,525,426,292,270,306,480,310,7050 ,Jordan,133,160,121,281,157,49,48,176,161,234,87,214,175,81,252,198,2526 ,Kazakhstan,121,139,20,,47,42,44,82,25,39,58,52,84,141,93,419,1406 ,Kenya,15,,,,,,,10,,,112,14,60,1,17,30,258 ,Kosovo,,,,,,,,,,,,,,,1,,1 ,Kuwait,245,67,23,45,2,12,5,279,5,9,85,113,31,73,692,366,2052 ,Kyrgyzstan,,,,9,5,3,2,,,,,,,,,,19 ,Laos,7,36,,0,,4,,,7,26,,14,19,19,,7,138 ,Latvia,3,13,3,25,12,4,9,49,44,11,14,27,9,5,5,1,234 ,Lebanon,4,,,,,1,,5,1,52,64,2,31,24,5,50,239 ,Lesotho,,6,,,1,,1,,,,,,,,,,8 ,Liberia,8,,,,,,,,,,,,,,,,8 ,Libya,1,14,15,16,26,24,8,73,120,10,44,349 ,Lithuania,6,16,12,1,47,9,52,4,27,27,8,1,1,73,3,21,308 ,Uganda,,,0,,,,,,,,,,,,,,0 ,Sri Lanka,1,,1,,,0,,,,,,,,,,,2 ,Luxembourg,,,,1,,,,,,7,7,,1,,,,16 ,Macedonia,14,112,,,,,0,,,,,,,1,,,128 ,Madagascar,,,,,,,,,,0,,,,0,,,0 ,Malawi,,,,,,,,,3,,,,1,2,2,,7 ,Malaysia,26,26,154,147,65,57,398,526,508,1512,421,5,47,71,73,190,4227 ,Maldives,,,,,,,15,,,,5,,,5,,,24 ,Mali,7,,1,,,13,,8,3,10,,,9,6,,,57 ,Malta,0,0,,,,18,,,,,,8,8,,12,,45 ,Mauritania,31,,26,7,,,,,,,9,5,11,10,5,,103 ,Mauritius,,,,,6,,,,,,,,,,45,,51 ,Mexico,227,152,97,31,320,33,75,,22,59,112,229,261,69,97,500,2284 ,Mongolia,,,,,,,,,14,,27,3,51,,,13,107 ,Morocco,125,11,156,12,14,101,47,27,46,39,306,1398,826,82,572,42,3803 ,Mozambique,0,,,1,,,,,,,,0,0,9,12,,22 ,Myanmar,16,149,157,83,194,160,175,138,93,52,63,664,478,237,300,320,3277 ,Namibia,,21,11,,16,,72,6,66,15,,1,57,9,2,,276 ,NATO**,,18,,,,,116,,,420,,,22,,,,576 ,Nepal,,11,9,9,34,6,,,1,,,3,,,5,14,91 ,Netherlands,125,178,244,125,127,102,320,240,157,288,193,149,376,332,10,86,3052 ,New Zealand,,45,17,107,49,10,5,81,2,48,58,23,25,26,79,56,631 ,Nicaragua,,,,,,,,14,,14,,,,,,,28 ,Niger,,,,14,,,,,8,1,0,,,13,3,9,48 ,Nigeria,36,7,6,62,6,,15,52,19,65,186,65,4,35,224,188,971 ,Macedonia,,0,,,,,,,,,,,,,,,0 ,Afghanistan,19,207,,,,,,,,,,,,,,,226 ,North Korea,18,28,9,8,8,5,15,5,5,4,1,,,,,,103 ,Norway,229,99,90,14,6,14,542,567,624,588,159,614,149,62,23,143,3921 ,Libya,,,,,,,,,,,,0,,,,,0 ,Oman,118,33,40,36,41,173,301,16,75,93,30,21,120,490,736,148,2469 ,Pakistan,175,408,541,628,455,421,338,670,1047,1214,2176,1063,1028,1144,752,735,12797 ,Palestine,,,,,,,,2,,14,6,,,,,,21 ,Panama,,,1,,,,,,,7,,,15,30,,,52 ,Papua New Guinea,,,,,,,,,,,,,,,3,,3 ,Paraguay,,6,,,4,1,,,,,3,8,7,0,,,29 ,Peru,24,5,16,22,47,368,193,172,,43,46,63,10,49,153,169,1380 ,Philippines,,10,5,10,34,12,23,16,10,1,3,63,16,75,12,158,449 ,PIJ (Israel/Palestine)*,,,,,,,,,,,,,0,,,,0 ,Poland,148,36,255,349,225,112,463,990,594,169,158,92,207,155,252,131,4336 ,Portugal,2,19,,29,70,157,220,60,144,369,892,168,40,13,4,11,2196 ,PRC (Israel/Palestine)*,,,,,,,,,,,,,,,0,,0 ,Qatar,14,11,11,11,,,,27,,286,30,198,319,73,55,655,1690 ,Romania,21,19,16,17,285,437,61,98,78,56,105,80,21,20,0,22,1335 ,Russian Federation,,,,,,,4,100,,8,22,11,98,153,206,88,690 ,Rwanda,14,,,,,,2,15,8,11,,,5,11,14,7,86 ,Saudi Arabia,85,61,567,167,1170,167,205,214,363,796,1070,1237,1080,1672,2782,3161,14796 ,Senegal,,,,,,15,9,18,6,4,4,20,,6,7,11,99 ,Serbia,1,27,,,,,,,,,16,,0,,,,44 ,Seychelles,,,,,,15,,,,,,8,,7,16,,45 ,Sierra Leone,,,,,,,9,,,,,2,0,1,,,12 ,Singapore,798,254,234,83,376,538,69,355,1113,1481,1020,935,828,780,683,98,9645 ,Slovakia,0,,27,,,4,,0,,9,9,,2,6,,,57 ,Slovenia,2,41,2,17,17,3,3,2,,6,40,28,,,,,162 ,Somalia,,,,,,,,,,,,,,3,,0,3 ,South Africa,6,18,,,,262,708,881,486,128,180,212,132,2,50,,3065 ,South Korea,1396,773,528,752,1059,804,1650,1755,1683,796,1250,1553,1066,182,715,245,16207 ,South Sudan,,,,,,,,37,44,1,,61,3,5,18,22,190 ,Spain,334,168,289,253,315,363,315,337,346,235,290,181,238,176,127,153,4119 ,Sri Lanka,297,161,45,35,49,58,97,89,71,,5,21,,,5,,934 ,Sudan,,106,49,204,293,132,65,33,128,89,182,173,119,196,61,27,1858 ,Suriname,2,,,,,,,,,,,,,7,,3,11 ,Swaziland,1,1,,,,,,,,,,,,,,,2 ,Sweden,204,165,75,64,47,78,122,41,44,54,51,191,206,52,43,43,1481 ,Switzerland,23,68,63,117,203,168,83,108,18,39,47,31,9,4,0,2,983 ,Syrian Arab Republic,64,28,45,69,25,35,100,20,276,193,298,368,371,361,15,,2267 ,Syria rebels*,,,,,,,,,,,,,1,1,0,,2 ,Taiwan (ROC),585,345,298,117,319,691,503,12,11,60,97,198,425,553,1084,681,5978 ,Tajikistan,,,,,,,13,7,,32,,,,3,,,55 ,Tanzania,3,,,51,,10,12,1,,25,,78,115,92,26,20,433 ,Thailand,85,117,152,131,114,70,47,8,13,64,49,270,289,392,93,185,2078 ,Timor-Leste,,,,,,,,,,,18,,,,,,18 ,Togo,,,,,,,,,,,1,,4,,16,,21 ,Tonga,,,,,,,,,,,,,,,,5,5 ,Trinidad and Tobago,11,0,2,,,,,6,,,24,12,12,,,46,113 ,Tunisia,,,83,1,,168,2,,3,,7,7,,38,43,6,357 ,Turkey,1190,510,905,330,257,1113,531,692,710,780,484,770,1503,650,1556,448,12427 ,Turkmenistan,,,,18,21,,,,7,36,14,236,115,69,102,122,739 ,UAE,247,186,222,685,1210,2170,2021,919,752,561,605,1210,1088,2235,731,1289,16128 ,Uganda,6,,34,,36,10,5,,5,23,37,471,219,20,,3,868 ,UIC (Somalia)*,,,,,,,0,,,,,,,,,,0 ,Ukraine,,,,,,,,,,,,,,,1,10,11 ,Ukraine Rebels*,,,,,,,,,,,,,,,24,,24 ,United Kingdom,871,1277,719,761,212,27,308,764,508,383,511,368,586,492,214,382,8381 ,United Nations**,31,,,,2,1,2,1,0,,,,,5,23,4,69 ,United States,330,487,499,592,560,520,641,819,951,968,1111,995,1180,802,566,565,11587 ,United Wa State (Myanmar)*,,1,,,,,,,,,,,,,,,1 ,Unknown country,,2,,0,,,,,12,,8,6,,30,31,51,139 ,Unknown rebel group*,,0,0,,,,,,,,,,,,,,0 ,Uruguay,4,,11,,,20,8,3,78,29,20,,,6,9,8,196 ,Uzbekistan,,8,9,,,,,,,,,,,,,62,79 ,Venezuela,108,103,50,15,9,21,380,774,737,358,208,594,680,1165,173,162,5535 ,Viet Nam,7,85,66,28,304,297,41,8,204,78,184,1039,766,362,1078,870,5414 ,Yemen,158,85,593,62,254,317,38,66,40,5,258,45,38,23,6,12,2000 ,Zambia,33,,2,,,0,30,5,2,,,1,66,,,24,161 ,Zimbabwe,3,10,,16,,25,25,,,,,,,,,,78
d3.js Pie Chart With label
I started working with this d3.js Donut Chart: JSFiddleI am trying to change it into a Pie Chart without the circle in the middle. I am new to d3.js. I have tried several different ideas but have been unable to get this to remove the circle in the middle of the chart. Any and all help is appreciated Here is my code: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <style> .label-text { alignment-baseline : middle; font-size: 12px; font-family: arial,helvetica,"sans-serif"; fill: #393939; } .label-line { stroke-width: 1; stroke: #393939; } .label-circle { fill: #393939; } </style> <script src="http://d3js.org/d3.v3.min.js"></script> </head> <body> <svg> <g id="canvas"> <g id="art" /> <g id="labels" /></g> </svg> <script> var data = [{ label: 'Star Wars', instances: 207 }, { label: 'Lost In Space', instances: 3 }, { label: 'the Boston Pops', instances: 20 }, { label: 'Indiana Jones', instances: 150 }, { label: 'Harry Potter', instances: 75 }, { label: 'Jaws', instances: 5 }, { label: 'Lincoln', instances: 1 }]; svg = d3.select("svg"); canvas = d3.select("#canvas"); art = d3.select("#art"); labels = d3.select("#labels"); // Create the pie layout function. // This function will add convenience // data to our existing data, like // the start angle and end angle // for each data element. jhw_pie = d3.layout.pie(); jhw_pie.sort(null); jhw_pie.value(function (d) { // Tells the layout function what // property of our data object to // use as the value. return d.instances; }); // Store our chart dimensions cDim = { height: 500, width: 500, innerRadius: 50, outerRadius: 150, labelRadius: 175 } // Set the size of our SVG element svg.attr({ height: cDim.height, width: cDim.width }); // This translate property moves the origin of the group's coordinate // space to the center of the SVG element, saving us translating every // coordinate individually. canvas.attr("transform", "translate(" + (cDim.width / 2) + "," + (cDim.height / 2) + ")"); pied_data = jhw_pie(data); // The pied_arc function we make here will calculate the path // information for each wedge based on the data set. This is // used in the "d" attribute. pied_arc = d3.svg.arc() .innerRadius(50) .outerRadius(150); // This is an ordinal scale that returns 10 predefined colors. // It is part of d3 core. pied_colors = d3.scale.ordinal() .range(["#04B486", "#F2F2F2", "#F5F6CE", "#00BFFF","orange","purple","pink"]); // Let's start drawing the arcs. enteringArcs = art.selectAll(".wedge").data(pied_data) .enter(); enteringArcs .append("g") .attr("class", "wedge") .append("path") .attr("d", pied_arc) .style("fill", function (d, i) { return pied_colors(i); }); // Now we'll draw our label lines, etc. enteringLabels = labels.selectAll(".label").data(pied_data).enter(); labelGroups = enteringLabels.append("g").attr("class", "label"); labelGroups.append("circle").attr({ x: 0, y: 0, r: 2, fill: "#000", transform: function (d, i) { centroid = pied_arc.centroid(d); return "translate(" + pied_arc.centroid(d) + ")"; }, 'class': "label-circle" }); // "When am I ever going to use this?" I said in // 10th grade trig. textLines = labelGroups.append("line").attr({ x1: function (d, i) { return pied_arc.centroid(d)[0]; }, y1: function (d, i) { return pied_arc.centroid(d)[1]; }, x2: function (d, i) { centroid = pied_arc.centroid(d); midAngle = Math.atan2(centroid[1], centroid[0]); x = Math.cos(midAngle) * cDim.labelRadius; return x; }, y2: function (d, i) { centroid = pied_arc.centroid(d); midAngle = Math.atan2(centroid[1], centroid[0]); y = Math.sin(midAngle) * cDim.labelRadius; return y; }, 'class': "label-line" }); textLabels = labelGroups.append("text").attr({ x: function (d, i) { centroid = pied_arc.centroid(d); midAngle = Math.atan2(centroid[1], centroid[0]); x = Math.cos(midAngle) * cDim.labelRadius; sign = (x > 0) ? 1 : -1 labelX = x + (5 * sign) return labelX; }, y: function (d, i) { centroid = pied_arc.centroid(d); midAngle = Math.atan2(centroid[1], centroid[0]); y = Math.sin(midAngle) * cDim.labelRadius; return y; }, 'text-anchor': function (d, i) { centroid = pied_arc.centroid(d); midAngle = Math.atan2(centroid[1], centroid[0]); x = Math.cos(midAngle) * cDim.labelRadius; return (x > 0) ? "start" : "end"; }, 'class': 'label-text' }).text(function (d) { return d.data.label }); alpha = 0.5; spacing = 12; function relax() { again = false; textLabels.each(function (d, i) { a = this; da = d3.select(a); y1 = da.attr("y"); textLabels.each(function (d, j) { b = this; // a & b are the same element and don't collide. if (a == b) return; db = d3.select(b); // a & b are on opposite sides of the chart and // don't collide if (da.attr("text-anchor") != db.attr("text-anchor")) return; // Now let's calculate the distance between // these elements. y2 = db.attr("y"); deltaY = y1 - y2; // Our spacing is greater than our specified spacing, // so they don't collide. if (Math.abs(deltaY) > spacing) return; // If the labels collide, we'll push each // of the two labels up and down a little bit. again = true; sign = deltaY > 0 ? 1 : -1; adjust = sign * alpha; da.attr("y", +y1 + adjust); db.attr("y", +y2 - adjust); }); }); // Adjust our line leaders here // so that they follow the labels. if (again) { labelElements = textLabels[0]; textLines.attr("y2", function (d, i) { labelForLine = d3.select(labelElements[i]); return labelForLine.attr("y"); }); setTimeout(relax, 20) } } relax(); </script> </body> </html> Thanks
See this updated fiddle. The code contained the following lines, of which the innerRadious was changed to 0. pied_arc = d3.svg.arc() .innerRadius(00) // <- this .outerRadius(150); It's a bit misleading, as there's an innerRadius variable somewhere before that, but it's not used at this point. While you're at it, you might want to align all of that stuff.
D3.js Gauge look like Telerik Radial Gauge
Hello I need help to add gray (Minor and Major) graduation lines inside the gauge to capture more precisely the position of the needle. Also if you have any idea how we could put text to Major graduation lines. For my sample I would required 7 Major graduation lines divided by 10 minor separations (to look exactly like the Telerik Gauge). Here is my implementation : http://jsfiddle.net/8svg5/ <html> <head runat="server"> <title></title> </head> <body> <div> <a id="myTooltip" title="This is my message"></a> <div id="svgTarget"></div> </div> <script> $(function () { var gaugeRanges = [ { From: 1.5, To: 2.5, Color: "#8dcb2a" }, { From: 2.5, To: 3.5, Color: "#ffc700" }, { From: 3.5, To: 4.5, Color: "#ff7a00" }, { From: 4.5, To: 6, Color: "#c20000" }]; $("#svgTarget").mttD3Gauge({ data: gaugeRanges }); }); </script> </body> </html> (function ($) { $.fn.mttD3Gauge = function (options) { var settings = $.extend({ width: 300, innerRadius: 130, outterRadius: 145, data: [] }, options); this.create = function () { this.html("<svg class='mtt-svgClock' width='" + settings.width + "' height='" + settings.width + "'></svg>"); var maxLimit = 0; var minLimit = 9999999; var d3DataSource = []; var d3TickSource = []; //Data Genration $.each(settings.data, function (index, value) { d3DataSource.push([value.From, value.To, value.Color]); if (value.To > maxLimit) maxLimit = value.To; if (value.From < minLimit) minLimit = value.From; }); if (minLimit > 0) { d3DataSource.push([0, minLimit, "#d7d7d7"]); } var pi = Math.PI; //Control Genration var vis = d3.select(this.selector + " .mtt-svgClock"); var translate = "translate(" + settings.width / 2 + "," + settings.width / 2 + ")"; var cScale = d3.scale.linear().domain([0, maxLimit]).range([-120 * (pi / 180), 120 * (pi / 180)]); var arc = d3.svg.arc() .innerRadius(settings.innerRadius) .outerRadius(settings.outterRadius) .startAngle(function (d) { return cScale(d[0]); }) .endAngle(function (d) { return cScale(d[1]); }); var tickArc = d3.svg.arc() .innerRadius(settings.innerRadius - 20) .outerRadius(settings.innerRadius - 2) .startAngle(function (d) { return cScale(d[0]); }) .endAngle(function (d) { return cScale(d[1]); }); for (var i = 0; i < 10; i++) { var point = (i * maxLimit) / 10.0; d3TickSource.push([point, point +1, "#d7d7d7"]); } vis.selectAll("path") .data(d3DataSource) .enter() .append("path") .attr("d", arc) .style("fill", function (d) { return d[2]; }) .attr("transform", translate); return this; }; return this.create(); }; }(jQuery)); enter code here Here is the link of the page of what i'm trying to achieve with D3.js http://demos.telerik.com/aspnet-ajax/gauge/examples/types/radialgauge/defaultcs.aspx?#qsf-demo-source Any help will be greatly appreciated!
I finally found the way to add graduation, feel free to use this code <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> <script src="Scripts/jquery-1.9.1.js"></script> <script src="Scripts/html5shiv.js"></script> <script src="Scripts/d3.v3.min.js"></script> <script src="Scripts/mtt-D3Gauge.js"></script> </head> <body> <div> <a id="myTooltip" title="This is my message"></a> <div id="svgTarget"></div> </div> <script> $(function () { var gaugeRanges = [ { From: 1.5, To: 2.5, Color: "#8dcb2a" }, { From: 2.5, To: 3.5, Color: "#ffc700" }, { From: 3.5, To: 4.5, Color: "#ff7a00" }, { From: 4.5, To: 6, Color: "#c20000" }]; $("#svgTarget").mttD3Gauge({ data: gaugeRanges }); }); </script> </body> </html> (function ($) { $.fn.mttD3Gauge = function (options) { var vis; var settings = $.extend({ width: 300, innerRadius: 130, outterRadius: 145, majorGraduations: 6, minorGraduations: 10, majorGraduationLenght: 16, minorGraduationLenght: 10, majorGraduationMarginTop: 7, majorGraduationColor: "rgb(234,234,234)", minorGraduationColor:"rgb(234,234,234)", data: [] }, options); this.create = function () { this.html("<svg class='mtt-svgClock' width='" + settings.width + "' height='" + settings.width + "'></svg>"); var maxLimit = 0; var minLimit = 9999999; var d3DataSource = []; //Data Genration $.each(settings.data, function (index, value) { d3DataSource.push([value.From, value.To, value.Color]); if (value.To > maxLimit) maxLimit = value.To; if (value.From < minLimit) minLimit = value.From; }); if (minLimit > 0) { d3DataSource.push([0, minLimit, "#d7d7d7"]); } //Render Gauge Color Area vis = d3.select(this.selector + " .mtt-svgClock"); var translate = "translate(" + settings.width / 2 + "," + settings.width / 2 + ")"; var cScale = d3.scale.linear().domain([0, maxLimit]).range([-120 * (Math.PI / 180), 120 * (Math.PI / 180)]); var arc = d3.svg.arc() .innerRadius(settings.innerRadius) .outerRadius(settings.outterRadius) .startAngle(function (d) { return cScale(d[0]); }) .endAngle(function (d) { return cScale(d[1]); }); vis.selectAll("path") .data(d3DataSource) .enter() .append("path") .attr("d", arc) .style("fill", function (d) { return d[2]; }) .attr("transform", translate); renderMajorGraduations(); return this; }; var renderMinorGraduations = function (majorGraduationsAngles, indexMajor) { var graduationsAngles = []; if (indexMajor > 0) { var minScale = majorGraduationsAngles[indexMajor - 1]; var maxScale = majorGraduationsAngles[indexMajor]; var scaleRange = maxScale - minScale; for (var i = 1; i < settings.minorGraduations; i++) { var scaleValue = minScale + i * scaleRange / settings.minorGraduations; graduationsAngles.push(scaleValue); } var xCenter = settings.width / 2; var yCenter = settings.width / 2; //Render Minor Graduations $.each(graduationsAngles, function (indexMinor, value) { var cos1Adj = Math.round(Math.cos((90 - value) * Math.PI / 180) * (settings.innerRadius - settings.majorGraduationMarginTop - settings.minorGraduationLenght)); var sin1Adj = Math.round(Math.sin((90 - value) * Math.PI / 180) * (settings.innerRadius - settings.majorGraduationMarginTop - settings.minorGraduationLenght)); var cos2Adj = Math.round(Math.cos((90 - value) * Math.PI / 180) * (settings.innerRadius - settings.majorGraduationMarginTop)); var sin2Adj = Math.round(Math.sin((90 - value) * Math.PI / 180) * (settings.innerRadius - settings.majorGraduationMarginTop)); var x1 = xCenter + cos1Adj; var y1 = yCenter + sin1Adj * -1; var x2 = xCenter + cos2Adj; var y2 = yCenter + sin2Adj * -1; vis.append("svg:line") .attr("x1", x1) .attr("y1", y1) .attr("x2", x2) .attr("y2", y2) .style("stroke", settings.majorGraduationColor); }); } }; var renderMajorGraduations = function () { var scaleRange = 240; var minScale = -120; var graduationsAngles = []; for (var i = 0; i <= settings.majorGraduations; i++) { var scaleValue = minScale + i * scaleRange / settings.majorGraduations; graduationsAngles.push(scaleValue); } var xCenter = settings.width / 2; var yCenter = settings.width / 2; //Render Major Graduations $.each(graduationsAngles, function (index, value) { var cos1Adj = Math.round(Math.cos((90 - value) * Math.PI / 180) * (settings.innerRadius - settings.majorGraduationMarginTop - settings.majorGraduationLenght)); var sin1Adj = Math.round(Math.sin((90 - value) * Math.PI / 180) * (settings.innerRadius - settings.majorGraduationMarginTop - settings.majorGraduationLenght)); var cos2Adj = Math.round(Math.cos((90 - value) * Math.PI / 180) * (settings.innerRadius - settings.majorGraduationMarginTop)); var sin2Adj = Math.round(Math.sin((90 - value) * Math.PI / 180) * (settings.innerRadius - settings.majorGraduationMarginTop)); var x1 = xCenter + cos1Adj; var y1 = yCenter + sin1Adj * -1; var x2 = xCenter + cos2Adj; var y2 = yCenter + sin2Adj * -1; vis.append("svg:line") .attr("x1", x1) .attr("y1", y1) .attr("x2", x2) .attr("y2", y2) .style("stroke", settings.majorGraduationColor); renderMinorGraduations(graduationsAngles, index); }); }; return this.create(); }; }(jQuery));