I am trying to draw a rectangle with a dashed strong in SVG using D3 but when I do the top and bottom dashed lines are blurry. Here is my code:
var width = 400,
height = 400;
var svg = d3.select('body')
.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate('+height/2+','+width/2+')');
svg.append('rect')
.attr('width', '185')
.attr('height', '45')
.attr('x', -height/2+185/2)
.attr('y', -width/2+10)
.attr('fill', 'rgba(0,0,0,0)')
.attr('stroke', '#2378ae')
.attr('stroke-dasharray', '10,5')
.attr('stroke-linecap', 'butt')
.attr('stroke-width', '3')
http://jsfiddle.net/sigscotty/9H9PX/
Here is what it looks like in the browser:
Any way to get the top and bottom crisp looking like the sides?
shape-rendering is probably what you want. shape-rendering="crispEdges" should do it for your case. Alternatively you could adjust the y and height attributes so that the top and bottom positions are + 0.5.
Related
I've created a scatter plot in d3. The problem is that the y axis label does not appear in firefox and chrome (works fine in IE). I've tried doing things like making the svg width 100%, but for some reason the label always gets cut off.
<div id="TimeSeriesChartDiv" style="display: inline; float: right; width: 650px;
height: 415px">
</div>
//Width and height
var w = 600;
var h = 300;
var padding = 30;
var margin = { top: 20, right: 20, bottom: 30, left: 20 };
var df = d3.time.format("%b-%y");
//Create scale functions
var xScale = d3.time.scale()
.domain([d3.min(dataset, function (d) { return d[0]; }), d3.max(dataset, function (d) { return d[0]; })])
.range([padding, w - padding * 2])
.nice(5);
var yScale = d3.scale.linear()
.domain([0, d3.max(dataset, function (d) { return d[1]; })])
.range([h - padding, padding]);
//Define X axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(5)
.tickFormat(df);
//Define Y axis
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(5);
//Create SVG element
var svg = d3.select("#TimeSeriesChartDiv")
.append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom);
//Create X axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(20," + (h - padding) + ")")
.call(xAxis);
//Create Y axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + 50 + ",0)")
.call(yAxis);
svg.append("text")
.attr("class", "axislabel")
.attr("text-anchor", "end")
.attr("x", w / 2)
.attr("y", h + 8)
.text("Date");
svg.append("text")//-->>this is the text that gets cut off
.attr("class", "axislabel")
.attr("text-anchor", "end")
.attr("x", -100)
.attr("y", -15)
//.attr("dy", ".75em")
.attr("transform", "rotate(-90)")
.text(unit);
Any ideas would be much appreciated. Thanks
You are using negative coordinates for your text, which means they get drawn outside the SVG. It seems that IE9 doesn't seem to clip thing to the SVG area, other browsers do. The best solution is to add enough padding to your graph so that your text can be drawn inside the SVG. Disabling the clipping does not seem to be supported in all browsers.
Thanks Jan -- with additional help from:
http://www.d3noob.org/2012/12/adding-axis-labels-to-d3js-graph.html
this worked:
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("class", "axislabel")
.attr("text-anchor", "middle")
.attr("x", 0 - (h / 2))
.attr("y",0)//any negative value here wouldnt display in ff or chrome
.attr("dy", "1em")
.text(unit);
I'm working through a book on data visualization with D3. I'm sorta new to this and I am trying to add axis to my chart. The example code works but for some reason when I try to append an axis class to my SVG element, it won't work.
My code is below:
function draw(data) {
//code
"use strict";
var margin = 50,
width = 700,
height = 300;
var x_extent = d3.extent(data, function(d){return d.collision_with_injury});
var y_extent = d3.extent(data, function(d){return d.dist_between_fail});
var x_scale = d3.scale.linear()
.range([margin, width-margin])
.domain(x_extent);
var y_scale = d3.scale.linear()
.range([height-margin, margin])
.domain(y_extent);
var x_axis = d3.svg.axis().scale("x_scale");
var y_axis = d3.svg.axis().scale("y_scale").orient("left");
d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d){return x_scale(d.collision_with_injury)})
.attr("cy", function(d){return y_scale(d.dist_between_fail)})
.attr("r", 5)
d3.select("svg")
.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height-margin) + ")")
.call(x_axis);
d3.select("svg")
.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + margin +", 0)")
.call(y_axis)
d3.select('.y axis')
.append('text')
.text('mean distance between failure (miles)')
.attr('transform', "rotate (-90, -43, 0) translate(-280)")
d3.select('.x axis')
.append('text')
.text('collisions with injury (per million miles)')
.attr('x', function(){return (width / 2) - margin})
.attr('y', margin/1.5)
}
Class names cannot contain spaces. When you run the code .attr("class", "x axis") you're actually assigning the two classes x and axis to the element. This is not a problem as such, but the selector .y axis doesn't work as you would expect for the same reason. It tries to find an element with class y and an axis tag (as you didn't put a dot in front of it). This fails, as there is no such element.
The easiest way to fix this is probably to simply assign a one-word class, e.g. xAxis. Alternatively, you could change your selector to .y .axis to match elements that have those two classes.
I'm having difficulty determining the starting coordinate of the bounding box for the svg text element that corresponds to the label for a D3.js ordinal x-axis.
From the current code the text label DOM node x attributes have values of 0. However the label text is translated. Thus I would use svg.selectAll("g.x.axis g.tick.major").attr("transform") to determine the transform attributes of the label elements. I suppose I could just glean information those return values. Is there an easier method for this?
Here's an example DOM element from the code.
<g class="tick major" transform="translate(73.33333333333333,0)" style="opacity: 1;"><line y2="6" x2="0">
<line y2="6" x2="0"></line>
<text y="9" x="0" dy=".71em" style="text-anchor: middle;">banana</text>
</g>
My script:
var margin = {top: 100, right: 100, bottom: 100, left: 100},
width = 310 - margin.left - margin.right,
height = 200 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.domain(["apple", "orange", "banana", "grapefruit"])
.rangePoints([0, width]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var svg = d3.select("body")
.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 + ")");
svg.append("g")
.attr("class", "x axis")
.call(xAxis);
console.log(svg.selectAll("g.x.axis g.tick.major")
.attr("transform"))
js and I am trying to figure out how to draw a discrete number of rectangles in an SVG element. It could be 5 rectangles to a million. What is the best way to go about this? Should I be using the Ordinal scale since I have a discrete number of rectangles or should I be using the linear scale? So I'm thinking that the width of the rectangles should shrink as the number of rectangles grows larger.
You have to compute the layout and create the appropriate scales. For example:
var width = 300,
height = 20,
margin = 2,
nRect = 20,
rectWidth = (width - (nRect - 1) * margin) / nRect,
svg = d3.select('#chart').append('svg')
.attr('width', width)
.attr('height', height);
var data = d3.range(nRect),
posScale = d3.scale.linear()
.domain(d3.extent(data))
.range([0, width - rectWidth]);
svg.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('x', posScale)
.attr('width', rectWidth)
.attr('height', height);
I wrote a small jsfiddle with this code: http://jsfiddle.net/pnavarrc/CA7rY/
I need to draw a pie chart that's works in IE 8, so I'm using d34raphael.
currently this is my code, which is modified from a d3 pie chart example https://raw.github.com/mbostock/d3/master/examples/pie/pie.html
var width = 300,
height = 300,
outerRadius = Math.min(width, height) / 2,
innerRadius = outerRadius * .6,
data = d3.range(10).map(Math.random),
color = d3.scale.category20(),
donut = d3.layout.pie(),
arc = d3.svg.arc().innerRadius(innerRadius).outerRadius(outerRadius);
// #chart is a div
var paper = new Raphael($('#chart')[0], width, height);
var svg = d3.raphael(paper);
paper.setStart();
var vis = svg.selectAll('rect')
.data([data])
.enter().append('rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', width)
.attr('height', height);
svg.selectAll('path')
.data(donut)
.enter().append('path')
.attr('fill', function(d, i) { return color(i); })
.attr('d', arc)
.attr('transform', 'translate(' + outerRadius + ',' + outerRadius + ')');
paper.setFinish().transform(['t', 0, 0]);
it crashes when I pass donut into the data function, the bind function inside d3's data function has a group argument. after stepping through the data function, I found that group was undefined. (for me, it crashes on d3.v2.js:4997 bind(group = this[i], value.call(group, group.parentNode.__data__, i));, it tries to reference parentNode on the undefined group) I think this may be related to raphael not supporting the g tag. any Ideas on how i can use the d3 pie layout with d34raphael? Thanks