Moving Pull Request #202 to backup until we iron out some problems

master-patched
Bob Monteverde 12 years ago
parent 4cd94ff5d8
commit 1c67464234

@ -47,8 +47,8 @@ var chart = nv.models.bullet()
.attr("class", "bullet nvd3")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
//.append("g")
//.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
vis
.transition()

@ -946,9 +946,7 @@ nv.models.bullet = function() {
selection.each(function(d, i) {
var availableWidth = width - margin.left - margin.right,
availableHeight = height - margin.top - margin.bottom,
container = d3.select(this),
mainGroup = this.parentNode.parentNode.getAttribute('transform')
heightFromTop = parseInt(mainGroup.replace(/.*,(\d+)\)/,"$1")) //TODO: There should be a smarter way to get this value
container = d3.select(this);
var rangez = ranges.call(this, d, i).slice().sort(d3.descending),
markerz = markers.call(this, d, i).slice().sort(d3.descending),
@ -959,9 +957,8 @@ nv.models.bullet = function() {
// Setup Scales
// Compute the new x-scale.
var MaxX = Math.max(rangez[0] ? rangez[0]:0 , markerz[0] ? markerz[0] : 0 , measurez[0] ? measurez[0] : 0)
var x1 = d3.scale.linear()
.domain([0, MaxX]).nice() // TODO: need to allow forceX and forceY, and xDomain, yDomain
.domain([0, Math.max(rangez[0], markerz[0], measurez[0])]) // TODO: need to allow forceX and forceY, and xDomain, yDomain
.range(reverse ? [availableWidth, 0] : [0, availableWidth]);
// Retrieve the old x-scale, if this is an update.
@ -1006,7 +1003,7 @@ nv.models.bullet = function() {
dispatch.elementMouseover({
value: d,
label: (i <= 0) ? 'Maximum' : (i > 1) ? 'Minimum' : 'Mean', //TODO: make these labels a variable
pos: [x1(d), heightFromTop]
pos: [x1(d), availableHeight/2]
})
})
.on('mouseout', function(d,i) {
@ -1036,7 +1033,7 @@ nv.models.bullet = function() {
dispatch.elementMouseover({
value: d,
label: 'Current', //TODO: make these labels a variable
pos: [x1(d), heightFromTop]
pos: [x1(d), availableHeight/2]
})
})
.on('mouseout', function(d) {
@ -1067,7 +1064,7 @@ nv.models.bullet = function() {
dispatch.elementMouseover({
value: d,
label: 'Previous',
pos: [x1(d), heightFromTop]
pos: [x1(d), availableHeight/2]
})
})
.on('mouseout', function(d,i) {
@ -1203,15 +1200,15 @@ nv.models.bulletChart = function() {
// Private Variables
//------------------------------------------------------------
var showTooltip = function(e, parentElement) {
var offsetElement = parentElement.parentNode.parentNode,
var showTooltip = function(e, offsetElement) {
var offsetElement = document.getElementById("chart"),
left = e.pos[0] + offsetElement.offsetLeft + margin.left,
top = e.pos[1] + offsetElement.offsetTop + margin.top;
var content = '<h3>' + e.label + '</h3>' +
'<p>' + e.value + '</p>';
nv.tooltip.show([left, top], content, e.value < 0 ? 'e' : 'w', null, offsetElement.parentNode);
nv.tooltip.show([left, top], content, e.value < 0 ? 'e' : 'w', null, offsetElement);
};
//============================================================
@ -1274,15 +1271,14 @@ nv.models.bulletChart = function() {
gEnter.append('g').attr('class', 'nv-bulletWrap');
gEnter.append('g').attr('class', 'nv-titles');
wrap.attr('transform', 'translate(' + margin.left + ',' + ( margin.top + i*height )+ ')');
wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
//------------------------------------------------------------
// Compute the new x-scale.
var MaxX = Math.max(rangez[0] ? rangez[0]:0 , markerz[0] ? markerz[0] : 0 , measurez[0] ? measurez[0] : 0)
var x1 = d3.scale.linear()
.domain([0, MaxX]).nice() // TODO: need to allow forceX and forceY, and xDomain, yDomain
.domain([0, Math.max(rangez[0], markerz[0], measurez[0])]) // TODO: need to allow forceX and forceY, and xDomain, yDomain
.range(reverse ? [availableWidth, 0] : [0, availableWidth]);
// Retrieve the old x-scale, if this is an update.

10
nv.d3.min.js vendored

File diff suppressed because one or more lines are too long

@ -0,0 +1,250 @@
// Chart design based on the recommendations of Stephen Few. Implementation
// based on the work of Clint Ivy, Jamie Love, and Jason Davies.
// http://projects.instantcognition.com/protovis/bulletchart/
nv.models.bullet = function() {
//============================================================
// Public Variables with Default Settings
//------------------------------------------------------------
var margin = {top: 0, right: 0, bottom: 0, left: 0}
, orient = 'left' // TODO top & bottom
, reverse = false
, ranges = function(d) { return d.ranges }
, markers = function(d) { return d.markers }
, measures = function(d) { return d.measures }
, forceX = [0] // List of numbers to Force into the X scale (ie. 0, or a max / min, etc.)
, width = 380
, height = 30
, tickFormat = null
, dispatch = d3.dispatch('elementMouseover', 'elementMouseout')
;
//============================================================
function chart(selection) {
selection.each(function(d, i) {
var availableWidth = width - margin.left - margin.right,
availableHeight = height - margin.top - margin.bottom,
container = d3.select(this),
mainGroup = nv.log(this.parentNode.parentNode).getAttribute('transform'),
heightFromTop = nv.log(parseInt(mainGroup.replace(/.*,(\d+)\)/,"$1"))); //TODO: There should be a smarter way to get this value
var rangez = ranges.call(this, d, i).slice().sort(d3.descending),
markerz = markers.call(this, d, i).slice().sort(d3.descending),
measurez = measures.call(this, d, i).slice().sort(d3.descending);
//------------------------------------------------------------
// Setup Scales
// Compute the new x-scale.
var MaxX = Math.max(rangez[0] ? rangez[0]:0 , markerz[0] ? markerz[0] : 0 , measurez[0] ? measurez[0] : 0)
var x1 = d3.scale.linear()
.domain([0, MaxX]).nice() // TODO: need to allow forceX and forceY, and xDomain, yDomain
.range(reverse ? [availableWidth, 0] : [0, availableWidth]);
// Retrieve the old x-scale, if this is an update.
var x0 = this.__chart__ || d3.scale.linear()
.domain([0, Infinity])
.range(x1.range());
// Stash the new scale.
this.__chart__ = x1;
//------------------------------------------------------------
//------------------------------------------------------------
// Setup containers and skeleton of chart
var wrap = container.selectAll('g.nv-wrap.nv-bullet').data([d]);
var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-bullet');
var gEnter = wrapEnter.append('g');
var g = wrap.select('g');
wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
//------------------------------------------------------------
var w0 = function(d) { return Math.abs(x0(d) - x0(0)) }, // TODO: could optimize by precalculating x0(0) and x1(0)
w1 = function(d) { return Math.abs(x1(d) - x1(0)) };
// Update the range rects.
var range = g.selectAll('rect.nv-range')
.data(rangez);
range.enter().append('rect')
.attr('class', function(d, i) { return 'nv-range nv-s' + i; })
.attr('width', w0)
.attr('height', availableHeight)
.attr('x', reverse ? x0 : 0)
.on('mouseover', function(d,i) {
dispatch.elementMouseover({
value: d,
label: (i <= 0) ? 'Maximum' : (i > 1) ? 'Minimum' : 'Mean', //TODO: make these labels a variable
pos: [x1(d), heightFromTop]
})
})
.on('mouseout', function(d,i) {
dispatch.elementMouseout({
value: d,
label: (i <= 0) ? 'Minimum' : (i >=1) ? 'Maximum' : 'Mean' //TODO: make these labels a variable
})
})
d3.transition(range)
.attr('x', reverse ? x1 : 0)
.attr('width', w1)
.attr('height', availableHeight);
// Update the measure rects.
var measure = g.selectAll('rect.nv-measure')
.data(measurez);
measure.enter().append('rect')
.attr('class', function(d, i) { return 'nv-measure nv-s' + i; })
.attr('width', w0)
.attr('height', availableHeight / 3)
.attr('x', reverse ? x0 : 0)
.attr('y', availableHeight / 3)
.on('mouseover', function(d) {
dispatch.elementMouseover({
value: d,
label: 'Current', //TODO: make these labels a variable
pos: [x1(d), heightFromTop]
})
})
.on('mouseout', function(d) {
dispatch.elementMouseout({
value: d,
label: 'Current' //TODO: make these labels a variable
})
})
d3.transition(measure)
.attr('width', w1)
.attr('height', availableHeight / 3)
.attr('x', reverse ? x1 : 0)
.attr('y', availableHeight / 3);
// Update the marker lines.
var marker = g.selectAll('path.nv-markerTriangle')
.data(markerz);
var h3 = availableHeight / 6;
marker.enter().append('path')
.attr('class', 'nv-markerTriangle')
.attr('transform', function(d) { return 'translate(' + x0(d) + ',' + (availableHeight / 2) + ')' })
.attr('d', 'M0,' + h3 + 'L' + h3 + ',' + (-h3) + ' ' + (-h3) + ',' + (-h3) + 'Z')
.on('mouseover', function(d,i) {
dispatch.elementMouseover({
value: d,
label: 'Previous',
pos: [x1(d), heightFromTop]
})
})
.on('mouseout', function(d,i) {
dispatch.elementMouseout({
value: d,
label: 'Previous'
})
});
d3.transition(marker)
.attr('transform', function(d) { return 'translate(' + x1(d) + ',' + (availableHeight / 2) + ')' });
marker.exit().remove();
});
d3.timer.flush();
return chart;
}
//============================================================
// Expose Public Variables
//------------------------------------------------------------
chart.dispatch = dispatch;
// left, right, top, bottom
chart.orient = function(_) {
if (!arguments.length) return orient;
orient = _;
reverse = orient == 'right' || orient == 'bottom';
return chart;
};
// ranges (bad, satisfactory, good)
chart.ranges = function(_) {
if (!arguments.length) return ranges;
ranges = _;
return chart;
};
// markers (previous, goal)
chart.markers = function(_) {
if (!arguments.length) return markers;
markers = _;
return chart;
};
// measures (actual, forecast)
chart.measures = function(_) {
if (!arguments.length) return measures;
measures = _;
return chart;
};
chart.forceX = function(_) {
if (!arguments.length) return forceX;
forceX = _;
return chart;
};
chart.width = function(_) {
if (!arguments.length) return width;
width = _;
return chart;
};
chart.height = function(_) {
if (!arguments.length) return height;
height = _;
return chart;
};
chart.margin = function(_) {
if (!arguments.length) return margin;
margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
return chart;
};
chart.tickFormat = function(_) {
if (!arguments.length) return tickFormat;
tickFormat = _;
return chart;
};
//============================================================
return chart;
};

@ -0,0 +1,349 @@
// Chart design based on the recommendations of Stephen Few. Implementation
// based on the work of Clint Ivy, Jamie Love, and Jason Davies.
// http://projects.instantcognition.com/protovis/bulletchart/
nv.models.bulletChart = function() {
//============================================================
// Public Variables with Default Settings
//------------------------------------------------------------
var bullet = nv.models.bullet()
;
var orient = 'left' // TODO top & bottom
, reverse = false
, margin = {top: 5, right: 40, bottom: 20, left: 120}
, ranges = function(d) { return d.ranges }
, markers = function(d) { return d.markers }
, measures = function(d) { return d.measures }
, width = null
, height = 55
, tickFormat = null
, tooltips = true
, tooltip = function(key, x, y, e, graph) {
return '<h3>' + e.label + '</h3>' +
'<p>' + e.value + '</p>'
}
, noData = "No Data Available."
, dispatch = d3.dispatch('tooltipShow', 'tooltipHide')
;
//============================================================
//============================================================
// Private Variables
//------------------------------------------------------------
var showTooltip = function(e, parentElement) {
var offsetElement = parentElement.parentNode.parentNode,
left = e.pos[0] + offsetElement.offsetLeft + margin.left,
top = e.pos[1] + offsetElement.offsetTop + margin.top;
var content = '<h3>' + e.label + '</h3>' +
'<p>' + e.value + '</p>';
nv.tooltip.show([left, top], content, e.value < 0 ? 'e' : 'w', null, offsetElement.parentNode);
};
//============================================================
function chart(selection) {
selection.each(function(d, i) {
var container = d3.select(this);
var availableWidth = (width || parseInt(container.style('width')) || 960)
- margin.left - margin.right,
availableHeight = height - margin.top - margin.bottom,
that = this;
chart.update = function() { chart(selection) };
chart.container = this;
//------------------------------------------------------------
// Display No Data message if there's nothing to show.
/*
// Disabled until I figure out a better way to check for no data with the bullet chart
if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
var noDataText = container.selectAll('.nv-noData').data([noData]);
noDataText.enter().append('text')
.attr('class', 'nvd3 nv-noData')
.attr('dy', '-.7em')
.style('text-anchor', 'middle');
noDataText
.attr('x', margin.left + availableWidth / 2)
.attr('y', margin.top + availableHeight / 2)
.text(function(d) { return d });
return chart;
} else {
container.selectAll('.nv-noData').remove();
}
*/
//------------------------------------------------------------
var rangez = ranges.call(this, d, i).slice().sort(d3.descending),
markerz = markers.call(this, d, i).slice().sort(d3.descending),
measurez = measures.call(this, d, i).slice().sort(d3.descending);
//------------------------------------------------------------
// Setup containers and skeleton of chart
var wrap = container.selectAll('g.nv-wrap.nv-bulletChart').data([d]);
var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-bulletChart');
var gEnter = wrapEnter.append('g');
var g = wrap.select('g');
gEnter.append('g').attr('class', 'nv-bulletWrap');
gEnter.append('g').attr('class', 'nv-titles');
wrap.attr('transform', 'translate(' + margin.left + ',' + ( margin.top + i*height )+ ')');
//------------------------------------------------------------
// Compute the new x-scale.
var MaxX = Math.max(rangez[0] ? rangez[0]:0 , markerz[0] ? markerz[0] : 0 , measurez[0] ? measurez[0] : 0)
var x1 = d3.scale.linear()
.domain([0, MaxX]).nice() // TODO: need to allow forceX and forceY, and xDomain, yDomain
.range(reverse ? [availableWidth, 0] : [0, availableWidth]);
// Retrieve the old x-scale, if this is an update.
var x0 = this.__chart__ || d3.scale.linear()
.domain([0, Infinity])
.range(x1.range());
// Stash the new scale.
this.__chart__ = x1;
/*
// Derive width-scales from the x-scales.
var w0 = bulletWidth(x0),
w1 = bulletWidth(x1);
function bulletWidth(x) {
var x0 = x(0);
return function(d) {
return Math.abs(x(d) - x(0));
};
}
function bulletTranslate(x) {
return function(d) {
return 'translate(' + x(d) + ',0)';
};
}
*/
var w0 = function(d) { return Math.abs(x0(d) - x0(0)) }, // TODO: could optimize by precalculating x0(0) and x1(0)
w1 = function(d) { return Math.abs(x1(d) - x1(0)) };
var title = gEnter.select('.nv-titles').append("g")
.attr("text-anchor", "end")
.attr("transform", "translate(-6," + (height - margin.top - margin.bottom) / 2 + ")");
title.append("text")
.attr("class", "nv-title")
.text(function(d) { return d.title; });
title.append("text")
.attr("class", "nv-subtitle")
.attr("dy", "1em")
.text(function(d) { return d.subtitle; });
bullet
.width(availableWidth)
.height(availableHeight)
var bulletWrap = g.select('.nv-bulletWrap');
d3.transition(bulletWrap).call(bullet);
// Compute the tick format.
var format = tickFormat || x1.tickFormat(8);
// Update the tick groups.
var tick = g.selectAll('g.nv-tick')
.data(x1.ticks(8), function(d) {
return this.textContent || format(d);
});
// Initialize the ticks with the old scale, x0.
var tickEnter = tick.enter().append('g')
.attr('class', 'nv-tick')
.attr('transform', function(d) { return 'translate(' + x0(d) + ',0)' })
.style('opacity', 1e-6);
tickEnter.append('line')
.attr('y1', availableHeight)
.attr('y2', availableHeight * 7 / 6);
tickEnter.append('text')
.attr('text-anchor', 'middle')
.attr('dy', '1em')
.attr('y', availableHeight * 7 / 6)
.text(format);
// Transition the entering ticks to the new scale, x1.
d3.transition(tickEnter)
.attr('transform', function(d) { return 'translate(' + x1(d) + ',0)' })
.style('opacity', 1);
// Transition the updating ticks to the new scale, x1.
var tickUpdate = d3.transition(tick)
.attr('transform', function(d) { return 'translate(' + x1(d) + ',0)' })
.style('opacity', 1);
tickUpdate.select('line')
.attr('y1', availableHeight)
.attr('y2', availableHeight * 7 / 6);
tickUpdate.select('text')
.attr('y', availableHeight * 7 / 6);
// Transition the exiting ticks to the new scale, x1.
d3.transition(tick.exit())
.attr('transform', function(d) { return 'translate(' + x1(d) + ',0)' })
.style('opacity', 1e-6)
.remove();
//============================================================
// Event Handling/Dispatching (in chart's scope)
//------------------------------------------------------------
dispatch.on('tooltipShow', function(e) {
if (tooltips) showTooltip(e, that.parentNode);
});
//============================================================
});
d3.timer.flush();
return chart;
}
//============================================================
// Event Handling/Dispatching (out of chart's scope)
//------------------------------------------------------------
bullet.dispatch.on('elementMouseover.tooltip', function(e) {
dispatch.tooltipShow(e);
});
bullet.dispatch.on('elementMouseout.tooltip', function(e) {
dispatch.tooltipHide(e);
});
dispatch.on('tooltipHide', function() {
if (tooltips) nv.tooltip.cleanup();
});
//============================================================
//============================================================
// Expose Public Variables
//------------------------------------------------------------
chart.dispatch = dispatch;
chart.bullet = bullet;
// left, right, top, bottom
chart.orient = function(x) {
if (!arguments.length) return orient;
orient = x;
reverse = orient == 'right' || orient == 'bottom';
return chart;
};
// ranges (bad, satisfactory, good)
chart.ranges = function(x) {
if (!arguments.length) return ranges;
ranges = x;
return chart;
};
// markers (previous, goal)
chart.markers = function(x) {
if (!arguments.length) return markers;
markers = x;
return chart;
};
// measures (actual, forecast)
chart.measures = function(x) {
if (!arguments.length) return measures;
measures = x;
return chart;
};
chart.width = function(x) {
if (!arguments.length) return width;
width = x;
return chart;
};
chart.height = function(x) {
if (!arguments.length) return height;
height = x;
return chart;
};
chart.margin = function(_) {
if (!arguments.length) return margin;
margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
return chart;
};
chart.tickFormat = function(x) {
if (!arguments.length) return tickFormat;
tickFormat = x;
return chart;
};
chart.tooltips = function(_) {
if (!arguments.length) return tooltips;
tooltips = _;
return chart;
};
chart.tooltipContent = function(_) {
if (!arguments.length) return tooltip;
tooltip = _;
return chart;
};
chart.noData = function(_) {
if (!arguments.length) return noData;
noData = _;
return chart;
};
//============================================================
return chart;
};

@ -29,9 +29,7 @@ nv.models.bullet = function() {
selection.each(function(d, i) {
var availableWidth = width - margin.left - margin.right,
availableHeight = height - margin.top - margin.bottom,
container = d3.select(this),
mainGroup = this.parentNode.parentNode.getAttribute('transform')
heightFromTop = parseInt(mainGroup.replace(/.*,(\d+)\)/,"$1")) //TODO: There should be a smarter way to get this value
container = d3.select(this);
var rangez = ranges.call(this, d, i).slice().sort(d3.descending),
markerz = markers.call(this, d, i).slice().sort(d3.descending),
@ -42,9 +40,8 @@ nv.models.bullet = function() {
// Setup Scales
// Compute the new x-scale.
var MaxX = Math.max(rangez[0] ? rangez[0]:0 , markerz[0] ? markerz[0] : 0 , measurez[0] ? measurez[0] : 0)
var x1 = d3.scale.linear()
.domain([0, MaxX]).nice() // TODO: need to allow forceX and forceY, and xDomain, yDomain
.domain([0, Math.max(rangez[0], markerz[0], measurez[0])]) // TODO: need to allow forceX and forceY, and xDomain, yDomain
.range(reverse ? [availableWidth, 0] : [0, availableWidth]);
// Retrieve the old x-scale, if this is an update.
@ -89,7 +86,7 @@ nv.models.bullet = function() {
dispatch.elementMouseover({
value: d,
label: (i <= 0) ? 'Maximum' : (i > 1) ? 'Minimum' : 'Mean', //TODO: make these labels a variable
pos: [x1(d), heightFromTop]
pos: [x1(d), availableHeight/2]
})
})
.on('mouseout', function(d,i) {
@ -119,7 +116,7 @@ nv.models.bullet = function() {
dispatch.elementMouseover({
value: d,
label: 'Current', //TODO: make these labels a variable
pos: [x1(d), heightFromTop]
pos: [x1(d), availableHeight/2]
})
})
.on('mouseout', function(d) {
@ -150,7 +147,7 @@ nv.models.bullet = function() {
dispatch.elementMouseover({
value: d,
label: 'Previous',
pos: [x1(d), heightFromTop]
pos: [x1(d), availableHeight/2]
})
})
.on('mouseout', function(d,i) {

@ -36,15 +36,15 @@ nv.models.bulletChart = function() {
// Private Variables
//------------------------------------------------------------
var showTooltip = function(e, parentElement) {
var offsetElement = parentElement.parentNode.parentNode,
var showTooltip = function(e, offsetElement) {
var offsetElement = document.getElementById("chart"),
left = e.pos[0] + offsetElement.offsetLeft + margin.left,
top = e.pos[1] + offsetElement.offsetTop + margin.top;
var content = '<h3>' + e.label + '</h3>' +
'<p>' + e.value + '</p>';
nv.tooltip.show([left, top], content, e.value < 0 ? 'e' : 'w', null, offsetElement.parentNode);
nv.tooltip.show([left, top], content, e.value < 0 ? 'e' : 'w', null, offsetElement);
};
//============================================================
@ -107,15 +107,14 @@ nv.models.bulletChart = function() {
gEnter.append('g').attr('class', 'nv-bulletWrap');
gEnter.append('g').attr('class', 'nv-titles');
wrap.attr('transform', 'translate(' + margin.left + ',' + ( margin.top + i*height )+ ')');
wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
//------------------------------------------------------------
// Compute the new x-scale.
var MaxX = Math.max(rangez[0] ? rangez[0]:0 , markerz[0] ? markerz[0] : 0 , measurez[0] ? measurez[0] : 0)
var x1 = d3.scale.linear()
.domain([0, MaxX]).nice() // TODO: need to allow forceX and forceY, and xDomain, yDomain
.domain([0, Math.max(rangez[0], markerz[0], measurez[0])]) // TODO: need to allow forceX and forceY, and xDomain, yDomain
.range(reverse ? [availableWidth, 0] : [0, availableWidth]);
// Retrieve the old x-scale, if this is an update.

Loading…
Cancel
Save