I am interested to create a line chart -- that draws itself from left to right -- essentially connecting dots in the x-axis.
http://bl.ocks.org/markmarkoh/8700606
http://bl.ocks.org/duopixel/4063326
This is the jsfiddle that I've made to start creating this chart.
http://jsfiddle.net/NYEaX/1512/
//__invoke line
$('[data-role="line"]').each(function(index) {
createLine(this);
});
function createLine(el){
var w = $(el).data("width");
var h = $(el).data("height");
var svg = d3.select($(el)[0])
.append("svg")
.attr("width", w)
.attr("height", h);
var data = d3.range(11).map(function(){return Math.random()*10})
var x = d3.scale.linear().domain([0, 10]).range([0, 700]);
var y = d3.scale.linear().domain([0, 10]).range([10, 290]);
var line = d3.svg.line()
.interpolate("cardinal")
.x(function(d,i) {return x(i);})
.y(function(d) {return y(d);})
var path = svg.append("path")
.attr("d", line(data))
.attr("stroke", "steelblue")
.attr("stroke-width", "2")
.attr("fill", "none");
var totalLength = path.node().getTotalLength();
path
.attr("stroke-dasharray", totalLength + " " + totalLength)
.attr("stroke-dashoffset", totalLength)
.transition()
.duration(2000)
.ease("linear")
.attr("stroke-dashoffset", 0);
svg.on("click", function(){
path
.transition()
.duration(2000)
.ease("linear")
.attr("stroke-dashoffset", totalLength);
});
/* plot axis */
var padding = 100; // space around the chart, not including labels
// define the x axis
var xAxis = d3.svg.axis()
.orient("bottom")
.scale(x);
//.tickFormat(date_format);
// draw x axis with labels and move to the bottom of the chart area
svg.append("g")
.attr("class", "xaxis axis") // two classes, one for css formatting, one for selection below
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
/* plot axis */
}
One solution that you can do is to append svg circles that correspond with the path before drawing the path. Example Fiddle: http://jsfiddle.net/stancheta/ystymLm4/6/
var circles = svg.selectAll("dot")
.data(data)
.enter().append("svg:circle")
.attr('class', 'circ')
.attr("r", 3)
.attr("cx", function(d, i) { return x(i); })
.attr("cy", function(d, i) { return y(d); })
.style('fill', 'lightsteelblue');
Related
This is my first time using d3.js, so please bear with me. I am implementing this inside of a vue.js file as pure javascript.
I am trying to make a scatter plot with zooming capabilities. So far I have everything nearly working, but when I zoom I notice that the x-axis isn't scaling properly, but the y-axis is working properly. For instance, when looking at the original plot, a point may be at around 625 on the x-axis, but after zooming in the same point will be less than 600. This is not happening with the y-axis - those points scale properly. I am assuming that something is wrong with the scaling of the x-axis in my zoom function, but I just can't figure it out. Please take a look, and let me know if you can see where I went wrong.
Edit: I should mention that this is using d3.js version 7.4.4
<template>
<div id="reg_plot"></div>
</template>
<script>
import * as d3 from 'd3';
export default {
name: 'regCamGraph',
components: {
d3
},
methods: {
createSvg() {
// dimensions
var margin = {top: 20, right: 20, bottom: 30, left: 40},
svg_dx = 1400,
svg_dy =1000,
chart_dx = svg_dx - margin.right - margin.left,
chart_dy = svg_dy - margin.top - margin.bottom;
// data
var y = d3.randomNormal(400, 100);
var x_jitter = d3.randomUniform(-100, 1400);
var d = d3.range(1000)
.map(function() {
return [x_jitter(), y()];
});
// fill
var colorScale = d3.scaleLinear()
.domain(d3.extent(d, function(d) { return d[1]; }))
.range([0, 1]);
// y position
var yScale = d3.scaleLinear()
.domain(d3.extent(d, function(d) { return d[1]; }))
.range([chart_dy, margin.top]);
// x position
var xScale = d3.scaleLinear()
.domain(d3.extent(d, function(d) { return d[0]; }))
.range([margin.right, chart_dx]);
console.log("chart_dy: " + chart_dy);
console.log("margin.top: " + margin.top);
console.log("chart_dx: " + chart_dx);
console.log("margin.right: " + margin.right);
// y-axis
var yAxis = d3.axisLeft(yScale);
// x-axis
var xAxis = d3.axisBottom(xScale);
// zoom
var svg = d3.select("#reg_plot")
.append("svg")
.attr("width", svg_dx)
.attr("height", svg_dy);
svg.call(d3.zoom().on("zoom", zoom)); // ref [1]
// plot data
var circles = svg.append("g")
.attr("id", "circles")
.attr("transform", "translate(200, 0)")
.selectAll("circle")
.data(d)
.enter()
.append("circle")
.attr("r", 4)
.attr("cx", function(d) { return xScale(d[0]); })
.attr("cy", function(d) { return yScale(d[1]); })
.style("fill", function(d) {
var norm_color = colorScale(d[1]);
return d3.interpolateInferno(norm_color)
});
// add y-axis
var y_axis = svg.append("g")
.attr("id", "y_axis")
.attr("transform", "translate(75,0)")
.call(yAxis).style("font-size", "20px")
// add x-axis
var x_axis = svg.append("g")
.attr("id", "x_axis")
.attr("transform", `translate(${margin.left}, ${svg_dy - margin.bottom})`)
.call(xAxis).style("font-size", "20px")
function zoom(e) {
// re-scale y axis during zoom
y_axis.transition()
.duration(50)
.call(yAxis.scale(e.transform.rescaleY(yScale)));
// re-scale x axis during zoom
x_axis.transition()
.duration(50)
.call(xAxis.scale(e.transform.rescaleX(xScale)));
// re-draw circles using new y-axis scale
var new_xScale = e.transform.rescaleX(xScale);
var new_yScale = e.transform.rescaleY(yScale);
console.log(d);
x_axis.call(xAxis.scale(new_xScale));
y_axis.call(yAxis.scale(new_yScale));
circles.data(d)
.attr('cx', function(d) {return new_xScale(d[0])})
.attr('cy', function(d) {return new_yScale(d[1])});
}
}
},
mounted() {
this.createSvg();
}
}
</script>
Interestingly enough, after I set the clip region to prevent showing points outside of the axes the problem seemed to resolve itself. This is how I created the clip path:
// clip path
var clip = svg.append("defs").append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("id", "clip-rect")
.attr("x", "0")
.attr("y", "0")
.attr('width', chart_dx)
.attr('height', chart_dy);
And I then added that attribute to the svg when plotting the data like this:
svg.append("g").attr("clip-path", "url(#clip)")
Updated clip path with plot data section:
// clip path
var clip = svg.append("defs").append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("id", "clip-rect")
.attr("x", "0")
.attr("y", "0")
.attr('width', chart_dx)
.attr('height', chart_dy);
// plot data
var circles = svg.append("g")
.attr("id", "circles")
.attr("transform", "translate(75, 0)")
.attr("clip-path", "url(#clip)") //added here
.selectAll("circle")
.data(d)
.enter()
.append("circle")
.attr("r", 4)
.attr("cx", function(d) { return xScale(d[0]); })
.attr("cy", function(d) { return yScale(d[1]); })
.style("fill", function(d) {
var norm_color = colorScale(d[1]);
return d3.interpolateInferno(norm_color)
});
I ended up resolving this issue. I have updated the original post to show what worked for me.
Basically, after adding the clip region things started to work properly.
// clip path (this is the new clip region that I added. It prevents dots from being drawn outside of the axes.
var clip = svg.append("defs").append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("id", "clip-rect")
.attr("x", "0")
.attr("y", "0")
.attr('width', chart_dx)
.attr('height', chart_dy);
// plot data
var circles = svg.append("g")
.attr("id", "circles")
.attr("transform", "translate(75, 0)")
.attr("clip-path", "url(#clip)") //added clip region to svg here
.selectAll("circle")
.data(d)
.enter()
.append("circle")
.attr("r", 4)
.attr("cx", function(d) { return xScale(d[0]); })
.attr("cy", function(d) { return yScale(d[1]); })
.style("fill", function(d) {
var norm_color = colorScale(d[1]);
return d3.interpolateInferno(norm_color)
});
I am developing a two-way bar chart using d3. I want to add grid lines to the bar chart, how to customize those grid lines. I've used d3fc to draw the grid lines. It looks something like
var x = d3.scaleLinear()
.rangeRound([0, width])
var y = d3.scaleBand()
.rangeRound([0, height]).padding(0.5);
var xAxis = d3.axisBottom(x)
.ticks(8)
.tickSize(0)
.tickFormat(function(d){
return d3.format('.00s')(Math.abs(d)); // Use Math.abs() to get the absolute value
});
var yAxis = d3.axisLeft(y)
.ticks(5)
.tickSize(0);
//draw grid lines
const gridline = fc.annotationSvgGridline()
.xScale(x)
.yScale(y);
var svg = d3.select("#ageSexNotif").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 + ")");
x.domain([-d3.max(data, function(d){
return d.female
})*1.2,d3.max(data, function(d){
return d.female
})*1.2])
y.domain(data.map(function (d) {
return d.age;
}));
svg.append("g")
.attr("class", "x axis")
.call(xAxis)
.call(gridline);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
// .call(gridline);
var barsRight = svg.selectAll(".bar")
.data(data)
.enter().append("g")
barsRight.append("rect")
.attr("class", "bar")
.attr("x", function (d) {
return x(Math.min(0, d.female));
})
.attr("y", function (d) {
return y(d.age);
})
.attr("width", function (d) {
return Math.abs(x(d.female) - x(0));
})
.transition()
.duration(1500)
.delay(200)
.style("margin-top", "10px")
.attr("height", y.bandwidth())
.attr("fill", "#F293C9")
.attr("text", "label");
barsRight.append("text")
.attr("class", "label")
//y position of the label is halfway down the bar
.attr("y", function (d) {
return y(d.age) + y.bandwidth()- 6;
})
//x position is 3 pixels to the right of the bar
.attr("x", function (d) {
return x(d.female) + 10;
})
.text(function (d) {
return (d.female/1000)+'k';
})
.style("font-family", "Source Sans Pro")
.style("font-size", "14px")
.style("font-weight", "bold")
.attr("fill", "#F293C9");
var barsLeft = svg.selectAll(".bar2")
.data(data)
.enter().append("g")
barsLeft.append("rect")
.attr("class", "bar2")
.attr("x", function (d) {
return x(Math.min(0, -d.male));
})
.attr("y", function (d) {
return y(d.age);
})
.attr("width", function (d) {
return Math.abs(x(-d.male) - x(0));
})
.transition()
.duration(1500)
.delay(200)
.style("margin-top", "10px")
.attr("height", y.bandwidth())
.attr("fill", "#4880FF");
barsLeft.append("text")
.attr("class", "label")
.style("font-family", "Source Sans Pro")
.style("font-size", "14px")
.style("font-weight", "bold")
.attr("fill","#4880FF")
//y position of the label is halfway down the bar
.attr("y", function (d) {
return y(d.age) + y.bandwidth()- 6;
})
//x position is 3 pixels to the right of the bar
.attr("x", function (d) {
return x(-d.male) - 40;
})
.text(function (d) {
return (d.male/1000)+'k';
});
The result of my chart is
My chart should look like this
How to join the edges in x-axis and highlight the base axis as shown in the image? Any help for customizing the grid lines is appreciated.
Link to my example link
Thanks in advance!
You can add class name to your grid lines using attr('class', 'class-name'), and add your effect by CSS.
I've made some changes to your pen that you can see here.
The main changes:
join the edges in x-axis
If you remove the *1.2 multiplier from the domains and add .nice() then the x-axis will be squared off with the gridlines.
var x = d3.scaleLinear()
.rangeRound([0, width])
.domain([-d3.max(data, d => d.female), d3.max(data, d => d.female)])
.nice();
highlight the base axis
We can do this using an annotation line from d3fc.
const line = fc.annotationSvgLine()
.xScale(x)
.yScale(y)
.orient('vertical')
.label('')
.decorate(selection => {
selection.select('line')
.attr('stroke', 'black');
});
svg.datum([0]).call(line);
Here we are creating an annotation line using our scales. We set the line to be vertical and we remove the default label by replacing it with an empty string. After that we use the decorate function to colour the line black.
customizing the gridlines
We can control the opacity of the gridlines using a decorate function.
const opacityDecorate = selection => {
selection.attr('opacity', 0.2);
};
const gridline = fc.annotationSvgGridline()
.xScale(x)
.yScale(y)
.xDecorate(opacityDecorate)
.yDecorate(opacityDecorate);
Here we are using a decorate function to set the opacity for the both the horizontal and vertical gridlines. Alternatively you could also use different decorate functions to style the horizontal and vertical lines differently.
I hope this helps!
Need some help figuring out how to auto update 3djs scatter plot. The code looks fine ,however, when the update
function is running the graph gets updated but the scatter plot remains at place. I'm using svg.selectAll(".dot").remove() in order to remove the outdated ones but unable to find a way to added them back. I found a few solutions online but none of them worked for my code.
Any help would be much appreciated. thanks
DB structure:
dtg | temperature
2016-03-02 09:14:00 23
2016-03-02 09:10:00 22
Code:
<script>
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 40},
width = 400 - margin.left - margin.right,
height = 200 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;
var formatTime = d3.time.format("%e %B %X");
// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
// Define the line
var valueline = d3.svg.line()
.x(function(d) { return x(d.dtg); })
.y(function(d) { return y(d.temperature); });
var div = d3.select("#chart1").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// Adds the svg canvas
var svg = d3.select("#chart1")
.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 + ")");
function make_x_axis() {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(10)
}
function make_y_axis() {
return d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10)
}
// Get the data
d3.json("2301data.php", function(error, data) {
data.forEach(function(d) {
d.dtg = parseDate(d.dtg);
d.temperature = +d.temperature;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.dtg; }));
y.domain([0, 60]); //
// y.domain([0, d3.max(data, function(d) { return d.temperature; })]);
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("d", valueline(data));
// draw the scatterplot
svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.filter(function(d) { return d.temperature > 30 })
.style("fill", "red")
.attr("r", 3.5)
.attr("cx", function(d) { return x(d.dtg); })
.attr("cy", function(d) { return y(d.temperature); })
// Tooltip stuff after this
.on("mouseover", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
div.transition()
.duration(200)
.style("opacity", .9);
div .html(
d.temperature + "C" + "<br>" +
formatTime(d.dtg))
.style("left", (d3.event.pageX + 8) + "px")
.style("top", (d3.event.pageY - 18) + "px");})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.style("font-size", "14px")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.style("font-size", "14px")
.call(yAxis);
// Draw the grid 1
svg.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat("")
)
// Draw the grid 2
svg.append("g")
.attr("class", "grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat("")
)
// Addon 3 // text label for the graph
svg.append("text")
.attr("x", (width / 2))
.attr("y", 0 - (margin.top / 2))
.attr("text-anchor", "middle")
.style("font-size", "14px")
.style("text-decoration", "underline")
.style('fill', 'white')
//.attr("class", "shadow") // using text css
.text("2301 Temperature read in the past 24h\n");
});
var inter = setInterval(function() {
updateData();
}, 5000);
// ** Update data section (Called from the onclick)
function updateData() {
// Get the data again
d3.json("2301data.php", function(error, data) {
data.forEach(function(d) {
d.dtg = parseDate(d.dtg);
d.temperature = +d.temperature;
//d.hum = +d.hum; // Addon 9 part 3
});
// Scale the range of the data again
x.domain(d3.extent(data, function(d) { return d.dtg; }));
y.domain([0, 60]);
var svg = d3.select("#chart1").transition();
// Make the changes
svg.selectAll(".dot").remove(); //remove old dots
svg.select(".line").duration(750).attr("d", valueline(data));
svg.select("x.axis").duration(750).call(xAxis);
svg.select("y.axis").duration(750).call(yAxis);
//update the scatterplot
svg.selectAll(".dotUpdate")
.data(data)
.attr("class", "dotUpdate")
.enter().append("circle")
.filter(function(d) { return d.temperature > 30 })
.style("fill", "red")
.attr("r", 3.5)
.attr("cx", function(d) { return x(d.dtg); })
.attr("cy", function(d) { return y(d.temperature); });
});
}
</script>
The first thing I did wrong was using the wrong d3js.. the following line has to be replaced
<script src="http://d3js.org/d3.v3.min.js"></script>
With the following or else svg.selectAll would not work.
<script type="text/javascript" src="http://d3js.org/d3.v3.js"></script>
Now, as far as the scatter plots update goes. I'm now using the code below which works fine with some databases. In my case it still does not work well and I'll be posting it as a sepearte question as stakoverflow guidlines requsts..
// ** Update data section (Called from the onclick)
function updateData() {
// Get the data again
data = d3.json("2301data.php", function(error, data) {
data.forEach(function(d) {
d.dtg = parseDate(d.dtg);
d.temperature = +d.temperature;
// d.hum = +d.hum; // Addon 9 part 3
});
// Scale the range of the data again
x.domain(d3.extent(data, function(d) { return d.dtg; }));
y.domain([0, 60]); // Addon 9 part 4
var svg = d3.select("#chart1")
var circle = svg.selectAll("circle").data(data)
svg.select(".x.axis") // change the x axis
.transition()
.duration(750)
.call(xAxis);
svg.select(".y.axis") // change the y axis
.transition()
.duration(750)
.call(yAxis);
svg.select(".line") // change the line
.transition()
.duration(750)
.attr("d", valueline(data));
circle.transition()
.duration(750)
.attr("cx", function(d) { return x(d.dtg); })
// enter new circles
circle.enter()
.append("circle")
.filter(function(d) { return d.temperature > 30 })
.style("fill", "red")
.attr("r", 3.5)
.attr("cx", function(d) { return x(d.dtg); })
// remove old circles
circle.exit().remove()
});
}
I created a bar plot and my Y axis is reversed somehow (also seems like the scale is not right). I really couldn't figure it out by myself. Here is the link for Jsfiddle.
This is the code I am working on, in case you want to try it elsewhere.
var w = 700;
var h = 400;
var margin = 40;
var dataset = [
{key:1,value:4000},
{key:2,value:3500},
{key:3,value:4400},
{key:4,value:3250},
{key:5,value:4785},
{key:6,value:3600},
{key:7,value:3200}
];
var key = function(d) {
return d.key;
};
var value = function(d) {
return d.value;
};
console.log(dataset);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var xScale = d3.scale.ordinal()
.domain(d3.range(dataset.length+1))
.rangeRoundBands([40, w], 0.05);
var yScale = d3.scale.linear()
.domain([0, 5000])
.range([0, h-40]);
var x_axis = d3.svg.axis().scale(xScale);
var y_axis = d3.svg.axis().scale(yScale).orient("left");
d3.select("svg")
.append("g")
.attr("class","x axis")
.attr("transform","translate(0,"+(h-margin)+")")
.call(x_axis);
d3.select("svg")
.append("g")
.attr("class","y axis")
.attr("transform","translate("+margin+",0)")
.call(y_axis);
//Create bars
svg.selectAll("rect")
.data(dataset, key)
.enter()
.append("rect")
.attr("x", function(d, i) {
return xScale(i);
})
.attr("y", function(d) {
return h - yScale(d.value);
})
.attr("width", xScale.rangeBand())
.attr("height", function(d) {
return yScale(d.value)-margin;
})
.attr("fill", function(d) {
return "rgb(96, 0, " + (d.value * 10) + ")";
})
//Tooltip
.on("mouseover", function(d) {
//Get this bar's x/y values, then augment for the tooltip
var xPosition = parseFloat(d3.select(this).attr("x")) + xScale.rangeBand() / 2;
var yPosition = parseFloat(d3.select(this).attr("y")) + 14;
//Update Tooltip Position & value
d3.select("#tooltip")
.style("left", xPosition + "px")
.style("top", yPosition + "px")
.select("#value")
.text(d.value);
d3.select("#tooltip").classed("hidden", false)
})
.on("mouseout", function() {
//Remove the tooltip
d3.select("#tooltip").classed("hidden", true);
}) ;
//Create labels
svg.selectAll("text")
.data(dataset, key)
.enter()
.append("text")
.text(function(d) {
return d.value;
})
.attr("text-anchor", "middle")
.attr("x", function(d, i) {
return xScale(i) + xScale.rangeBand() / 2;
})
.attr("y", function(d) {
return h - yScale(d.value) + 14;
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");
Maybe this will help.
http://jsfiddle.net/S575k/4/
A few notes:
I reversed your y domain range from .range([0, h-margin]); to .range([h-margin, 0]); This will fix the issue of the y-axis marks going in the wrong direction because the browser consider's the origin (0,0) point to the the upper-left corner, and not the bottom-left corner like in math.
Because of this reversal I had to tweak your .attr('height') and .attr('y').
A nice way to find the height of bar in a bar chart is to realize that the yscale(0) will give you the pixel-position of the bottom of the barchart. You can then do yscale(value) - yscale(0) to get the pixel-height of your bars.
I have a basic line graph with two lines. When I click a button, one of the two lines will draw on the graph.
I use stroke-dasharray to draw the lines.
Would anyone know how I could add tooltips to my lines?
Does using stroke-dasharray make it harder?
Heres my code.
var button=d3.select("#button");
//defines canvas (area in which graph is placed)
var margin = {top: 30, right: 20, bottom: 50, left: 60},
width = 800 - margin.left - margin.right,
height = 700 - margin.top - margin.bottom;
var parseDate = d3.time.format("%d-%b-%y").parse;
//OUTPUT RANGE
var x = d3.time.scale()
.range([0, width]);
//OUTPUT RANGE
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis().scale(x)
.orient("bottom")
.ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left")
.ticks(5);
//assigns coordinates for each piece of data
var valueline = d3.svg.line()
.interpolate("interpolation")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
//second line data
var valueline2 = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.open); });
//create area for 'area' below line
var area = d3.svg.area()
.x(function(d) { return x(d.date); })
.y0(height)
.y1(function(d) { return y(d.close); });
//creates area to draw graph
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
//groups content
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
function make_x_axis() {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5)
}
function make_y_axis() {
return d3.svg.axis()
.scale(y)
.orient("left")
.ticks(30)
}
// csv callback function
d3.csv("myData3.csv", function(data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
d.open = +d.open;
});
//INPUT DOMAINS
//.extent() returns min and max values of argument
x.domain(d3.extent(data, function(d) { return d.date; }));
//returns max of whichever set of data is bigger
y.domain([0, d3.max(data, function(d) { return Math.max(d.close, d.open); })]);
d3.select("#button1").on("click", function(){
var path = svg.append("path") // Add the valueline path.
.attr("class", "line")
.attr("d", valueline(data))
.attr("stroke", "steelblue")
.attr("stroke-width", "5")
.attr("fill", "none");
var totalLength = path.node().getTotalLength();
path
.attr("stroke-dasharray", totalLength + "30" * 30)
.attr("stroke-dashoffset", totalLength)
.transition()
.duration(2000)
.ease("linear")
.attr("stroke-dashoffset", 0);
})
d3.select("#button2").on("click", function(){
var path2 = svg.append("path") // Add the valueline path.
.attr("class", "line2")
.attr("d", valueline2(data))
.attr("stroke", "steelblue")
.attr("stroke-width", "5")
.attr("fill", "none");
var totalLength = path2.node().getTotalLength();
path2
.attr("stroke-dasharray", totalLength + "30" * 30)
.attr("stroke-dashoffset", totalLength)
.transition()
.duration(2000)
.ease("linear")
.attr("stroke-dashoffset", 0)
})
svg.append("g") // Add the X Axis
.attr("class", "x axis")
//moves x axis to bottom of graph
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
//text label for x-axis
svg.append("text") // text label for the x axis
.attr("transform", "translate(" + (width / 2) + " ," + (height + margin.bottom - 5 ) + ")")
.style("text-anchor", "middle")
.text("Date");
svg.append("g") // Add the Y Axis
.attr("class", "y axis")
.call(yAxis);
//text label for y-axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x",0 - (height / 2))
//adds extra left padding as original y pos = 0
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Value");
//adding a title to the graph
svg.append("text")
.attr("x", (width / 2))
.attr("y", 0 - (margin.top / 2))
.attr("text-anchor", "middle")
.style("font-size", "16px")
.style("text-decoration", "underline")
.text("Graph");
//draw x axis grid
svg.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat("")
)
//draw y axis grid
svg.append("g")
.attr("class", "grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat("")
)
});<!--d3.csv close-->
Thanks in advance!
The easiest way to add a tooltip is to append an svg:title element to the elements you want to have a tooltip for. It will be displayed by the browser automatically when you hover over the element. It works for all kinds of elements as well.
So your code would need to look something like
var path = svg.append("path") // Add the valueline path.
.attr("class", "line")
.attr("d", valueline(data))
.attr("stroke", "steelblue")
.attr("stroke-width", "5")
.attr("fill", "none")
.append("title").text("whatever");
If you need more sophisticated functionality, you could try for example tipsy, which works in a similar way.