D3 x3dom - 3d scatter plot - d3.js
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!
Related
Fill not working with areaRadial() generated shape
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. :)
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
The bar in the d3 graph is going out of range and i am not able to select it using a brush
I have created a d3 graph to show the event count per day so the xaxis shows date and y axis shows count. I have also included brush event to filter data accordingly. but the last bar is shown outof range and i am not able to select it using brush. Now how can i make it look proper. I am adding an image of it and code too ... Everything is coming fine except the selection. please help me out. thanku :) var data = document.getElementById('eventCountList').innerHTML; flights = JSON.parse(data); // Various formatters. var formatNumber = d3.format(",d"), formatChange = d3.format("+,d"), formatDate = d3.time .format("%B %d, %Y"), formatTime = d3.time .format("%I:%M:%S %p"); // A nest operator, for grouping the flight list. var nestByDate = d3.nest().key(function(d) { return d3.time.day(d.date); }); // A little coercion, since the CSV is untyped. flights.forEach(function(d, i) { d.index = i; console.log(d.eventTimeGmt); d.date = parseDate(String(d.eventTimeGmt)); }); // Create the crossfilter for the relevant dimensions and groups. var flight = crossfilter(flights), all = flight.groupAll(), date = flight .dimension(function(d) { return d.date; }), dates = date.group(d3.time.day), second = flight .dimension(function(d) { return d.date.getSeconds(); }), seconds = second.group(Math.floor), minute = flight .dimension(function(d) { return d.date.getMinutes() + d.date.getSeconds() / 60; }), minutes = minute.group(Math.floor), hour = flight .dimension(function(d) { return d.date.getHours() + d.date.getMinutes() / 60; }), hours = hour.group(Math.floor); var charts = [ barChart().dimension(second).group(seconds).x( d3.scale.linear().domain([ 0, 60 ]).rangeRound( [ 0, 10 * 60 ])), barChart().dimension(minute).group(minutes).x( d3.scale.linear().domain([ 0, 60 ]).rangeRound( [ 0, 10 * 60 ])), barChart().dimension(hour).group(hours).x( d3.scale.linear().domain([ 0, 24 ]).rangeRound( [ 0, 10 * 60 ])), barChart() .dimension(date) .group(dates) .round(d3.time.hour.round) .x( d3.time .scale() .domain( [ new Date( flights[flights.length - 1].eventTimeGmt .substring( 0, 4), flights[flights.length - 1].eventTimeGmt .substring( 5, 7) - 1, flights[flights.length - 1].eventTimeGmt .substring( 8, 10)), new Date( flights[0].eventTimeGmt .substring( 0, 4), flights[0].eventTimeGmt .substring( 5, 7) - 1, flights[0].eventTimeGmt .substring( 8, 10)) ]) .rangeRound([ 0, 10 * 60 ])) /*.filter( [ new Date(2001, 1, 1), new Date(2001, 2, 1) ]) */ ]; // Given our array of charts, which we assume are in the same order as the // .chart elements in the DOM, bind the charts to the DOM and render them. // We also listen to the chart's brush events to update the display. var chart = d3.selectAll(".chart").data(charts).each( function(chart) { chart.on("brush", renderAll).on("brushend", renderAll); }); // Render the initial lists. var list = d3.selectAll(".list").data([ flightList ]); // Render the total. d3.selectAll("#total").text(formatNumber(flight.size())); renderAll(); // Renders the specified chart or list. function render(method) { d3.select(this).call(method); } // Whenever the brush moves, re-rendering everything. function renderAll() { chart.each(render); list.each(render); d3.select("#active").text(formatNumber(all.value())); } // Like d3.time.format, but faster //2015-12-28 11:18:32 function parseDate(d) { return new Date(d.substring(0, 4), d.substring(5, 7) - 1, d .substring(8, 10), d.substring(11, 13), d.substring(14, 16), d.substring(17, 19)); } window.filter = function(filters) { filters.forEach(function(d, i) { charts[i].filter(d); }); renderAll(); }; window.reset = function(i) { charts[i].filter(null); window.poll.start(); renderAll(); }; function flightList(div) { var flightsByDate = nestByDate.entries(date.top(40)); div.each(function() { var date = d3.select(this).selectAll(".date").data( flightsByDate, function(d) { return d.key; }); date.enter().append("div").attr("class", "date").append( "div").attr("class", "day").text(function(d) { return formatDate(d.values[0].date); }); date.exit().remove(); var flight = date.order().selectAll(".flight").data( function(d) { return d.values; }, function(d) { return d.index; }); var flightEnter = flight.enter().append("div").attr( "class", "flight"); flightEnter.append("div").attr("class", "time").text( function(d) { return formatTime(d.date); }); flightEnter.append("div").attr("class", "sourceAddress") .text(function(d) { return d.sourceAddress; }); flightEnter.append("div").attr("class", "destAddress") .text(function(d) { return d.destAddress; }); flight.exit().remove(); flight.order(); }); } function barChart() { if (!barChart.id) barChart.id = 0; var margin = { top : 10, right : 10, bottom : 20, left : 40 }, x, y = d3.scale.linear().range([ 100, 0 ]), id = barChart.id++, axis = d3.svg .axis().orient("bottom"), yAxisLeft = d3.svg.axis() .scale(y).orient("left"), brush = d3.svg.brush(), brushDirty, dimension, group, round; function chart(div) { var width = x.range()[1], height = y.range()[0]; y.domain([ 0, group.top(1)[0].value ]); div.each(function() { var div = d3.select(this), 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", function(d) { return 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); g.append("g").attr("class", "y axis").attr( "transform", "translate(" + 0 + ")", 0) .call(yAxisLeft); g.append("text").attr( "transform", "rotate(-90 " + margin.left / 1.8 + " " + height / 2 + ")").style( "text-anchor", "start") .style("fill", "red") .text("no. of events "); /* g.append("text") .attr("transform", "translate(" + (width / 2) + " ," + (height + margin.bottom) + ")") .style("text-anchor", "middle") .text("Date"); */ /* g.append("text") .attr("transform", "rotate(-90)") .attr("y", 0 – margin.left) .attr("x",0 - (height / 2)) .attr("dy", "1em") .style("text-anchor", "middle") .text("no. of events"); */ // Initialize the brush component with pretty resize handles. var gBrush = g.append("g").attr("class", "brush") .call(brush); gBrush.selectAll("rect").attr("height", height); gBrush.selectAll(".resize").append("path").attr( "d", resizePath); } // Only redraw the brush if set externally. if (brushDirty) { brushDirty = false; g.selectAll(".brush").call(brush); div.select(".title a").style("display", brush.empty() ? "none" : null); if (brush.empty()) { g.selectAll("#clip-" + id + " rect").attr("x", 0).attr("width", width); } else { var extent = brush.extent(); g.selectAll("#clip-" + id + " rect").attr("x", x(extent[0])).attr("width", x(extent[1]) - x(extent[0])); } } g.selectAll(".bar").attr("d", barPath); }); function barPath(groups) { var path = [], i = -1, n = groups.length, 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) { var e = +(d == "e"), x = e ? 1 : -1, y = height / 3; return "M" + (.5 * x) + "," + y + "A6,6 0 0 " + e + " " + (6.5 * x) + "," + (y + 6) + "V" + (2 * y - 6) + "A6,6 0 0 " + e + " " + (.5 * x) + "," + (2 * y) + "Z" + "M" + (2.5 * x) + "," + (y + 8) + "V" + (2 * y - 8) + "M" + (4.5 * x) + "," + (y + 8) + "V" + (2 * y - 8); } } brush.on("brushstart.chart", function() { window.poll.stop(); var div = d3.select(this.parentNode.parentNode.parentNode); div.select(".title a").style("display", null); }); brush.on("brush.chart", function() { var g = d3.select(this.parentNode), extent = brush .extent(); if (round) g.select(".brush").call( brush .extent(extent = extent .map(round))) .selectAll(".resize").style("display", null); g.select("#clip-" + id + " rect").attr("x", x(extent[0])).attr("width", x(extent[1]) - x(extent[0])); dimension.filterRange(extent); }); brush.on("brushend.chart", function() { if (brush.empty()) { var div = d3 .select(this.parentNode.parentNode.parentNode); div.select(".title a").style("display", "none"); div.select("#clip-" + id + " rect").attr("x", null) .attr("width", "120%"); dimension.filterAll(); } }); chart.margin = function(_) { if (!arguments.length) return margin; margin = _; return chart; }; chart.x = function(_) { if (!arguments.length) return x; x = _; axis.scale(x); brush.x(x); return chart; }; chart.y = function(_) { if (!arguments.length) return y; y = _; yAxisLeft.scale(y); return chart; }; chart.dimension = function(_) { if (!arguments.length) return dimension; dimension = _; return chart; }; chart.filter = function(_) { if (_) { brush.extent(_); dimension.filterRange(_); } else { brush.clear(); dimension.filterAll(); } brushDirty = true; return chart; }; chart.group = function(_) { if (!arguments.length) return group; group = _; return chart; }; chart.round = function(_) { if (!arguments.length) return round; round = _; return chart; }; return d3.rebind(chart, brush, "on"); } };
I have added a day as an offset. that solved my problem.below is my code that solved my problem..... d3.time.day.offset(new Date(flights[0].eventTimeGmt.substring(0,4) ,flights[0].eventTimeGmt.substring(5,7)-1, flights[0].eventTimeGmt.substring(8,10)), 1)
d3.js zoom transition with map tiles
I'm trying to implement a zoom transition on a map that uses tiles. I want to zoom in on one location, then go back and forth between two other locations. This is the example I'm working from: http://bl.ocks.org/mbostock/6242308 That does what I want, only I wish to use map tiles instead of a topojson or geojson file. Right now the map is calling the final location in the jump function, but the transitions between locations aren't working. Any idea on what's happening would be greatly welcomed-- nothing showing in console and I'm a bit stuck. Many thanks. My code is below, and it's also in this plunker. <!DOCTYPE html> <meta charset="utf-8"> <style> body { margin: 0; } #container { position: relative; overflow: hidden; } #map{ width:100%; height:100%; } .layer { position: absolute; } .tile { pointer-events: none; position: absolute; width: 256px; height: 256px; } </style> <body> <script src="http://d3js.org/d3.v3.min.js"></script> <script src="http://d3js.org/d3.geo.tile.v0.min.js"></script> <div id="canvas"> <div id="container"> <g id="map"> <div class="layer"></div> </div> </div> </div> <script> var width = Math.max(960, window.innerWidth), height = Math.max(500, window.innerHeight), prefix = prefixMatch(["webkit", "ms", "Moz", "O"]); var tile = d3.geo.tile() .size([width, height]); var sf = [-122.417, 37.775], belowsf = [-122.510962, 37.580284], ny = [-74.0064, 40.7142], brooklyn = [-73.975536, 40.691674]; var projection = d3.geo.mercator() .scale(200000) .translate([-width / 2, -height / 2]); // just temporary var zoom = d3.behavior.zoom(); var canvas = d3.select("#canvas") .style("width", width + "px") .style("height", height + "px"); var container = d3.select("#container") .style("width", width + "px") .style("height", height + "px"); canvas .call(zoomTo(ny,200300).event) .transition() .duration(20000) .each(jump); var map = d3.select("#map"); var layer = d3.select(".layer"); function zoomTo(location, newscale) { return zoom .scale((newscale) * 2 * Math.PI) .translate(projection(location).map(function(x) { return -x; })); } function jump() { var t = d3.select(this); (function repeat() { t = t.transition() .call(zoomTo(sf, 200000).event) .transition() .call(zoomTo(belowsf, 200000).event) .each("end", repeat); })(); } zoomed(); function zoomed() { var tiles = tile .scale(zoom.scale()) .translate(zoom.translate()) (); projection .scale(zoom.scale() / 2 / Math.PI) .translate(zoom.translate()); var image = layer .style(prefix + "transform", matrix3d(tiles.scale, tiles.translate)) .selectAll(".tile") .data(tiles, function(d) { return d; }); image.exit() .remove(); image.enter().append("img") .attr("class", "tile") .attr("src", function(d) { return "http://" + ["a", "b", "c"][Math.random() * 3 | 0] + ".basemaps.cartocdn.com/light_all/" + d[2] + "/" + d[0] + "/" + d[1] + ".png"; }) .style("left", function(d) { return (d[0] << 8) + "px"; }) .style("top", function(d) { return (d[1] << 8) + "px"; }); } function matrix3d(scale, translate) { var k = scale / 256, r = scale % 1 ? Number : Math.round; return "matrix3d(" + [k, 0, 0, 0, 0, k, 0, 0, 0, 0, k, 0, r(translate[0] * scale), r(translate[1] * scale), 0, 1 ] + ")"; } function prefixMatch(p) { var i = -1, n = p.length, s = document.body.style; while (++i < n) if (p[i] + "Transform" in s) return "-" + p[i].toLowerCase() + "-"; return ""; } function formatLocation(p, k) { var format = d3.format("." + Math.floor(Math.log(k) / 2 - 2) + "f"); return (p[1] < 0 ? format(-p[1]) + "°S" : format(p[1]) + "°N") + " " + (p[0] < 0 ? format(-p[0]) + "°W" : format(p[0]) + "°E"); } </script> </body> </html>
After a lot of headscratching it turned out that the main thing was that you didn't actually tell the zoom behaviour to call the zoomed function: var zoom = d3.behavior.zoom().on("zoom", zoomed); This required moving some variable definitions such that everything is defined when this is called. Apart from that, you don't need to adjust the projection in the zoom handler, as the zoom of the tiles is achieved by setting a transform on the container. Complete demo here.
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.