af Piotr Delikat 9 år siden
17620
Mere som dette
app.filter('startDate', function(){ ... });
<html>
<head>
<script>
...
app.directive('d3Map', function(){ ... });
app.directive('d3LineChart', function(){ ... });
app.directive('d3ScatterPlot', function(){ ... });
app.directive('d3ChordDiagram', function(){ ... });
</script>
</head>
<body>
<d3-map></d3-map>
<d3-line-chart data="data"></d3-line-chart>
<d3-scatter-plot data="data"></d3-scatter-plot>
<d3-chord-diagram data="data"></d3-chord-diagram>
</body>
</html>
in HTML
app.directive('d3ChordDiagram', function(){ ... });
angular.element($window).on('resize', function(){ $scope.$apply() })
scope.$watch(function() { return el.clientWidth * el.clientHeight}, function() { width = el.clientWidth height = el.clientHeight })
all the variables that depends on with and height goes inside secon function
$scope.charts = d3.range(10).map(function() { return d3.range(10).map(Math.random) })
random data with 10 values for 10 charts
app = directive('chartName', function() { })
it should return an link
return { link:link, restrict: 'E', scope: {data: '=' } };
function link (scope, el) { //d3 code inside, el is an element }
you can pull the data out the chart function
var data = scope.data;
it reference to the
var app = angular.module("myApp", []);
link to angular libarary of course
function dragged(d) { d.x = d3.event.x; d.y = d3.event.y; d3.select(this) .attr("transform", 'translate(' + d.x + ',' + d.y + ')'); date = xScale.invert(d3.event.x); d.DATE = parseTime(date); temp = yScale.invert(d3.event.y); d.TMAX = temp.toString(); console.log(d); };
in this function we acctually are changing the data in the database!
we change the d.y, and d.x, and set it equal to the values from the event (mouse position) d3.event.x and d3.event.y
function dragStarted() { d3.event.sourceEvent.stopPropagation(); d3.select(this) .select('circle') .style("fill", 'red'); };
d3.event.sourceEvent.stopPropagation();
the event stops in the element that the event was registered
and the event is not sending to other DOM elements
it stops all other actions triggered by the event
is to prevent so called "bubbling up"
dots.call(circleDrag);
what is the same as circleDrag(dots);
var circleDrag = d3.behavior.drag() .on("dragstart", dragStarted) .on("drag", dragged);
there is also .on("dragend", callBackFunction())
function zoomed() { viz.attr("transform", "translate(" + d3.event.translate + ")" + "scale(" + d3.event.scale + ")"); };
d3.event.scale tells how low or high we scaled by mouse wheel
is bounder by .scaleExtent[1, 10]
d3.event.translate holds the mouse position during zooming
var svg = d3.select("#viz-wrapper") .append('svg') .attr('height', height + padding * 2 ) .attr('width', width + padding * 2) .call(zoom);
var viz = svg.append('g') .attr('id', 'viz') .attr('transform', 'translate(' + padding + ',' + padding + ')');
we append rest of elements to the svg, under id of 'viz'
.on("zoom", zoomed);
it can be also "click", "double-click", or any other event
on the event "zoom", the zoomed function should be run
.scaleExtend()
limit how far we can zoom in and out
dots.on("mouseleave", function(d, i) { dot = d3.select(this); dot.select('circle') .attr('r', defaultCircleRadius); });
dots.on("mouseenter", function(d, i) { dot = d3.select(this); radius = solveForR( parseInt(d.TMAX) ) dot.select('circle') .attr('r', rScale( radius )); });
rDomain = d3.extent(data, function(element){ return solveForR(parseInt(element.TMAX)); });
we use solveForR() function to calculate r based on TMAX
var solveForR = function(TMAX) { // area of a circle // Area = Pi * r * r Area = Math.abs( TMAX ); r = Math.sqrt( Area / Math.PI); return r };
area based on TMAX value
var rScale = d3.scale.linear() .range([5, 50]);
var defaultCircleRadius = 2;
dots.on("mouseleave", function(d, i) { d3.select(this) .select('text') .style('display', 'none'); });
you can make sub-selection on text of children of the g element, and change it's style
.on("eventType", eventListener function() {});
and i is index of the selected element
eventListener function has acces to the data of selected element
dots.attr('transform', function(d) {
//get the x position
date=parseTime.parse(d.DATE);
x = xScale(date)
//get the y position
y = yScale(d.TMAX)
return 'translate(' + x + ',' + y + ')'
})
and style it
.style('stroke', '#00ffd2')
.style('fill', '#006bff');
append circle to the g points
dots.append('circle')
.attr('r', 5);
and text
dots.append('text')
.text(function(d) {
return d.TMAX
});
});
.style('display', 'none');
to hide it on default
dots = viz.selectAll('g.dots')
.data(data).enter().append('g').attr('class', 'dots');
to spread axis with a buffer
easy way
xMax = d3.max(data, function() { time = parseTime.parse(element.DATE); time.setMonth(getMonth() +1); return time });
oneDayLater = function(date) {return date.setDate(date.getDate() + 1)};
xScale.domain([xMin, xMax]);
xMin = d3.min(data, function(element) { time = parseTime.parse(element.DATE); time.setMonth(getMonth() - 1); return time });
oneDayEarlier = function(date) { return date.setDate(date.getDate() - 1) };
yDomain = d3.extent(data, function() { return parseInt(element.TMAX) * 1.1 });
.attr("dy", "10px");
shift along the y-axis on the position of an element or its content
.attr("dx", "-10px")
shift along the x-axis on the position of an element or its content
.style('font-size', '10px')
.style("text-anchor", "end")
align for the text (start-, middle- or end-alignment) a string of text relative to a given point
.attr("transform", function() { return "rotate(-65)" })
we use function to rotate each element in the selection and not all the elements
rotate() is much like translate() but it rotate the text not move it
rotating the labels
.selectAll('text')
.ticks(20);
.orient("left")
.scale(yScale)
adding yAxis
dont need to be transformed becouse it starts at the beginning of the svg (0)
.call(yAxis);
.attr("class", "y axis")
adding xAxis
other way
xAxis(viz.append("g").attr('class', 'x axis') )
svgElementId.append("g")
.call(xAxis);
.attr("transform", "translate(0," + height + ")")
translate() moves the text accross the axis
it tells the axis that values should go from 0 to height value
.attr("class", "x axis")
.ticks(8);
how many lables will be attached to axis
.orient("bottom")
where to laloyt the axis
.scale(xScale)
how to spread the axis
d3.time.format("%b %y");
xDomain = d3.extend(data, function(element) { return parseTime.parse(element.DATE) });
but there is d3.extend(); method
function createDate(dateString) { // create a formatter based on how we expect // the data from our data set var format = d3.time.format("%Y%m%d"); // create a JavaScript data object based on // the string return format.parse(dateString); };
function ready to do it
to use this format to transform valentinesDay data
parseTime.parse(valentinesDay);
it returns: Sat Feb 14 2015 00:00:00 GTM-0800 (PST)
.parse();
method that changes strings of time data into JS data objects
var parseTime = d3.time.format("%Y%m%d");
you can also use it to convert JavaScript data object into this format
parseTime(new Date());
return: "20150828"
we receive: valentinesDay = "20150214";
in d3.time.format(); you can specify the data format that you will recieve from your data
yScale.invert(100)
to check what value (from the data) is mapped to 100px space on y Axis
it can be usefull to track the data by mouse and touch events
DATE ex.
xScale.invert(800);
return: Tue Dec 31 1974 00:00:00 GMT+0100 (Środkowoeuropejski czas stand.)
xScale.invert(0);
return: Wed Aug 01 1973 00:00:00 GMT+0200 (Środkowoeuropejski czas letni)
TMAX ex.
yScale.invert(800);
return -33
yScale.invert(0);
return 361
yScale.domain(yDomain);
or change the domain if you put in new parameters
to see array of min and max values from the data
yScale.range()
to see available range in the svg for spreading data on Y axis
yScale(d.TMAX)
it will return the pixel value where one of the dots will be positioned inside the scale
dots.attr('cy', function(d) {
return yScale(d.TMAX) })
and map the data between these min and max values
this method contain min and max values from yDomain
or you can do d3.max and d3.min simultaniously
yDomain = d3.extent(data, function(element) return parseInt(element.TMAX) });
it return an array with Min and Max values
you need such format to yScale method
so: yScale.domain(yDomain)
[-33, 361]
give you the range ofvalues from data parameter: TMAX
solution with better performance because you iterate the data only once
yMax = d3.max(data, function(element) { return parseInt(element.TMAX) });
will return maximum value from given data parameter: TMAX
yMin = d3.min(data, function(element) {return parseInt(element.TMAX) });
will return minimum value from given data parameter: TMAX
use parseInt on values from the data to convert it into numeric values
if you now that the data is numeric you can use
d3.max(data, function(element) { return +element.TMAX });
it depends on min and max values from your data
var xScale = d3.time.scale().range([0, width])
var yScale = d3.scale.linear().range([height, 0])
var height = 800;
var yScale = d3.scale.linear()
.range([height, 0]);
ordinary
sets of names, categories etc.
alphabetical
to deal with order of things
var x = d3.scale.ordinal()
.domain(["A", "B", "C", "D", "E", "F"]) .range([0, 1, 2, 3, 4, 5]);
you need to set a range for the order
.rangeBands([0, width]);
If width is 960, x("A") is now 0 and x("B") is 160, and so on.
quantative
pow
log
linear
to deal with numbers
Subtopic
You can open any files, and set break points to run your code to a specyfic line
and later access the variable or function in the given time
by accessing d in the console
{return Math.max(0 + padding, Math.random() * width - padding)} //give us some random number based on width minus padding left and right
=== 10
gives you maximum value from equation
return a absolute value (when you dealing with nagative numbers)
it can takes 2 parameters
i - index value of the data
optional
d - data or datum
dots.attr('r', function(d) {return d.TMAX});
.append('circle')
.append('svg').attr('width', 200px).attr('height', 200px)
we can also set the properties depending on index i value
circles.style('stroke-width', function(d, i) { return i*2; }) ;
circles.attr('r', function(d, i) { return d; });
you can also access data from the array of objects
.attr('fill', function(d, i) { return d.color; })
Set the fill color depending of the bound object
circles.attr('r', function(d, i) { return d.r; });
var data = [
{cx:50, cy:50, r: 10, color: '#ff0000'},
{cx:150, cy:50, r: 20, color: '#ff0066'},
{cx:250, cy:50, r: 30, color: '#ff00aa'},
{cx:350, cy:50, r: 40, color: '#ff00ff'}
];
var viz = d3.select("#viz-wrapper")
.append('svg')
.attr('id', 'viz');
d3.csv('../../app/climate_data.csv', function(data) {
dots = viz.selectAll('circle') //ghost selection
dots.data(data) //return 516 objects
dots.enter() // still return 516 objects
dots.append('circle'); //adding 516 circle elements to HTML
//binding data (absolute value from max temp/ 100 to make it C deg) to r of a circle
dots.attr('r', function(d) {return Math.abs(d.TMAX) / 100});
});
we can treat the .enter() selection just like any other selection to modify the content.
specifies the selection
prepares the selection to update the DOM with new elements
return data that are already binded to the DOM element + new data
If the new dataset is larger, the surplus data ends up in the enter selection and new nodes are added.
if we are creating ghost selection it will return same number of elements as the data() operator
in case that selected elements have some values new data will not replace it
<script type="text/javascript">
// Create a data array
var data = [10, 20, 30, 40];
// Bind data array to the Selection
var circles = d3.selectAll('circle').data(data);
console.log(circles.data());
// [10, 20, 30, 40]
</script>
key is additional parameter
you can call a function there, that interacts with every data item
it returns the number of elements = number of data records
for binding data from file to choosen element
you can select element that not exist yet
core of D3
d3.xml()
d3.tsv()
d3.html()
d3.text()
d3.csv('filePath', function(error, data){})
<script type="text/javascript">
d3.csv('climate_data.csv', function(data) {
debugger;
});
</script>
d3 converting cvs data to JSON like objects
after request type "data" in the console to access it
awesome!
d3.json('filePath', function(error, data){})
d3.json('data/phones.json', function(error, data) {
//all the magic whit data here
conslole.log(error);
console.log(data);
});
data is a data from a file
result of the request
error is a error message that shows up when the file can't be accesed
function is a callback function
will work only if data is succesfully loaded, or fail
file name relative to the script file
non-blocking
d3.selectAll('div').classed('hosue', false)
none of the divs will have class="house"
d3.selectAll('div').classed('house',true)
it will return a selection
all divs will have calss="house"
return false becouse non all div has calss ('.hosue')
it return false, becouse element (#tree) don't have class ('hosue')
<p>I like fruits.</p>
<p>Apple, Banana and Orange</p>
<script type="text/javascript">
function set_custom_attr(selection, attr, value) {
selection
.attr(attr, value);
}
d3.selectAll('p').call(set_custom_attr, 'align', 'center');
</script>
and the result is:
<p align="center">I like fruits.</p>
<p align="center">Apple, Banana and Orange</p>
d3.selectAll('p').each(function(d, i){
var self = d3.select(this);
// Output the text of every element
console.log(self.text());
});
</script>
jQuery way works :)
arrayName.lenght
objectName['keyName']
test.phones[0]
objectName.nestedObjectName.keyName
is used to center it verticaly
<svg width="100%" height="100%" viewBox="0 0 95 50"
xmlns="http://www.w3.org/2000/svg">
<g stroke="green" fill="white" stroke-width="5">
<circle cx="25" cy="25" r="15" />
<circle cx="40" cy="25" r="15" />
<circle cx="55" cy="25" r="15" />
<circle cx="70" cy="25" r="15" />
</g>
</svg>
stroke-width
stroke
color
x2, y2
x1, y1
attributes
cy
cx
r
var d3 = require("d3"),
jsdom = require("jsdom");
var document = jsdom.jsdom(),
svg =d3.select(document.body).append("svg");