Hello everyone,
I have the following problem. I have an oData Rest endpoint and a limitation per request of batches of 50 records. Now I want to draw a line chart with nested user information like the users name and under that the work day and the working time. So I iterate over all the users and try to find the min max for the working day and working time and draw the initial svg.
Now when I get the next 50 records I want to rescale x and y axis to a new min max and I also need to rescale the old 50 records to the new scale, and there is my main problem. I don't have the data of the data of the 50 former records but I have the path drawn by those data.
How can I rescale the old paths to the new domain before I fill in the new data? And how do I add the information of the same user to the path of the user. Each user should have only one path in the line chart.
Also, how do I keep a legend for each line in the chart for each user?
I'm getting my data from a MS Dynamics CRM oData Rest endpoint and I'm substituting a webresource via fiddler in a given MS Dynamics CRM environment if anyone is wondering where I get my data from
My current version looks like this:
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8'>
<title>dc.js Experiment</title>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0-alpha1/jquery.min.js' type='text/javascript'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.8/d3.js' type='text/javascript'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js' type='text/javascript'></script>
<script src="/WebResources/con_XrmServiceToolkit_2.1.js"></script>
</head>
<body>
<style>
.legend {
font-size: 14px;
font-weight: bold;
}
.xaxis path,
.xaxis line,
.yaxis path,
.yaxis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.yaxis text,
.xaxis text {
font-family: sans-serif;
font-size: 11px;
}
</style>
<script type="text/javascript">
var margin = {
top: 20,
right: 100,
bottom: 70,
left: 50
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var color = d3.scale.category20();
var xScale = d3.time.scale()
.range( [ 0, width ] );
var yScale = d3.scale.linear()
.range( [ height, 0 ] );
var xAxis = d3.svg.axis()
.scale( xScale )
.orient( "bottom" );
var yAxis = d3.svg.axis()
.scale( yScale )
.orient( "left" );
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 + ")" );
var lineGen = d3.svg.line().interpolate("monotone")
.x( function ( d ) {
return xScale(new Date(d.key + " 00:00:00"));
} )
.y( function ( d ) {
return yScale(d.values);
} );
(function executeQueryRest (){
var returnResults = [];
XrmServiceToolkit.Rest.RetrieveMultiple(
"con_workrecordSet",
"$select=&$filter=&$top=100&$orderby=CreatedOn",
function (results) {
render(results);
},
function (error) {
},
function onComplete() {
},
true
);
})();
function render(data){
var dataGroup = d3.nest()
.key(function(d){
return d.OwnerId.Name;
})
.key(function(d){
var format = d3.time.format("%Y-%m-%d");
return format(d.CreatedOn);
})
.rollup(function( workingtime ){
return d3.sum( workingtime, function ( d ) {
return d.con_workingtime;
} );
})
.entries(data);
var xMin = d3.min( dataGroup ,
function ( d ) {
return d3.min( _.map(d.values, function(value){return new Date(value.key + " 00:00:00");}));
}
);
var xMax = d3.max( dataGroup ,
function ( d ) {
return d3.max( _.map(d.values, function(value){return new Date(value.key + " 00:00:00");}));
}
);
var yMin = d3.min( dataGroup ,
function ( d ) {
return d3.min( _.map(d.values, function(value){return value.values;}));
}
);
var yMax = d3.max( dataGroup ,
function ( d ) {
return d3.max( _.map(d.values, function(value){return value.values;}));
}
);
if ( $(".yaxis").length > 0 || $(".xaxis").length > 0){
var newXMin = d3.min([xMin, xScale.domain()[0] ]);
var newXMax = d3.max([xMax, xScale.domain()[1] ]);
var newYMin = d3.min([yMin, yScale.domain()[0] ]);
var newYMax = d3.max([yMax, yScale.domain()[1] ]);
xScale.domain([newXMin, newXMax]);
yScale.domain([0, newYMax]);
} else {
xScale.domain([xMin, xMax]);
yScale.domain([0, yMax]);
}
if ( $(".yaxis").length > 0 || $(".xaxis").length > 0){
// d3.selectAll(".yaxis").remove();
// d3.selectAll(".xaxis").remove();
svg.select(".yaxis")
.transition().duration(1500).ease("sin-in-out")
.call(yAxis);
svg.select(".xaxis")
.transition().duration(1500).ease("sin-in-out")
.call(xAxis);
} else {
svg.append( "g" )
.attr( "class", "xaxis" )
// .style({ 'stroke': 'Black', 'fill': 'none', 'stroke-width': '2px'})
.attr( "transform", "translate(0," + height + ")" )
.call( xAxis )
.append("text")
.attr("transform", "translate(" + (width / 2) + " ," + (height + margin.bottom) + ")")
.style("text-anchor", "middle")
.text("Date");
svg.append( "g" )
.attr( "class", "yaxis" )
// .style({ 'stroke': 'Black', 'fill': 'none', 'stroke-width': '2px'})
.call( yAxis )
.append( "text" )
.attr( "transform", "rotate(-90)" )
.attr( "y", 6 )
.attr( "dy", ".71em" )
.style( "text-anchor", "end" )
.text( "Workingtime" );
}
_.forEach(dataGroup, function(d, i){
// if ( $("#line_" + d.key.replace(/\s|\,/g,"")).length > 0){
// var path = svg.select("#line_" + d.key.replace(/\s|\,/g,""))
// .data(d.values);
// path.enter().append("path")
// .attr("d", lineGen(d.values, xScale, yScale))
// .attr("stroke", function(){
// return color( d.key.length );
// })
// .attr("stroke-width", 2)
// .attr('id', 'line_' + d.key.replace(/\s|\,/g,""))
// .attr("fill", "none");
// } else {
var path = svg.selectAll("#line_" + d.key.replace(/\s|\,/g,""))
.data(d.values);
path.enter().append("path")
.transition()
.duration(300)
.attr("d", lineGen(d.values, xScale, yScale))
.attr("stroke", function(){
return color( d.key.length );
})
.attr("stroke-width", 2)
.attr('id', 'line_' + d.key.replace(/\s|\,/g,""))
.attr("fill", "none");
path.exit()
.transition()
.duration(300)
.ease("exp")
.attr("width", 0)
.remove();
// }
var point = svg.append("g")
.attr("class", "line-point");
point.selectAll( 'circle' )
.data( d.values )
.enter().append( 'circle' )
.transition()
.duration(300)
.attr( "cx", function ( d ) {
return xScale( new Date( d.key ) );
} )
.attr( "cy", function ( d ) {
return yScale( d.values );
} )
.attr( "r", 3.5 )
.style( "fill", function () { // dynamic colours
return color( d.key.length );
} )
var lSpace = width/dataGroup.length;
var legend = svg.append("text")
.attr("x", (lSpace / 2) + i * lSpace)
.attr("y", height + 45)
.style("fill", function(){return color( d.key.length );})
.attr("class", "legend")
.on('click', function() {
var active = d.active ? false : true;
var opacity = active ? 0 : 1;
d3.select("#line_" + d.key.replace(/\s|\,/g,""))
.transition()
.duration(200)
.style("opacity", opacity);
d.active = active;
})
.text(d.key);
});
}
</script>
</body>
</html>