trying out common comment structure in scatter, soon the rest will have it

master-patched
Bob Monteverde 12 years ago
parent c6e4ffb5c5
commit 631e50f684

@ -5483,36 +5483,44 @@ nv.models.scatter = function() {
// Public Variables with Default Settings
//------------------------------------------------------------
var margin = {top: 0, right: 0, bottom: 0, left: 0},
width = 960,
height = 500,
color = d3.scale.category20().range(), // array of colors to be used in order
id = Math.floor(Math.random() * 100000), //Create semi-unique ID incase user doesn't selet one
x = d3.scale.linear(),
y = d3.scale.linear(),
z = d3.scale.linear(), //linear because d3.svg.shape.size is treated as area
getX = function(d) { return d.x }, // accessor to get the x value from a data point
getY = function(d) { return d.y }, // accessor to get the y value from a data point
getSize = function(d) { return d.size }, // accessor to get the point radius from a data point //TODO: consider renamig size to z
getShape = function(d) { return d.shape || 'circle' },
forceX = [], // List of numbers to Force into the X scale (ie. 0, or a max / min, etc.)
forceY = [], // List of numbers to Force into the Y scale
forceSize = [], // List of numbers to Force into the Size scale
interactive = true, // If true, plots a voronoi overlay for advanced point interection
//removeZeroes = false, // If true, filters out points with y == 0 from being interactive //TODO: implement
clipEdge = false, // if true, masks lines within x and y scale
clipVoronoi = true, // if true, masks each point with a circle... can turn off to slightly increase performance
clipRadius = function() { return 25 }, // function to get the radius for point clips
xDomain, yDomain, sizeDomain; // Used to manually set the x and y domain, good to save time if calculation has already been made
var margin = {top: 0, right: 0, bottom: 0, left: 0}
, width = 960
, height = 500
, color = d3.scale.category20().range() // array of colors to be used in order
, id = Math.floor(Math.random() * 100000) //Create semi-unique ID incase user doesn't selet one
, x = d3.scale.linear()
, y = d3.scale.linear()
, z = d3.scale.linear() //linear because d3.svg.shape.size is treated as area
, getX = function(d) { return d.x } // accessor to get the x value
, getY = function(d) { return d.y } // accessor to get the y value
, getSize = function(d) { return d.size } // accessor to get the point size
, getShape = function(d) { return d.shape || 'circle' } // accessor to get point shape
, forceX = [] // List of numbers to Force into the X scale (ie. 0, or a max / min, etc.)
, forceY = [] // List of numbers to Force into the Y scale
, forceSize = [] // List of numbers to Force into the Size scale
, interactive = true // If true, plots a voronoi overlay for advanced point interection
, pointActive = function(d) { return !d.notActive } // any points that return false will be filtered out
, clipEdge = false // if true, masks points within x and y scale
, clipVoronoi = true // if true, masks each point with a circle... can turn off to slightly increase performance
, clipRadius = function() { return 25 } // function to get the radius for voronoi point clips
, xDomain = null // Override x domain (skips the calculation from data)
, yDomain = null // Override y domain
, sizeDomain = null // Override point size domain
, dispatch = d3.dispatch('elementClick', 'elementMouseover', 'elementMouseout')
;
//============================================================
//============================================================
// Private Variables
//------------------------------------------------------------
var dispatch = d3.dispatch('elementClick', 'elementMouseover', 'elementMouseout'),
x0, y0, z0,
timeoutID;
var x0, y0, z0 // used to store previous scales
, timeoutID
;
//============================================================
function chart(selection) {
@ -5521,11 +5529,6 @@ nv.models.scatter = function() {
availableHeight = height - margin.top - margin.bottom,
container = d3.select(this);
//store old scales if they exist
x0 = x0 || x;
y0 = y0 || y;
z0 = z0 || z;
//add series index to each data point for reference
data = data.map(function(series, i) {
series.values = series.values.map(function(point) {
@ -5536,26 +5539,39 @@ nv.models.scatter = function() {
});
// slight remap of the data for use in calculating the scales domains
//------------------------------------------------------------
// Setup Scales
// remap and flatten the data for use in calculating the scales' domains
var seriesData = (xDomain && yDomain && sizeDomain) ? [] : // if we know xDomain and yDomain and sizeDomain, no need to calculate.... if Size is constant remember to set sizeDomain to speed up performance
data.map(function(d) {
return d.values.map(function(d,i) {
return { x: getX(d,i), y: getY(d,i), size: getSize(d,i) }
d3.merge(
data.map(function(d) {
return d.values.map(function(d,i) {
return { x: getX(d,i), y: getY(d,i), size: getSize(d,i) }
})
})
});
);
//TODO: figure out the best way to deal with scales with equal MIN and MAX
x .domain(xDomain || d3.extent(d3.merge(seriesData).map(function(d) { return d.x }).concat(forceX)))
x .domain(xDomain || d3.extent(seriesData.map(function(d) { return d.x }).concat(forceX)))
.range([0, availableWidth]);
y .domain(yDomain || d3.extent(d3.merge(seriesData).map(function(d) { return d.y }).concat(forceY)))
y .domain(yDomain || d3.extent(seriesData.map(function(d) { return d.y }).concat(forceY)))
.range([availableHeight, 0]);
z .domain(sizeDomain || d3.extent(d3.merge(seriesData).map(function(d) { return d.size }).concat(forceSize)))
z .domain(sizeDomain || d3.extent(seriesData.map(function(d) { return d.size }).concat(forceSize)))
.range([16, 256]);
//.range([2, 10]);
//store old scales if they exist
x0 = x0 || x;
y0 = y0 || y;
z0 = z0 || z;
//------------------------------------------------------------
//------------------------------------------------------------
// Setup containers and skeleton of chart
var wrap = container.selectAll('g.wrap.scatter').data([data]);
var wrapEnter = wrap.enter().append('g').attr('class', 'wrap nvd3 scatter chart-' +id);
@ -5564,9 +5580,12 @@ nv.models.scatter = function() {
var g = wrap.select('g')
gEnter.append('g').attr('class', 'groups');
gEnter.append('g').attr('class', 'point-paths');
wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
//------------------------------------------------------------
defsEnter.append('clipPath')
.attr('id', 'edge-clip-' + id)
@ -5582,21 +5601,17 @@ nv.models.scatter = function() {
function updateInteractiveLayer() {
if (!interactive) {
//wrap.select('#points-clip-' + id).remove();
//wrap.select('.point-paths').remove();
return false;
}
if (!interactive) return false;
gEnter.append('g').attr('class', 'point-paths');
// TODO: add a removeZeros option, useful for the stacked chart and maybe others
var vertices = d3.merge(data.map(function(group, groupIndex) {
return group.values.map(function(point, pointIndex) {
// Adding noise to make duplicates very unlikely
// Injecting series and point index for reference
return [x(getX(point,pointIndex)) * (Math.random() / 1e12 + 1) , y(getY(point,pointIndex)) * (Math.random() / 1e12 + 1), groupIndex, pointIndex]; //temp hack to add noise untill I think of a better way so there are no duplicates
})
return group.values
.filter(pointActive) // remove non-interactive points
.map(function(point, pointIndex) {
// *Adding noise to make duplicates very unlikely
// **Injecting series and point index for reference
return [x(getX(point,pointIndex)) * (Math.random() / 1e12 + 1) , y(getY(point,pointIndex)) * (Math.random() / 1e12 + 1), groupIndex, pointIndex]; //temp hack to add noise untill I think of a better way so there are no duplicates
})
})
);
@ -5619,7 +5634,13 @@ nv.models.scatter = function() {
//inject series and point index for reference into voronoi
var voronoi = d3.geom.voronoi(vertices).map(function(d, i) { return { 'data': d, 'series': vertices[i][2], 'point': vertices[i][3] } });
var voronoi = d3.geom.voronoi(vertices).map(function(d, i) {
return {
'data': d,
'series': vertices[i][2],
'point': vertices[i][3]
}
});
var pointPaths = wrap.select('.point-paths').selectAll('path')
@ -5654,29 +5675,21 @@ nv.models.scatter = function() {
});
})
.on('mouseout', function(d, i) {
var series = data[d.series],
point = series.values[d.point];
dispatch.elementMouseout({
point: data[d.series].values[d.point],
series: data[d.series],
point: point,
series: series,
seriesIndex: d.series,
pointIndex: d.point
});
});
dispatch.on('elementMouseover.point', function(d) {
d3.select('.chart-' + id + ' .series-' + d.seriesIndex + ' .point-' + d.pointIndex)
.classed('hover', true);
});
dispatch.on('elementMouseout.point', function(d) {
d3.select('.chart-' + id + ' .series-' + d.seriesIndex + ' .point-' + d.pointIndex)
.classed('hover', false);
});
}
var groups = wrap.select('.groups').selectAll('.group')
.data(function(d) { return d }, function(d) { return d.key });
groups.enter().append('g')
@ -5703,10 +5716,10 @@ nv.models.scatter = function() {
return 'translate(' + x0(getX(d,i)) + ',' + y0(getY(d,i)) + ')'
})
.attr('d',
d3.svg.symbol()
.type(getShape)
.size(function(d,i) { return z(getSize(d,i)) })
);
d3.svg.symbol()
.type(getShape)
.size(function(d,i) { return z(getSize(d,i)) })
);
d3.transition(groups.exit().selectAll('path.point'))
.attr('transform', function(d,i) {
return 'translate(' + x(getX(d,i)) + ',' + y(getY(d,i)) + ')'
@ -5718,14 +5731,14 @@ nv.models.scatter = function() {
return 'translate(' + x(getX(d,i)) + ',' + y(getY(d,i)) + ')'
})
.attr('d',
d3.svg.symbol()
.type(getShape)
.size(function(d,i) { return z(getSize(d,i)) })
);
d3.svg.symbol()
.type(getShape)
.size(function(d,i) { return z(getSize(d,i)) })
);
// Delay the update of the invisible interactive layer so animations are smoother in the meantime
clearTimeout(timeoutID); //make sure unncesary repeat calls to updateInteractiveLayer don't occur
// Delay updating the invisible interactive layer for smoother animation
clearTimeout(timeoutID); // stop repeat calls to updateInteractiveLayer
timeoutID = setTimeout(updateInteractiveLayer, 1000);
//store old scales for use in transitions on update
@ -5740,7 +5753,26 @@ nv.models.scatter = function() {
//============================================================
// Global getters and setters
// Event Handling/Dispatching (out of chart's scope)
//------------------------------------------------------------
dispatch.on('elementMouseover.point', function(d) {
if (interactive)
d3.select('.chart-' + id + ' .series-' + d.seriesIndex + ' .point-' + d.pointIndex)
.classed('hover', true);
});
dispatch.on('elementMouseout.point', function(d) {
if (interactive)
d3.select('.chart-' + id + ' .series-' + d.seriesIndex + ' .point-' + d.pointIndex)
.classed('hover', false);
});
//============================================================
//============================================================
// Expose Public Variables
//------------------------------------------------------------
chart.dispatch = dispatch;
@ -5841,6 +5873,12 @@ nv.models.scatter = function() {
return chart;
};
chart.pointActive = function(_) {
if (!arguments.length) return pointActive;
pointActive = _;
return chart;
};
chart.clipEdge = function(_) {
if (!arguments.length) return clipEdge;
clipEdge = _;
@ -5877,6 +5915,8 @@ nv.models.scatter = function() {
return chart;
};
//============================================================
return chart;
}

4
nv.d3.min.js vendored

File diff suppressed because one or more lines are too long

@ -5,36 +5,44 @@ nv.models.scatter = function() {
// Public Variables with Default Settings
//------------------------------------------------------------
var margin = {top: 0, right: 0, bottom: 0, left: 0},
width = 960,
height = 500,
color = d3.scale.category20().range(), // array of colors to be used in order
id = Math.floor(Math.random() * 100000), //Create semi-unique ID incase user doesn't selet one
x = d3.scale.linear(),
y = d3.scale.linear(),
z = d3.scale.linear(), //linear because d3.svg.shape.size is treated as area
getX = function(d) { return d.x }, // accessor to get the x value from a data point
getY = function(d) { return d.y }, // accessor to get the y value from a data point
getSize = function(d) { return d.size }, // accessor to get the point radius from a data point //TODO: consider renamig size to z
getShape = function(d) { return d.shape || 'circle' },
forceX = [], // List of numbers to Force into the X scale (ie. 0, or a max / min, etc.)
forceY = [], // List of numbers to Force into the Y scale
forceSize = [], // List of numbers to Force into the Size scale
interactive = true, // If true, plots a voronoi overlay for advanced point interection
//removeZeroes = false, // If true, filters out points with y == 0 from being interactive //TODO: implement
clipEdge = false, // if true, masks lines within x and y scale
clipVoronoi = true, // if true, masks each point with a circle... can turn off to slightly increase performance
clipRadius = function() { return 25 }, // function to get the radius for point clips
xDomain, yDomain, sizeDomain; // Used to manually set the x and y domain, good to save time if calculation has already been made
var margin = {top: 0, right: 0, bottom: 0, left: 0}
, width = 960
, height = 500
, color = d3.scale.category20().range() // array of colors to be used in order
, id = Math.floor(Math.random() * 100000) //Create semi-unique ID incase user doesn't selet one
, x = d3.scale.linear()
, y = d3.scale.linear()
, z = d3.scale.linear() //linear because d3.svg.shape.size is treated as area
, getX = function(d) { return d.x } // accessor to get the x value
, getY = function(d) { return d.y } // accessor to get the y value
, getSize = function(d) { return d.size } // accessor to get the point size
, getShape = function(d) { return d.shape || 'circle' } // accessor to get point shape
, forceX = [] // List of numbers to Force into the X scale (ie. 0, or a max / min, etc.)
, forceY = [] // List of numbers to Force into the Y scale
, forceSize = [] // List of numbers to Force into the Size scale
, interactive = true // If true, plots a voronoi overlay for advanced point interection
, pointActive = function(d) { return !d.notActive } // any points that return false will be filtered out
, clipEdge = false // if true, masks points within x and y scale
, clipVoronoi = true // if true, masks each point with a circle... can turn off to slightly increase performance
, clipRadius = function() { return 25 } // function to get the radius for voronoi point clips
, xDomain = null // Override x domain (skips the calculation from data)
, yDomain = null // Override y domain
, sizeDomain = null // Override point size domain
, dispatch = d3.dispatch('elementClick', 'elementMouseover', 'elementMouseout')
;
//============================================================
//============================================================
// Private Variables
//------------------------------------------------------------
var dispatch = d3.dispatch('elementClick', 'elementMouseover', 'elementMouseout'),
x0, y0, z0,
timeoutID;
var x0, y0, z0 // used to store previous scales
, timeoutID
;
//============================================================
function chart(selection) {
@ -43,11 +51,6 @@ nv.models.scatter = function() {
availableHeight = height - margin.top - margin.bottom,
container = d3.select(this);
//store old scales if they exist
x0 = x0 || x;
y0 = y0 || y;
z0 = z0 || z;
//add series index to each data point for reference
data = data.map(function(series, i) {
series.values = series.values.map(function(point) {
@ -58,26 +61,39 @@ nv.models.scatter = function() {
});
// slight remap of the data for use in calculating the scales domains
//------------------------------------------------------------
// Setup Scales
// remap and flatten the data for use in calculating the scales' domains
var seriesData = (xDomain && yDomain && sizeDomain) ? [] : // if we know xDomain and yDomain and sizeDomain, no need to calculate.... if Size is constant remember to set sizeDomain to speed up performance
data.map(function(d) {
return d.values.map(function(d,i) {
return { x: getX(d,i), y: getY(d,i), size: getSize(d,i) }
d3.merge(
data.map(function(d) {
return d.values.map(function(d,i) {
return { x: getX(d,i), y: getY(d,i), size: getSize(d,i) }
})
})
});
);
//TODO: figure out the best way to deal with scales with equal MIN and MAX
x .domain(xDomain || d3.extent(d3.merge(seriesData).map(function(d) { return d.x }).concat(forceX)))
x .domain(xDomain || d3.extent(seriesData.map(function(d) { return d.x }).concat(forceX)))
.range([0, availableWidth]);
y .domain(yDomain || d3.extent(d3.merge(seriesData).map(function(d) { return d.y }).concat(forceY)))
y .domain(yDomain || d3.extent(seriesData.map(function(d) { return d.y }).concat(forceY)))
.range([availableHeight, 0]);
z .domain(sizeDomain || d3.extent(d3.merge(seriesData).map(function(d) { return d.size }).concat(forceSize)))
z .domain(sizeDomain || d3.extent(seriesData.map(function(d) { return d.size }).concat(forceSize)))
.range([16, 256]);
//.range([2, 10]);
//store old scales if they exist
x0 = x0 || x;
y0 = y0 || y;
z0 = z0 || z;
//------------------------------------------------------------
//------------------------------------------------------------
// Setup containers and skeleton of chart
var wrap = container.selectAll('g.wrap.scatter').data([data]);
var wrapEnter = wrap.enter().append('g').attr('class', 'wrap nvd3 scatter chart-' +id);
@ -86,9 +102,12 @@ nv.models.scatter = function() {
var g = wrap.select('g')
gEnter.append('g').attr('class', 'groups');
gEnter.append('g').attr('class', 'point-paths');
wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
//------------------------------------------------------------
defsEnter.append('clipPath')
.attr('id', 'edge-clip-' + id)
@ -104,21 +123,17 @@ nv.models.scatter = function() {
function updateInteractiveLayer() {
if (!interactive) {
//wrap.select('#points-clip-' + id).remove();
//wrap.select('.point-paths').remove();
return false;
}
if (!interactive) return false;
gEnter.append('g').attr('class', 'point-paths');
// TODO: add a removeZeros option, useful for the stacked chart and maybe others
var vertices = d3.merge(data.map(function(group, groupIndex) {
return group.values.map(function(point, pointIndex) {
// Adding noise to make duplicates very unlikely
// Injecting series and point index for reference
return [x(getX(point,pointIndex)) * (Math.random() / 1e12 + 1) , y(getY(point,pointIndex)) * (Math.random() / 1e12 + 1), groupIndex, pointIndex]; //temp hack to add noise untill I think of a better way so there are no duplicates
})
return group.values
.filter(pointActive) // remove non-interactive points
.map(function(point, pointIndex) {
// *Adding noise to make duplicates very unlikely
// **Injecting series and point index for reference
return [x(getX(point,pointIndex)) * (Math.random() / 1e12 + 1) , y(getY(point,pointIndex)) * (Math.random() / 1e12 + 1), groupIndex, pointIndex]; //temp hack to add noise untill I think of a better way so there are no duplicates
})
})
);
@ -141,7 +156,13 @@ nv.models.scatter = function() {
//inject series and point index for reference into voronoi
var voronoi = d3.geom.voronoi(vertices).map(function(d, i) { return { 'data': d, 'series': vertices[i][2], 'point': vertices[i][3] } });
var voronoi = d3.geom.voronoi(vertices).map(function(d, i) {
return {
'data': d,
'series': vertices[i][2],
'point': vertices[i][3]
}
});
var pointPaths = wrap.select('.point-paths').selectAll('path')
@ -176,29 +197,21 @@ nv.models.scatter = function() {
});
})
.on('mouseout', function(d, i) {
var series = data[d.series],
point = series.values[d.point];
dispatch.elementMouseout({
point: data[d.series].values[d.point],
series: data[d.series],
point: point,
series: series,
seriesIndex: d.series,
pointIndex: d.point
});
});
dispatch.on('elementMouseover.point', function(d) {
d3.select('.chart-' + id + ' .series-' + d.seriesIndex + ' .point-' + d.pointIndex)
.classed('hover', true);
});
dispatch.on('elementMouseout.point', function(d) {
d3.select('.chart-' + id + ' .series-' + d.seriesIndex + ' .point-' + d.pointIndex)
.classed('hover', false);
});
}
var groups = wrap.select('.groups').selectAll('.group')
.data(function(d) { return d }, function(d) { return d.key });
groups.enter().append('g')
@ -225,10 +238,10 @@ nv.models.scatter = function() {
return 'translate(' + x0(getX(d,i)) + ',' + y0(getY(d,i)) + ')'
})
.attr('d',
d3.svg.symbol()
.type(getShape)
.size(function(d,i) { return z(getSize(d,i)) })
);
d3.svg.symbol()
.type(getShape)
.size(function(d,i) { return z(getSize(d,i)) })
);
d3.transition(groups.exit().selectAll('path.point'))
.attr('transform', function(d,i) {
return 'translate(' + x(getX(d,i)) + ',' + y(getY(d,i)) + ')'
@ -240,14 +253,14 @@ nv.models.scatter = function() {
return 'translate(' + x(getX(d,i)) + ',' + y(getY(d,i)) + ')'
})
.attr('d',
d3.svg.symbol()
.type(getShape)
.size(function(d,i) { return z(getSize(d,i)) })
);
d3.svg.symbol()
.type(getShape)
.size(function(d,i) { return z(getSize(d,i)) })
);
// Delay the update of the invisible interactive layer so animations are smoother in the meantime
clearTimeout(timeoutID); //make sure unncesary repeat calls to updateInteractiveLayer don't occur
// Delay updating the invisible interactive layer for smoother animation
clearTimeout(timeoutID); // stop repeat calls to updateInteractiveLayer
timeoutID = setTimeout(updateInteractiveLayer, 1000);
//store old scales for use in transitions on update
@ -262,7 +275,26 @@ nv.models.scatter = function() {
//============================================================
// Global getters and setters
// Event Handling/Dispatching (out of chart's scope)
//------------------------------------------------------------
dispatch.on('elementMouseover.point', function(d) {
if (interactive)
d3.select('.chart-' + id + ' .series-' + d.seriesIndex + ' .point-' + d.pointIndex)
.classed('hover', true);
});
dispatch.on('elementMouseout.point', function(d) {
if (interactive)
d3.select('.chart-' + id + ' .series-' + d.seriesIndex + ' .point-' + d.pointIndex)
.classed('hover', false);
});
//============================================================
//============================================================
// Expose Public Variables
//------------------------------------------------------------
chart.dispatch = dispatch;
@ -363,6 +395,12 @@ nv.models.scatter = function() {
return chart;
};
chart.pointActive = function(_) {
if (!arguments.length) return pointActive;
pointActive = _;
return chart;
};
chart.clipEdge = function(_) {
if (!arguments.length) return clipEdge;
clipEdge = _;
@ -399,6 +437,8 @@ nv.models.scatter = function() {
return chart;
};
//============================================================
return chart;
}

Loading…
Cancel
Save