Target this->sibling with mouse event - d3.js

I'm following the book Interactive Data Visualization for the Web (2nd Ed). While learning about adding interactivity to a bar chart, the text states:
Throw an invisible rect with a fill of none and pointer-events value of all on the top of each group. Even though the rect is invisible, it will still trigger mouse events, so you could have the rect span the whole height of the chart. The net effect is that mousing anywhere in that column—even in “empty” whitespace above a short blue bar—would trigger the highlight effect.
I believe I've successfully created the invisible rect in the proper place (at the end, so as to not be behind the visible rects). I can mouse anywhere in the column, even in the empty whitespace above the short blue bar. However, I cannot figure out how to only highlight the blue bar and not the entire container rect.
Fiddle
//Width and height
var w = 600;
var h = 250;
var dataset = [5, 10, 13, 19, 21, 25, 22, 18, 15, 13,
11, 12, 15, 20, 18, 17, 16, 18, 23, 25];
var xScale = d3.scaleBand()
.domain(d3.range(dataset.length))
.rangeRound([0, w])
.paddingInner(0.05);
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset)])
.range([0, h]);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Create groups to hold the bars and text for each data point
var groups = svg.selectAll(".groups")
.data(dataset)
.enter()
.append("g")
.attr("class", "gbar");
//Create bars
groups.append("rect")
.attr("class", "actualRect")
.attr("x", function (d, i) {
return xScale(i);
})
.attr("y", function (d) {
return h - yScale(d);
})
.attr("width", xScale.bandwidth())
.attr("height", function (d) {
return yScale(d);
})
.attr("fill", function (d) {
return "rgb(0, 0, " + Math.round(d * 10) + ")";
});
//Create labels
groups.append("text")
.text(function (d) {
return d;
})
/*.style("pointer-events", "none")*/
.attr("text-anchor", "middle")
.attr("x", function (d, i) {
return xScale(i) + xScale.bandwidth() / 2;
})
.attr("y", function (d) {
return h - yScale(d) + 14;
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");
// Create container rect
// The goal is to be able to hover *above* a bar, but only highlight the visible blue bar to orange.
// I don't understand how to select (this).('actualRect'), instead of (this).("containerRect")
groups.append("rect")
.attr("class", "containerRect")
.attr("x", function (d, i) {
return xScale(i);
})
.attr("y", 0)
.attr("width", xScale.bandwidth())
.attr("height", h)
.attr("fill", "none")
.style("pointer-events", "all")
.on("mouseover", function () {
d3.select(this) // trying to target (this) -> .actualBar
.attr("fill", "orange");
});

You can select the sibling rect by first selecting this.parentNode from within your event callback function, and then making the desired selection.
d3.select(this.parentNode).select('.actualRect').attr("fill", "orange");
//Width and height
var w = 600;
var h = 250;
var dataset = [5, 10, 13, 19, 21, 25, 22, 18, 15, 13,
11, 12, 15, 20, 18, 17, 16, 18, 23, 25];
var xScale = d3.scaleBand()
.domain(d3.range(dataset.length))
.rangeRound([0, w])
.paddingInner(0.05);
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset)])
.range([0, h]);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Create groups to hold the bars and text for each data point
var groups = svg.selectAll(".groups")
.data(dataset)
.enter()
.append("g")
.attr("class", "gbar");
//Create bars
groups.append("rect")
.attr("class", "actualRect")
.attr("x", function (d, i) {
return xScale(i);
})
.attr("y", function (d) {
return h - yScale(d);
})
.attr("width", xScale.bandwidth())
.attr("height", function (d) {
return yScale(d);
})
.attr("fill", function (d) {
return "rgb(0, 0, " + Math.round(d * 10) + ")";
});
//Create labels
groups.append("text")
.text(function (d) {
return d;
})
/*.style("pointer-events", "none")*/
.attr("text-anchor", "middle")
.attr("x", function (d, i) {
return xScale(i) + xScale.bandwidth() / 2;
})
.attr("y", function (d) {
return h - yScale(d) + 14;
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");
// Create container rect
// The goal is to be able to hover *above* a bar, but only highlight the visible blue bar to orange.
// I don't understand how to select (this).('actualRect'), instead of (this).("containerRect")
groups.append("rect")
.attr("class", "containerRect")
.attr("x", function (d, i) {
return xScale(i);
})
.attr("y", 0)
.attr("width", xScale.bandwidth())
.attr("height", h)
.attr("fill", "none")
.style("pointer-events", "all")
.on("mouseover", function () {
d3.select(this.parentNode).select('.actualRect').attr("fill", "orange");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
Fiddle

Related

d3.js plot not displaying within R Shiny plot area

First, let me accept that i am new to d3.js. I am fairly accustomed to R. I have been doing plot in d3.js, thanks to the stack overflow community and some may d3.js example. I came across r2d3 as a mode to connect R and d3.js plots and hence have used the same to build a connection.
I have created a plot in d3.js and wanted to connect it with the R Shiny output. I am able to connect the plot to the R Shiny. But the plot is always coming out of the shiny plot area.
This is How my plot looks in the R Shiny area :
My Existing d3 plot in R Shiny
Requesting your suggestions on the following :
How to fix the d3.js plot within the R Shiny Area.
My Ui.R code is as below :
column(d3Output("clplot"),width = 12)
My server code is as below :
output$clplot <-r2d3::renderD3(
r2d3(data = cl_d3(),script="d3/cl_dilip_v1.js", d3_version = "5")
)
The js code is attached as below :
var margin = { top: 20, right: 20, bottom: 30, left: 50 },
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
var jsondata = [{ "promotedprice": 100, "nonpromotedprice": 350, "avgprice": 230, "x_value": 80, "brand": "Brand1" }, { "promotedprice": 99, "nonpromotedprice": 170, "avgprice": 130, "x_value": 140, "brand": "Brand2" }, { "promotedprice": 47, "nonpromotedprice": 147, "avgprice": 80, "x_value": 200, "brand": "Brand3" }, { "promotedprice": 100, "nonpromotedprice": 250, "avgprice": 220, "x_value": 260, "brand": "Brand4" }, { "promotedprice": 99, "nonpromotedprice": 170, "avgprice": 130, "x_value": 320, "brand": "Brand5" }];
// Creating the colour Category
var color = d3.scaleOrdinal(d3.schemeCategory10);
// Creating the 1st Comapartment
var svg = d3.select("body").append("svg")
.attr("width", 400)
.attr("height", 450);
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// Attach the Promoted Price Rectangle
var g = svg.selectAll("rect")
.data(data)
.enter()
.append("g")
.classed('rect', false)
.on("mouseover", function (d) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html(formatTime(d.x_value) + "<br/>" + d.nonpromotedprice);
//.style("left", (d3.event.pageX) + "px")
//.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function (d) {
div.transition()
.duration(0)
.style("opacity", 0);
})
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
var accent = d3.scaleOrdinal(d3.schemeAccent);
// Line for the 1st Block
g.append("line") // attach a line
.style("stroke", "#E6EAEE")
.style("stroke-width", 17) // colour the line
.attr("x1", function (d) { return d.x_value; }) // x position of the first end of the line
.attr("y1", function (d) { return d.nonpromotedprice; }) // y position of the first end of the line
.attr("x2", function (d) { return d.x_value; }) // x position of the second end of the line
.attr("y2", function (d) { return d.promotedprice; });
// Promoted Price Rectangle for the 1st Block
g.append("rect")
.attr("width", 24)
.attr("height", 13)
.attr("x", function (d) { return d.x_value - 12; })
.attr("y", function (d) { return d.promotedprice; })
.attr("fill", function (d) { return color(d.x_value); })
// Non Promoted Price Rectangle for the 1st Block
g.append("rect")
.attr("width", 24)
.attr("height", 13)
.attr("x", function (d) { return d.x_value - 12; })
.attr("y", function (d) { return d.nonpromotedprice; })
.attr("fill", function (d) { return color(d.x_value); })
// Average Price Rectangle for the 1st Block
g.append("rect")
.attr("width", 24)
.attr("height", 13)
.attr("x", function (d) { return d.x_value - 12; })
.attr("y", function (d) { return d.avgprice; })
.attr("fill", function (d) { return color(d.x_value); });
// Graph X- Axis and Title Text for 1st svg
var y_scale = d3.scaleLinear()
//.domain([d3.min(function (d) { return d.promotedprice }), d3.max(function (d) { return d.nonpromotedprice; })])
.range([370, 0]);
var y_axis = d3.axisLeft()
.scale(y_scale);
y_scale.domain([0, d3.max(data, function (d) { return d.nonpromotedprice; })]).nice();
g.append("g")
.attr("class", "grid")
.attr("transform", "translate(0, 40)")
.attr("fill", "lightgrey")
.attr("stroke-width", 0.15)
.attr("stroke-opacity", 0.2)
//.attr("shape-rendering", crispEdges)
//stroke-opacity: 0.7;shape-rendering: crispEdges;
.call(y_axis
.tickSize(-420)
.tickFormat(""))
;
// PEPSICO AS-IS BRAND CALL OUT
g.append("rect")
.attr("width", 38)
.attr("height", 20)
.attr("x", function (d) { return d.x_value - 2; })
.attr("y", function (d) { return d.promotedprice; })
.attr("fill", function (d) { return color(d.x_value); })
.attr("transform", "translate(" + -15 + "," + -40 + ")");
g.append("text")
//.classed('rotation', true)
//.attr('x', (d,i)=> xScale(i))
.attr("x", function (d) { return d.x_value - 13; })
.attr("y", function (d) { return d.promotedprice - 28; })
.attr("dy", ".35em")
.text(function (d) { return d.brand; })
.style("font-family", "arial")
.style("font-size", 8)
.attr("stroke-width", 0.15)
.attr("fill", "white");
function dragstarted(d) {
d3.select(this).raise().classed("active", true);
}
function dragged(d) {
d3.select(this).select("rect").attr("y", d.y = d3.event.y);
//.attr("x", d.x = d3.event.x)
}
function dragended(d)
{
d3.select(this).classed("active", false);
}
Try to delete this part of code:
var svg = d3.select("body").append("svg")
.attr("width", 400)
.attr("height", 450);

must it need a full-fill rectangle element in a g(group) element to activate the whole elements within the g element?

when g tag is bonded to a mouseover event whether elements within the g tag response in concert to the mouseover and don't need another rectangle to fill the g tag?
I am following a d3.js book, it refers to a situation that one visible element (here is a text tag) overlaps another (here is a rectangle), and if I bind an event (here is mouseover) to the deeper element, it won't call the event when your mouse over the upper element (the text tag) .
and it gives a solution that you can group the rect and text tags together, and bind the event to the g element so that both rect and text could work.
but it also needs a CSS code: pointer-events: all and another rectangle to overlap the whole the rectangle and text tags inside the g tag, in this case, it will work.
<head>
<meta charset="utf-8">
<title>D3: Smoother highlight transitions</title>
<script type="text/javascript" src="../d3.js"></script>
<style type="text/css">
/* No style rules here yet */
</style>
</head>
<body>
<script type="text/javascript">
//Width and height
var w = 600;
var h = 250;
var dataset = [5, 10, 13, 19, 21, 25, 22, 18, 15, 13,
11, 12, 15, 20, 18, 17, 16, 18, 23, 25
];
var xScale = d3.scaleBand()
.domain(d3.range(dataset.length))
.rangeRound([0, w])
.paddingInner(0.05);
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset)])
.range([0, h]);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Create bars
svg.selectAll("g")
.data(dataset)
.enter()
.append("g")
.append("rect")
.attr("x", function(d, i) {
return xScale(i);
})
.attr("y", function(d) {
return h - yScale(d);
})
.attr("width", xScale.bandwidth())
.attr("height", function(d) {
return yScale(d);
})
.attr("fill", function(d) {
return "rgb(0, 0, " + Math.round(d * 10) + ")";
});
//Create labels
svg.selectAll("g")
.append("text")
.text(function(d) {
return d;
})
.attr("text-anchor", "middle")
.attr("x", function(d, i) {
return xScale(i) + xScale.bandwidth() / 2;
})
.attr("y", function(d) {
return h - yScale(d) + 14;
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");
//*****************to add a mouseover event to g tag and overlap the rectangle and text tags above with a rectangle***************************
svg.selectAll("g")
.style("pointer-events", "all")
.on("mouseover", function() {
d3.select(this)
.select("rect")
.attr("fill", "orange");
})
.on("mouseout", function(d) {
d3.select(this)
.select("rect")
.transition()
.duration(250)
.attr("fill", "rgb(0, 0, " + (d * 10) + ")");
})
.append("rect")
.attr("x", function(d, i) {
return xScale(i);
})
.attr("y", function(d) {
return h - yScale(d);
})
.attr("width", xScale.bandwidth())
.attr("height", function(d) {
return yScale(d);
})
//*****************make it invisible*********************************
.attr("fill", "none");
</script>
</body>
you could copy it into an empty HTML file, and load it, it's a bar chart.
the only question is if a rectangle is needed to fill the unempty g tag to make the bar rectangles and text response together.

how to highlight a bar in stacked bar chart d3.js v4

I want to highlight a bar with April (value in x-axis) with a square box. but I am not getting a approach to do the same.
tried getting the co-ordinates of the respected bar, but unable to find a solution for the same
Unable to find the co-ordinates of the respective bar which I need to highlight.
what should be the approach for highlighting a bar with a square box in stacked bar chart d3.js v4
createStackedBarChart(130,300,10,60,20,45,"manager-line-graph-2");
function createStackedBarChart(height,width,top,right,bottom,left,id){
var margin = {top: top, right: right, bottom: bottom, left: left };
//console.log("margin"+margin);
var svg = d3.select("#"+id).append("svg"),
width = width - margin.left - margin.right,
height = height - margin.top - margin.bottom,
g = svg.attr("width", "100%")
.attr("height", height + margin.top + margin.bottom)
.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleBand()
.rangeRound([0, width])
.padding(0.2)
.align(5.0);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var z = d3.scaleOrdinal()
.range(["#0000FF", "#00FFFF", "#81F781", "#F3F781", "#FE2E2E"]);
var data = [
{"Months": "Feb","Installation": 5,"Product": 10,"Payment": 15,"Billing": 20,"Outage": 25},
{"Months": "March","Installation": 6,"Product": 8,"Payment": 9,"Billing": 15,"Outage": 18},
{"Months": "April","Installation": 9,"Product": 12,"Payment": 24,"Billing": 17,"Outage": 14},
{"Months": "May","Installation": 9,"Product": 12,"Payment": 14,"Billing": 17,"Outage": 14},
{"Months": "June","Installation": 9,"Product": 12,"Payment": 15,"Billing": 11,"Outage": 10}
];
// fix pre-processing
var keys = [];
for (key in data[0]){
if (key != "Months")
keys.push(key);
}
console.log("value of keys are " + keys);
data.forEach(function(d){
d.total = 0;
keys.forEach(function(k){
d.total += d[k];
})
});
//data.sort(function(a, b) {
//return b.total - a.total;
//});
x.domain(data.map(function(d) {
return d.Months;
}));
y.domain([0, d3.max(data, function(d) {
return d.total;
})]).nice();
z.domain(keys);
g.append("g")
.selectAll("g")
.data(d3.stack().keys(keys)(data))
.enter().append("g")
.attr("fill", function(d) {return z(d.key);})
.selectAll("rect")
.data(function(d) { return d; })
.enter().append("rect")
.attr("x", function(d) {
return x(d.data.Months);
})
.attr("y", function(d) {
return y(d[1]);
})
.attr("height", function(d) {
return y(d[0]) - y(d[1]);
})
.attr("width", x.bandwidth()-5);
g.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).ticks(5));
g.append("g")
.attr("class", "axis")
.call(d3.axisLeft(y).ticks(5, "s"))
.append("text")
.attr("x", 2)
.attr("y", y(y.ticks(5).pop()))
.attr("dy", "0.32em")
.attr("fill", "#000")
.attr("font-weight", "bold")
.attr("text-anchor", "start")
var legend = g.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("text-anchor", "end")
.selectAll("g")
.data(keys.slice().reverse())
.enter().append("g")
.attr("transform", function(d, i) {
return "translate(0," + i * 20 + ")";
});
//legend.append("rect")
//.attr("x", width + 20)
//.attr("width", 10)
//.attr("height", 10)
//.attr("fill", z);
legend.append("circle")
.attr("r",5)
.attr("cx", width+30)
.attr("cy", 0)
.attr("fill",z);
legend.append("text")
.attr("x", width + 88)
.attr("y", 3.5)
.attr("dy", "0.12em")
.text(function(d) {
return`enter code here` d;
});
}
One solution I have used previously is to create an invisible layer of bars for the same data. Then use the .on("mouseover", function...); to make the bars for that data visible again by changing the styles or the fill opacity.
Here is a sample bl.ock with what I mean. It is a grouped bar chart with ordinal scale, but the same could be applied to your data with some tweaking.
https://bl.ocks.org/Coola85/b05339b65a7f9b082ca210d307a3e469
Update May 5, 2018: upon further reading I see your issue is different than the solution I suggested. This link might give you a good starting point of how to use an if statement to selectively highlight particular data.
so you could use the following style for your rect
.style ("fill", function(d) {
if (d.Months === "April") {return "red"} // <== Add these
else { return "black" }
})

d3 horizontal bar chart with background and max value of 100%

I have this single horizontal bar chart and I want to make the following adjustments:
Show the tick value to the right of the bar chart, instead of by the axis.
Show a background for the bar chart scale instead of left and bottom axis.
Current version:
What I'd like to get to:
JS
var data = [
{"yAxis":"score", "xAxis":"72"}
];
// set the dimensions and margins of the graph
var margin = {top: 20, right: 20, bottom: 30, left: 80},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// set the ranges
var y = d3.scaleBand()
.range([height, 0])
.padding(0.4);
var x = d3.scaleLinear()
.range([0, width]);
var svg = d3.select(".barChartContainer").append("svg")
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "0 0 960 500")
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Scale the range of the data in the domains
x.domain([0, d3.max(data, function(d){ return d.xAxis; })])
y.domain(data.map(function(d) { return d.yAxis; }));
//y.domain([0, d3.max(data, function(d) { return d.prereqs; })]);
// append the rectangles for the bar chart
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("y", function(d) { return y(d.yAxis); })
.attr("height", y.bandwidth())
.transition()
.duration(1000)
.delay(function(d, i) {
return i * 100
})
.attr("width", function(d) {return x(d.xAxis); } );
// add the x Axis
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).tickValues(d3.range(x.domain()[0], x.domain()[1] + 1, 1))
.tickFormat(d3.format("d"))
);
svg.append("g")
.attr("class", "yAxis")
.call(d3.axisLeft(y));
I got this code from a codepen and I've been trying to adapt it, but it has been breaking so I stopped and was hoping you could help.
Thanks.
For showing the background for the bars, just copy your selection and chose a value of 100% for the rectangles, in a light gray fill:
var backgroundBar = svg.selectAll(null)
.data(data)
.enter()
.append("rect")
//etc...
.attr("width", function(d) {
return x(100);
});
Of course, you'll have to change the domain of the x scale:
var x = d3.scaleLinear()
.domain([0, 100]);
Then, drop both axis and print the labels using a text selection.
Finally, use another text selection for the values:
var values = svg.selectAll(null)
.data(data)
.enter()
.append("text")
//etc...
.text(function(d) {
return +d.xAxis
})
If you want, you can tween the text:
.attrTween("text", function(d) {
var self = this
var i = d3.interpolateNumber(0, +d.xAxis);
return function(t) {
return d3.select(self).text(~~i(t));
}
});
This is the result:
var data = [{
"yAxis": "score",
"xAxis": "72"
}];
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 80
},
width = 500 - margin.left - margin.right,
height = 200 - margin.top - margin.bottom;
var y = d3.scaleBand()
.range([height, 0])
.padding(0.4);
var x = d3.scaleLinear()
.range([0, width])
.domain([0, 100]);
var svg = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 200)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
y.domain(data.map(function(d) {
return d.yAxis;
}));
var backgroundBar = svg.selectAll(null)
.data(data)
.enter()
.append("rect")
.attr("fill", "lightgray")
.attr("y", function(d) {
return y(d.yAxis);
})
.attr("height", y.bandwidth())
.attr("width", function(d) {
return x(100);
});
var bar = svg.selectAll(null)
.data(data)
.enter()
.append("rect")
.attr("class", "bar")
.attr("y", function(d) {
return y(d.yAxis);
})
.attr("height", y.bandwidth())
.transition()
.duration(2000)
.delay(function(d, i) {
return i * 100
})
.attr("width", function(d) {
return x(d.xAxis);
});
var labels = svg.selectAll(null)
.data(data)
.enter()
.append("text")
.attr("y", function(d) {
return y(d.yAxis) + y.bandwidth() / 2;
})
.attr("x", -10)
.attr("text-anchor", "end")
.text(function(d) {
return d.yAxis
});
var values = svg.selectAll(null)
.data(data)
.enter()
.append("text")
.attr("y", function(d) {
return y(d.yAxis) + y.bandwidth() / 2;
})
.attr("x", 10)
.text(function(d) {
return +d.xAxis
})
.transition()
.duration(2000)
.delay(function(d, i) {
return i * 100
})
.attr("x", function(d) {
return x(d.xAxis) + 10;
})
.attrTween("text", function(d) {
var self = this
var i = d3.interpolateNumber(0, +d.xAxis);
return function(t) {
return d3.select(self).text(~~i(t));
}
});
<script src="https://d3js.org/d3.v4.min.js"></script>

Creating a border around your D3 graph

So I've just started my D3 journey, and wanted to ask about how one would create a small 1px border around the chart.
I created the variables "border" and "bordercolor" and then I added .attr("border",border) to the var svg = d3.select("body") portion of my code. It doesn't crash, but I get no border either.
I guess the question is how do i add this border, and if someone could explain why what i did is wrong.
<script type="text/javascript">
//Width and height
var w = 800;
var h = 400;
var padding = 20;
var border=1;
var bordercolor='black';
var dataset = [
[5, 20], [480, 90], [250, 50], [100, 33], [330, 95],[-50,-100],[50,-45],
[410, 12], [475, 44], [25, 67], [85, 21], [220, 88],[-480, 90], [3,-90]
];
// create scale functions
var xScale = d3.scale.linear()
.domain([d3.min(dataset, function(d) { return d[0]; }), d3.max(dataset, function(d) { return d[0]; })])
.range([padding, w - padding * 2]);
var yScale = d3.scale.linear()
.domain([d3.min(dataset, function(d) { return d[0]; }), d3.max(dataset, function(d) { return d[1]; })])
.range([h - padding, padding]);
var rScale = d3.scale.linear()
.domain( [-100, d3.max(dataset, function(d) { return d[1]; })] )
.range([2,5]);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h)
.attr("border",border)
;
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) {
return xScale(d[0]);
})
.attr("cy", function(d) {
return yScale(d[1]);
})
.attr("r", 3);
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
return d[0] + "," + d[1];
})
.attr("x", function(d) {
return xScale(d[0]);
})
.attr("y", function(d) {
return yScale(d[1]);
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "red");
</script>
Use the style attribute to place an outline around the svg:
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("style", "outline: thin solid red;") //This will do the job
.attr("width", w)
.attr("height", h);
The svg var is just a container. You need to add a path or element to the container and then give it the stroke color and width you want for your border. There is more than one way to do this. In this gist I did it by adding a rect with the following values:
var borderPath = svg.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("height", h)
.attr("width", w)
.style("stroke", bordercolor)
.style("fill", "none")
.style("stroke-width", border);
IMHO it's better to keep separated shape from style instructions:
.append("rect")
.attr("x", 5)
.attr("y", 5)
.attr("height", 40)
.attr("width", 50)
.attr("class","foo")
...
CSS:
svg rect.foo {
fill: white;
stroke-width: 0.5;
stroke: grey;
}
Simply use css:
svg {
border:1px solid black;
}
If X and Y Axis are used, other option is to use tickSizeOuter()
Example:
var yAxis = d3.axisLeft(y).ticks(5).tickSizeOuter(-width);
var xAxis = d3.axisBottom(x).ticks(5).tickSizeOuter(-height);

Resources