merging in pull request from @Nathanaela removing jQuery dependence, added pie chart model, some other useful changes

master-patched
Bob Monteverde 12 years ago
commit 9352d35cfc

@ -1,10 +1,12 @@
JS_FILES = \
src/nvtooltip.js \
src/intro.js \
src/core.js \
src/tooltip.js \
src/utils.js \
src/models/legend.js \
src/models/axis.js \
src/models/bar.js \
src/models/pie.js \
src/models/line.js \
src/models/lineWithFocus.js \
src/models/lineWithLegend.js \

@ -0,0 +1,6 @@
@echo off
copy src\intro.js /B + src\core.js /B + src\tooltip.js /B temp1.js /B
copy src\models\*.js /B + src\charts\*.js /B temp2.js /B
copy temp1.js /B + temp2.js /B + src\outro.js /B nv.d3.js /B
del temp1.js
del temp2.js

@ -17,18 +17,17 @@ text {
<svg id="test1"></svg>
<script src="../lib/d3.v2.js"></script>
<script src="../lib/jquery.min.js"></script>
<script src="../nv.d3.js"></script>
<script src="../src/models/bar.js"></script>
<script>
var testdata = [
{
label: "One",
label: "One is a very long",
y: 5
},
{
label: "Two",
label: "Two is also very long",
y: 2
},
{
@ -37,46 +36,134 @@ text {
},
{
label: "Four",
y: 7
y: 7
},
{
label: "Five",
y: 4
},
{
label: "Six",
y: 3
}
];
var testdata2 = [
{
label: "One is a very long",
y: 1
},
{
label: "Two is also very long",
y: 12
},
{
label: "Three",
y: -9
},
{
label: "Four",
y: 4
},
{
label: "Five",
y: 6
}
];
var td = 0;
var a = (Math.random()*10)+1;
if (a > 5) td = 1;
//Format A
nv.addGraph({
generate: function() {
var width = $(window).width() - 40,
height = $(window).height() - 40;
var width = nv.utils.windowSize().width - 40,
height = nv.utils.windowSize().height - 40;
var chart = nv.models.bar()
.width(width)
.height(height);
d3.select("#test1")
.attr('width', width)
.attr('height', height)
.datum(testdata)
.call(chart);
.height(height)
.labelField('label')
.dataField('y')
.showLabels(true)
.title("This is a sample chart title")
;
if (td === 0) {
d3.select("#test1")
.attr('width', width)
.attr('height', height)
.datum(testdata)
.call(chart);
} else {
d3.select("#test1")
.attr('width', width)
.attr('height', height)
.datum(testdata2)
.call(chart);
}
return chart;
},
callback: function(graph) {
$(window).resize(function() {
var width = $(window).width() - 40,
height = $(window).height() - 40;
graph.dispatch.on('tooltipShow', function(e) {
var offsetElement = document.getElementById("chart"),
left = e.pos[0],
top = e.pos[1];
var content = '<h3>' + e.label + '</h3>' +
'<p>' +
e.value +
'</p>';
nv.tooltip.show([left, top], content);
});
graph.dispatch.on('tooltipHide', function(e) {
nv.tooltip.cleanup();
});
graph.dispatch.on('elementClick', function(e) {
console.log("Bar Click",e);
});
graph.dispatch.on('chartClick', function(e) {
console.log("Chart Click",e);
});
graph.dispatch.on('chartClick', function(e) {
console.log('Click Switching to');
if (td === 0) {
d3.select("#test1")
.datum(testdata2)
.call(graph);
td = 1;
} else {
d3.select("#test1")
.datum(testdata)
.call(graph);
td = 0;
}
});
window.onresize = function() {
var width = nv.utils.windowSize().width - 40,
height = nv.utils.windowSize().height - 40;
d3.select("#test1")
.attr('width', width)
.attr('height', height)
.call(
graph
.width($(window).width() - 40)
.height($(window).height() - 40)
.width(width)
.height(height)
)
});
};
}
});

@ -21,9 +21,8 @@ text {
</div>
<script src="../lib/d3.v2.js"></script>
<script src="../lib/jquery.min.js"></script>
<script src="../nv.d3.js"></script>
<script src="../src/nvtooltip.js"></script>
<script src="../src/tooltip.js"></script>
<script src="../src/models/legend.js"></script>
<script src="../src/models/axis.js"></script>
<script src="../src/models/line.js"></script>
@ -60,8 +59,8 @@ var cumulativeMonthEndTestData = [
nv.addGraph({
generate: function() {
var width = $(window).width() - 40,
height = $(window).height() - 40;
var width = nv.utils.windowSize().width - 40,
height = nv.utils.windowSize().height - 40;
var chart = nv.models.cumulativeLine()
.width(width)
@ -94,9 +93,9 @@ nv.addGraph({
callback: function(graph) {
graph.dispatch.on('tooltipShow', function(e) {
var offset = $('#test1').offset(),
left = e.pos[0] + offset.left,
top = e.pos[1] + offset.top,
var offsetElement = document.getElementById("test1"),
left = e.pos[0] + offsetElement.offsetLeft,
top = e.pos[1] + offsetElement.offsetTop,
formatterY = d3.format(",.2%"),
formatterX = function(d) {
return d3.time.format('%x')(new Date(d))
@ -107,20 +106,19 @@ nv.addGraph({
formatterY(graph.y()(e.point)) + ' on ' + formatterX(graph.x()(e.point)) +
'</p>';
//$('#positionTest').css({'left': left, 'top': top});
nvtooltip.show([left, top], content);
nv.tooltip.show([left, top], content);
});
graph.dispatch.on('tooltipHide', function(e) {
nvtooltip.cleanup();
nv.tooltip.cleanup();
});
$(window).resize(function() {
var width = $(window).width() - 40,
height = $(window).height() - 40,
margin = graph.margin();
window.onresize = function() {
var width = nv.utils.windowSize().width - 40,
height = nv.utils.windowSize().height - 40,
margin = graph.margin();
if (width < margin.left + margin.right + 20)
@ -139,7 +137,7 @@ nv.addGraph({
.attr('height', height)
.call(graph);
});
};
}
});

@ -9,7 +9,6 @@
<svg id="test1"></svg>
<script src="../lib/d3.v2.js"></script>
<script src="../lib/jquery.min.js"></script>
<script src="../nv.d3.js"></script>
<script src="../src/models/legend.js"></script>
<script>
@ -25,7 +24,7 @@ nv.addGraph({
.width(width)
.height(height);
chart.dispatch.on('legendClick', function(d,i) { log(d,i) });
chart.dispatch.on('legendClick', function(d,i) { console.log(d,i) });
//chart.xaxis.tickFormat(d3.format(".02f"))

@ -13,7 +13,6 @@ body {
<svg id="test1"></svg>
<script src="../lib/d3.v2.js"></script>
<script src="../lib/jquery.min.js"></script>
<script src="../nv.d3.js"></script>
<script src="../src/models/legend.js"></script>
<script src="../src/models/line.js"></script>
@ -24,8 +23,8 @@ body {
//Format A
nv.addGraph({
generate: function() {
var width = $(window).width() - 40,
height = $(window).height() - 40;
var width = nv.utils.windowSize().width - 40,
height = nv.utils.windowSize().height - 40;
var chart = nv.models.line()
.width(width)
@ -42,11 +41,11 @@ nv.addGraph({
return chart;
},
callback: function(graph) {
$(window).resize(function() {
var width = $(window).width() - 40,
height = $(window).height() - 40,
window.onresize = function() {
var width = nv.utils.windowSize().width - 40,
height = nv.utils.windowSize().height - 40,
margin = graph.margin(),
animate = graph.animate();
animate = graph.animate();
if (width < margin.left + margin.right + 20)
@ -64,7 +63,7 @@ nv.addGraph({
.attr('width', width)
.attr('height', height)
.call(graph);
});
};
}
});

@ -32,10 +32,10 @@ text {
</div>
<script src="../lib/d3.v2.js"></script>
<script src="../lib/jquery.min.js"></script>
<!-- script src="../lib/jquery.min.js"></script -->
<script src="../nv.d3.js"></script>
<!-- including all the components so I don't have to minify every time I test in development -->
<script src="../src/nvtooltip.js"></script>
<script src="../src/tooltip.js"></script>
<script src="../src/models/legend.js"></script>
<script src="../src/models/axis.js"></script>
<script src="../src/models/line.js"></script>

@ -22,9 +22,8 @@ text {
</div>
<script src="../lib/d3.v2.js"></script>
<script src="../lib/jquery.min.js"></script>
<script src="../nv.d3.js"></script>
<script src="../src/nvtooltip.js"></script>
<script src="../src/tooltip.js"></script>
<script src="../src/models/legend.js"></script>
<script src="../src/models/axis.js"></script>
<script src="../src/models/line.js"></script>
@ -41,10 +40,10 @@ text {
nv.addGraph({
generate: function() {
var width = $(window).width() - 40,
height = $(window).height() - 40;
var width = nv.utils.windowSize().width - 40,
height = nv.utils.windowSize().height - 40;
var chart = nv.models.lineWithFocus()
var chart = nv.models.lineWithFocus()
.width(width)
.height(height)
//.dotRadius(1) //TODO: fix this setting
@ -64,29 +63,29 @@ nv.addGraph({
callback: function(graph) {
graph.dispatch.on('tooltipShow', function(e) {
var offset = $('#test1').offset(),
left = e.pos[0] + offset.left,
top = e.pos[1] + offset.top,
formatter = d3.format('.2r');
var offsetElement = document.getElementById("test1"),
left = e.pos[0] + offsetElement.offsetLeft,
top = e.pos[1] + offsetElement.offsetTop,
formatter = d3.format('.2r');
var content = '<h3>' + e.series.key + '</h3>' +
'<p>' +
formatter(graph.y()(e.point)) + ', ' + formatter(graph.x()(e.point)) +
'</p>';
nvtooltip.show([left, top], content);
nv.tooltip.show([left, top], content);
});
graph.dispatch.on('tooltipHide', function(e) {
nvtooltip.cleanup();
nv.tooltip.cleanup();
});
$(window).resize(function() {
var width = $(window).width() - 40,
height = $(window).height() - 40,
margin = graph.margin();
window.onresize = function() {
var width = nv.utils.windowSize().width - 40,
height = nv.utils.windowSize().height - 40,
margin = graph.margin();
if (width < margin.left + margin.right + 20)
@ -105,7 +104,7 @@ nv.addGraph({
.attr('height', height)
.call(graph);
});
};
}
});

@ -32,9 +32,8 @@ text {
</div>
<script src="../lib/d3.v2.js"></script>
<script src="../lib/jquery.min.js"></script>
<script src="../nv.d3.js"></script>
<script src="../src/nvtooltip.js"></script>
<script src="../src/tooltip.js"></script>
<script src="../src/models/legend.js"></script>
<script src="../src/models/axis.js"></script>
<script src="../src/models/line.js"></script>
@ -85,33 +84,34 @@ nv.addGraph({
},
callback: function(chart) {
var showTooltip = function(e) {
var offset = $(selector).offset(),
left = e.pos[0] + offset.left,
top = e.pos[1] + offset.top,
formatY = chart.yAxis.tickFormat(), //Assumes using same format as axis, can customize to show higher precision, etc.
var offsetElement = document.getElementById(selector.substr(1)),
left = e.pos[0] + offsetElement.offsetLeft,
top = e.pos[1] + offsetElement.offsetTop,
formatY = chart.yAxis.tickFormat(), //Assumes using same format as axis, can customize to show higher precision, etc.
formatX = chart.xAxis.tickFormat();
// uses the chart's getX and getY, you may customize if x position is not the same as the value you want
// uses the chart's getX and getY, you may customize if x position is not the same as the value you want
// ex. daily data without weekends, x is the index, while you want the date
var content = '<h3>' + e.series.key + '</h3>' +
'<p>' +
formatY(chart.y()(e.point)) + ' at ' + formatX(chart.x()(e.point)) +
'</p>';
nvtooltip.show([left, top], content);
nv.tooltip.show([left, top], content);
};
chart.dispatch.on('tooltipShow', showTooltip);
chart.dispatch.on('tooltipHide', nvtooltip.cleanup);
chart.dispatch.on('tooltipHide', nv.tooltip.cleanup);
$(window).resize(function() {
window.onresize= function() {
// now that width and height are functions, should be automatic..of course you can always override them
d3.select('#chart1 svg')
.attr('width', chart.width()()) //need to set SVG dimensions, chart is not aware of the SVG component
.attr('height', chart.height()())
.call(chart);
});
};
}
});

@ -9,7 +9,6 @@
<script src="../lib/d3.v2.js"></script>
<script src="../lib/jquery.min.js"></script>
<script src="../nv.d3.js"></script>
<script>

@ -0,0 +1,167 @@
<!DOCTYPE html>
<meta charset="utf-8">
<link href="../src/d3.css" rel="stylesheet" type="text/css">
<style>
body {
overflow-y:scroll;
}
text {
font: 12px sans-serif;
}
</style>
<body>
<svg id="test1"></svg>
<script src="../lib/d3.v2.js"></script>
<script src="../nv.d3.js"></script>
<script src="../src/models/pie.js"></script>
<script>
var testdata = [
{
label: "One",
y: 5
},
{
label: "Two",
y: 2
},
{
label: "Three",
y: 9
},
{
label: "Four",
y: 7
},
{
label: "Five",
y: 4
},
{
label: "Six",
y: 3
}
];
var testdata2 = [
{
label: "One",
y: 10
},
{
label: "Two",
y: 5
},
{
label: "Three",
y: 3
},
{
label: "Four",
y: 7
},
{
label: "Five",
y: 2
}
];
var td = 0;
var a = (Math.random()*10)+1;
if (a > 5) td = 1;
//Format A
nv.addGraph({
generate: function() {
var width = nv.utils.windowSize().width - 40,
height = nv.utils.windowSize().height - 40;
var chart = nv.models.pie()
.width(width)
.height(height)
.title('Hi this is the chart title')
;
if (td === 0) {
d3.select("#test1")
.attr('width', width)
.attr('height', height)
.datum(testdata)
.call(chart);
} else {
d3.select("#test1")
.attr('width', width)
.attr('height', height)
.datum(testdata2)
.call(chart);
}
return chart;
},
callback: function(graph) {
graph.dispatch.on('tooltipShow', function(e) {
var offsetElement = document.getElementById("chart"),
left = e.pos[0],
top = e.pos[1];
var content = '<h3>' + e.label + '</h3>' +
'<p>' +
e.value +
'</p>';
nv.tooltip.show([left, top], content);
});
graph.dispatch.on('tooltipHide', function(e) {
nv.tooltip.cleanup();
});
graph.dispatch.on('chartClick', function(e) {
console.log('Click Switching to');
if (td === 0) {
d3.select("#test1")
.datum(testdata2)
.call(graph);
td = 1;
} else {
d3.select("#test1")
.datum(testdata)
.call(graph);
td = 0;
}
});
graph.dispatch.on('elementClick', function(e) { console.log("Clicked on Element",e); });
graph.dispatch.on('elementDblClick', function(e) { console.log("Double Clicked on Element",e); });
//graph.dispatch.on('chartClick', function(e) { console.log("Clicked on chart",e); });
window.onresize = function() {
var width = nv.utils.windowSize().width - 40,
height = nv.utils.windowSize().height - 40;
d3.select("#test1")
.attr('width', width)
.attr('height', height)
.call(
graph
.width(width)
.height(height)
)
};
}
});
</script>

@ -13,7 +13,6 @@ body {
<svg id="test1"></svg>
<script src="../lib/d3.v2.js"></script>
<script src="../lib/jquery.min.js"></script>
<script src="../nv.d3.js"></script>
<script src="../src/models/legend.js"></script>
<script src="../src/models/scatter.js"></script>
@ -23,10 +22,10 @@ body {
//Format A
nv.addGraph({
generate: function() {
var width = $(window).width() - 40,
height = $(window).height() - 40;
var width = nv.utils.windowSize().width - 40,
height = nv.utils.windowSize().height - 40;
var chart = nv.models.scatter()
var chart = nv.models.scatter()
.width(width)
.height(height)
.margin({top: 20, right: 20, bottom: 20, left: 20})
@ -42,10 +41,10 @@ nv.addGraph({
return chart;
},
callback: function(graph) {
$(window).resize(function() {
var width = $(window).width() - 40,
height = $(window).height() - 40,
margin = graph.margin();
window.onresize = function() {
var width = nv.utils.windowSize().width - 40,
height = nv.utils.windowSize().height - 40,
margin = graph.margin();
if (width < margin.left + margin.right + 20)
@ -64,7 +63,7 @@ nv.addGraph({
.attr('height', height)
.call(graph);
});
};
}
});

@ -41,9 +41,8 @@ div {
</div>
<script src="../lib/d3.v2.js"></script>
<script src="../lib/jquery.min.js"></script>
<script src="../src/nvtooltip.js"></script>
<script src="../nv.d3.js"></script>
<script src="../src/tooltip.js"></script>
<script src="../src/models/legend.js"></script>
<script src="../src/models/axis.js"></script>
<script src="../src/models/scatter.js"></script>
@ -55,10 +54,10 @@ div {
//Format A
nv.addGraph({
generate: function() {
var width = $(window).width() - 20,
height = $(window).height() - 20;
var width = nv.utils.windowSize().width - 40,
height = nv.utils.windowSize().height - 40;
var chart = nv.models.scatterWithLegend()
var chart = nv.models.scatterWithLegend()
.width(width)
.height(height)
//.width(width)
@ -86,10 +85,10 @@ nv.addGraph({
callback: function(graph) {
graph.dispatch.on('tooltipShow', function(e) {
var offset = $('#test1').offset(),
left = e.pos[0] + offset.left,
top = e.pos[1] + offset.top,
formatter = d3.format(".2f");
var offsetElement = document.getElementById("test1"),
left = e.pos[0] + offsetElement.offsetLeft,
top = e.pos[1] + offsetElement.offsetTop,
formatter = d3.format(".2f");
/*
@ -104,20 +103,22 @@ nv.addGraph({
var contentX = '<strong>' + formatter(e.point.x) + '</strong>';
var contentY = '<strong>' + formatter(e.point.y) + '</strong>';
nvtooltip.show([left, $(window).height() - 30], contentX, 'n', 1);
nvtooltip.show([5, top], contentY, 'w', 1);
var height = nv.utils.windowSize().height - 40;
nv.tooltip.show([left, height - 50], contentX, 'n', 1);
nv.tooltip.show([5, top], contentY, 'w', 1);
});
graph.dispatch.on('tooltipHide', function(e) {
nvtooltip.cleanup();
nv.tooltip.cleanup();
});
$(window).resize(function() {
var width = $(window).width() - 20,
height = $(window).height() - 20,
margin = graph.margin(),
animate = graph.animate();
window.onresize = function() {
var width = nv.utils.windowSize().width - 40,
height = nv.utils.windowSize().height - 40,
margin = graph.margin(),
animate = graph.animate();
if (width < margin.left + margin.right + 20)
@ -136,7 +137,7 @@ nv.addGraph({
.attr('height', height)
.call(graph);
});
};
}
});

@ -18,7 +18,6 @@ text {
<h2>Sparkline: <span id="test1" class="sparkline"></span></h2>
<script src="../lib/d3.v2.js"></script>
<script src="../lib/jquery.min.js"></script>
<script src="../nv.d3.js"></script>
<script src="../src/models/sparkline.js"></script>
<script>
@ -27,8 +26,8 @@ text {
nv.addGraph({
generate: function() {
var chart = nv.models.sparkline()
.width(200)
.height(20)
.width(400)
.height(80)
d3.select("#test1")
.datum(sine())

@ -21,9 +21,8 @@ text {
</div>
<script src="../lib/d3.v2.js"></script>
<script src="../lib/jquery.min.js"></script>
<script src="../nv.d3.js"></script>
<script src="../src/nvtooltip.js"></script>
<script src="../src/tooltip.js"></script>
<script src="../src/models/stackedArea.js"></script>
<script>
@ -43,8 +42,8 @@ nv.addGraph({
});
var width = $(window).width() - 20,
height = $(window).height() - 20;
var width = nv.utils.windowSize().width - 20,
height = nv.utils.windowSize().height - 20;
var chart = nv.models.stackedArea()
.width(width)
@ -64,35 +63,35 @@ nv.addGraph({
},
callback: function(graph) {
/*
graph.dispatch.on('tooltipShow', function(e) {
var offset = $('#chart').offset(),
left = e.pos[0] + offset.left,
top = e.pos[1] + offset.top,
formatterY = d3.format(",.2%"),
var offsetElement = document.getElementById("chart"),
left = e.pos[0] + offsetElement.offsetLeft,
top = e.pos[1] + offsetElement.offsetTop,
formatterY = d3.format(",.2%"),
formatterX = function(d) {
return d3.time.format('%x')(new Date(d))
return d3.time.format('%x')(new Date(d))
};
var content = '<h3>' + e.series.key + '</h3>' +
'<p>' +
formatterY(graph.y()(e.point)) + ' on ' + formatterX(graph.x()(e.point)) +
formatterY(graph.y()(e.point)) + ' at ' + formatterX(graph.x()(e.point)) +
'</p>';
//$('#positionTest').css({'left': left, 'top': top});
nvtooltip.show([left, top], content);
nv.tooltip.show([left, top], content);
});
graph.dispatch.on('tooltipHide', function(e) {
nvtooltip.cleanup();
nv.tooltip.cleanup();
});
*/
$(window).resize(function() {
var width = $(window).width() - 20,
height = $(window).height() - 20,
window.onResize = function() {
var width = nv.utils.windowSize().width - 20,
height = nv.utils.windowSize().height - 20,
margin = graph.margin();
@ -112,7 +111,7 @@ nv.addGraph({
.attr('height', height)
.call(graph);
});
}
}
});

@ -26,10 +26,9 @@ text {
</div>
<script src="../lib/d3.v2.js"></script>
<script src="../lib/jquery.min.js"></script>
<script src="../nv.d3.js"></script>
<script src="../src/nvtooltip.js"></script>
<script src="../src/models/axis.js"></script>
<script src="../src/tooltip.js"></script>
<script src="../src/models/legend.js"></script>
<script src="../src/models/line.js"></script>
<script src="../src/models/stackedArea.js"></script>
@ -68,38 +67,32 @@ svg.transition().duration(500).call(chart);
chart.dispatch.on('tooltipShow', function(e) {
var offset = $('#chart').offset(),
left = e.pos[0] + offset.left,
top = e.pos[1] + offset.top,
formatterY = chart.stacked.offset() == 'expand' ? d3.format(',.2%') : d3.format(',.2f'), //TODO: stacked format should be set by caller
var offsetElement = document.getElementById("chart"),
left = e.pos[0] + offsetElement.offsetLeft,
top = e.pos[1] + offsetElement.offsetTop,
formatterY = chart.stacked.offset() == 'expand' ? d3.format(',.2%') : d3.format(',.2f'), //TODO: stacked format should be set by caller
formatterX = function(d) { return d };
/*
formatterY = d3.format(",.2%"),
formatterX = function(d) {
return d3.time.format('%x')(new Date(d))
};
*/
var content = '<h3>' + e.series.key + '</h3>' +
'<p>' +
formatterY(chart.y()(e.point)) + ' on ' + formatterX(chart.x()(e.point)) +
'</p>';
nvtooltip.show([left, top], content);
nv.tooltip.show([left, top], content);
});
chart.dispatch.on('tooltipHide', function(e) {
nvtooltip.cleanup();
nv.tooltip.cleanup();
});
$(window).resize(function() {
window.onresize = function() {
d3.select('#chart svg')
.attr('width', width())
.attr('height', height())
.call(chart);
});
};

8
lib/d3.v2.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
lib/jquery.min.js vendored

@ -1 +0,0 @@
jquery-1.7.1.min.js

@ -1,100 +1,14 @@
/*****
* A no frills tooltip implementation.
*****/
(function($) {
var nvtooltip = window.nvtooltip = {};
nvtooltip.show = function(pos, content, gravity, dist) {
var container = $('<div class="nvtooltip">');
gravity = gravity || 's';
dist = dist || 20;
container
.html(content)
.css({left: -1000, top: -1000, opacity: 0})
.appendTo('body'); //append the container out of view so we can get measurements
var height = container.height() + parseInt(container.css('padding-top')) + parseInt(container.css('padding-bottom')),
width = container.width() + parseInt(container.css('padding-left')) + parseInt(container.css('padding-right')),
windowWidth = $(window).width(),
windowHeight = $(window).height(),
scrollTop = $('body').scrollTop(),
scrollLeft = $('body').scrollLeft(),
left, top;
switch (gravity) {
case 'e':
left = pos[0] - width - dist;
top = pos[1] - (height / 2);
if (left < scrollLeft) left = pos[0] + dist;
if (top < scrollTop) top = scrollTop + 5;
if (top + height > scrollTop + windowHeight) top = scrollTop - height - 5;
break;
case 'w':
left = pos[0] + dist;
top = pos[1] - (height / 2);
if (left + width > windowWidth) left = pos[0] - width - dist;
if (top < scrollTop) top = scrollTop + 5;
if (top + height > scrollTop + windowHeight) top = scrollTop - height - 5;
break;
case 'n':
left = pos[0] - (width / 2);
top = pos[1] + dist;
if (left < scrollLeft) left = scrollLeft + 5;
if (left + width > windowWidth) left = windowWidth - width - 5;
if (top + height > scrollTop + windowHeight) top = pos[1] - height - dist;
break;
case 's':
left = pos[0] - (width / 2);
top = pos[1] - height - dist;
if (left < scrollLeft) left = scrollLeft + 5;
if (left + width > windowWidth) left = windowWidth - width - 5;
if (scrollTop > top) top = pos[1] + 20;
break;
}
container
.css({
left: left,
top: top,
opacity: 1
});
return container;
};
nvtooltip.cleanup = function() {
var tooltips = $('.nvtooltip');
tooltips.css({
'transition-delay': '0 !important',
'-moz-transition-delay': '0 !important',
'-webkit-transition-delay': '0 !important'
});
tooltips.css('opacity',0);
setTimeout(function() {
tooltips.remove()
}, 500);
};
})(jQuery);
(function(){
var nv = {
version: '0.0.1',
version: '0.0.1a',
dev: true //set false when in production
};
window.nv = nv;
nv.tooltip = {}; // For the tooltip system
nv.utils = {}; // Utility subsystem
nv.models = {}; //stores all the possible models/components
nv.charts = {}; //stores all the ready to use charts
nv.graphs = []; //stores all the graphs currently on the page
@ -103,19 +17,6 @@ nv.log = {}; //stores some statistics and potential error messages
nv.dispatch = d3.dispatch('render_start', 'render_end');
// ********************************************
// Public Helper functions, not part of NV
window.log = function(obj) {
if ((typeof(window.console) === 'object')
&& (typeof(window.console.log) === 'function'))
console.log.apply(console, arguments);
return obj;
};
// ********************************************
// Public Core NV functions
@ -127,7 +28,7 @@ nv.dispatch.on('render_start', function(e) {
nv.dispatch.on('render_end', function(e) {
nv.log.endTime = +new Date;
nv.log.totalTime = nv.log.endTime - nv.log.startTime;
if (nv.dev) log('total', nv.log.totalTime); //used for development, to keep track of graph generation times
if (nv.dev && console.log) console.log('total', nv.log.totalTime); //used for development, to keep track of graph generation times
});
@ -171,7 +72,6 @@ nv.addGraph = function(obj) {
};
nv.identity = function(d) { return d };
@ -180,9 +80,6 @@ nv.strip = function(s) {
}
/* An ugly implementation to get month end axis dates
* Will hopefully refactor sooner than later
*/
@ -228,8 +125,131 @@ d3.time.monthEnds = d3_time_range(d3.time.monthEnd, function(date) {
);
nv.utils.windowSize = function() {
// Sane defaults
var size = {width: 640, height: 480};
// Earlier IE uses Doc.body
if (document.body && document.body.offsetWidth) {
size.width = document.body.offsetWidth;
size.height = document.body.offsetHeight;
}
// IE can use depending on mode it is in
if (document.compatMode=='CSS1Compat' &&
document.documentElement &&
document.documentElement.offsetWidth ) {
size.width = document.documentElement.offsetWidth;
size.height = document.documentElement.offsetHeight;
}
// Most recent browsers use
if (window.innerWidth && window.innerHeight) {
size.width = window.innerWidth;
size.height = window.innerHeight;
}
return (size);
};
/*****
* A no frills tooltip implementation.
*****/
(function() {
var nvtooltip = window.nv.tooltip = {};
nvtooltip.show = function(pos, content, gravity, dist) {
var container = document.createElement("div");
container.className = "nvtooltip";
gravity = gravity || 's';
dist = dist || 20;
var body = document.getElementsByTagName("body")[0];
container.innerHTML = content;
container.style.left = 1;
container.style.top = 1;
container.style.opacity = 0;
body.appendChild(container);
var height = parseInt(container.offsetHeight),
width = parseInt(container.offsetWidth),
windowWidth = nv.utils.windowSize().width,
windowHeight = nv.utils.windowSize().height,
scrollTop = body.scrollTop,
scrollLeft = body.scrollLeft,
left, top;
switch (gravity) {
case 'e':
left = pos[0] - width - dist;
top = pos[1] - (height / 2);
if (left < scrollLeft) left = pos[0] + dist;
if (top < scrollTop) top = scrollTop + 5;
if (top + height > scrollTop + windowHeight) top = scrollTop - height - 5;
break;
case 'w':
left = pos[0] + dist;
top = pos[1] - (height / 2);
if (left + width > windowWidth) left = pos[0] - width - dist;
if (top < scrollTop) top = scrollTop + 5;
if (top + height > scrollTop + windowHeight) top = scrollTop - height - 5;
break;
case 'n':
left = pos[0] - (width / 2);
top = pos[1] + dist;
if (left < scrollLeft) left = scrollLeft + 5;
if (left + width > windowWidth) left = windowWidth - width - 5;
if (top + height > scrollTop + windowHeight) top = pos[1] - height - dist;
break;
case 's':
left = pos[0] - (width / 2);
top = pos[1] - height - dist;
if (left < scrollLeft) left = scrollLeft + 5;
if (left + width > windowWidth) left = windowWidth - width - 5;
if (scrollTop > top) top = pos[1] + 20;
break;
}
container.style.left = left+"px";
container.style.top = top+"px";
container.style.opacity = 1;
return container;
};
nvtooltip.cleanup = function() {
// Find the tooltips, mark them for removal by this class (so others cleanups won't find it)
var tooltips = document.getElementsByClassName('nvtooltip');
var purging = [];
while(tooltips.length) {
purging.push(tooltips[0]);
tooltips[0].style.transitionDelay = "0 !important";
tooltips[0].style.opacity = 0;
tooltips[0].className = "nvtooltip-pending-removal";
}
setTimeout(function() {
while (purging.length) {
var removeMe = purging.pop();
removeMe.parentNode.removeChild(removeMe);
}
}, 500);
};
})();
nv.models.legend = function() {
var margin = {top: 5, right: 0, bottom: 5, left: 10},
width = 400,
@ -448,33 +468,67 @@ nv.models.axis = function() {
}
nv.models.bar = function() {
var margin = {top: 20, right: 10, bottom: 20, left: 60},
var margin = {top: 20, right: 10, bottom: 80, left: 60},
width = 960,
height = 500,
animate = 500;
animate = 500,
label ='label',
rotatedLabel = true,
showLabels = true,
id = Math.floor(Math.random() * 10000), //Create semi-unique ID in case user doesn't select one
color = d3.scale.category20(),
field ='y',
title = '';
var x = d3.scale.ordinal(),
y = d3.scale.linear(),
xAxis = d3.svg.axis().scale(x).orient('bottom').ticks(5),
yAxis = d3.svg.axis().scale(y).orient('left');
xAxis = d3.svg.axis().scale(x).orient('bottom'),
yAxis = d3.svg.axis().scale(y).orient('left'),
dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'tooltipShow', 'tooltipHide');
function chart(selection) {
selection.each(function(data) {
//x .domain(data.map(function(d,i) { return d.label }))
x .domain(["One", "Two", "Three", "Four", "Five"])
x .domain(data.map(function(d,i) { return d[label]; }))
.rangeRoundBands([0, width - margin.left - margin.right], .1);
y .domain([0, d3.max(data, function(d) { return d.y; })])
.range([height - margin.top - margin.bottom, 0]);
var min = d3.min(data, function(d) { return d[field] });
var max = d3.max(data, function(d) { return d[field] });
var x0 = Math.max(-min, max);
var x1 = -x0;
// If we have no negative values, then lets stack this with just positive bars
if (min >= 0) x1 = 0;
y .domain([x1, x0])
.range([height - margin.top - margin.bottom, 0])
.nice();
xAxis.ticks( width / 100 );
yAxis.ticks( height / 36 ).tickSize(-(width - margin.right - margin.left), 0);
yAxis.tickSize(-(width - margin.right - margin.left), 0);
var parent = d3.select(this)
.on("click", function(d,i) {
dispatch.chartClick({
data: d,
index: i,
pos: d3.event,
id: id
});
});
var wrap = parent.selectAll('g.wrap').data([data]);
var gEnter = wrap.enter();
gEnter.append("text")
.attr("class", "title")
.attr("dy", ".91em")
.attr("text-anchor", "start")
.text(title);
gEnter = gEnter.append('g').attr('class', 'wrap').attr('id','wrap-'+id).append('g');
var wrap = d3.select(this).selectAll('g.wrap').data([data]);
var gEnter = wrap.enter().append('g').attr('class', 'wrap').append('g');
gEnter.append('g').attr('class', 'x axis');
gEnter.append('g').attr('class', 'y axis');
@ -489,43 +543,95 @@ nv.models.bar = function() {
var bars = wrap.select('.bars').selectAll('.bar')
.data(function(d) { return d });
bars.exit().remove();
.data(function(d) { return d; });
bars.exit().remove();
var barsEnter = bars.enter().append('svg:rect')
.attr('class', function(d) { return d[field] < 0 ? "bar negative" : "bar positive"})
.attr("fill", function(d, i) { return color(i); })
.attr('x', 0 )
.on('mouseover', function(d,i){
d3.select(this).classed('hover', true);
dispatch.tooltipShow({
label: d[label],
value: d[field],
data: d,
index: i,
// TODO: Calculate the center to the bar
pos: [d3.event.pageX, d3.event.pageY],
id: id
});
var barsEnter = bars.enter().append('g')
.attr('class', 'bar')
.on('mouseover', function(d,i){ d3.select(this).classed('hover', true) })
.on('mouseout', function(d,i){ d3.select(this).classed('hover', false) });
barsEnter.append('rect')
.attr('y', function(d) { return y(0) });
barsEnter.append('text')
.attr('text-anchor', 'middle')
.attr('dy', '-4px');
})
.on('mouseout', function(d,i){
d3.select(this).classed('hover', false);
dispatch.tooltipHide({
label: d[label],
value: d[field],
data: d,
index: i,
id: id
});
})
.on('click', function(d,i) {
dispatch.elementClick({
label: d[label],
value: d[field],
data: d,
index: i,
pos: d3.event,
id: id
});
d3.event.stopPropagation();
})
.on('dblclick', function(d,i) {
dispatch.elementDblClick({
label: d[label],
value: d[field],
data: d,
index: i,
pos: d3.event,
id: id
});
d3.event.stopPropagation();
});
bars
.attr('transform', function(d,i) { return 'translate(' + x(d.label) + ',0)' })
bars.selectAll('rect')
.order()
bars
.attr('class', function(d) { return d[field] < 0 ? "bar negative" : "bar positive"})
.attr('transform', function(d,i) { return 'translate(' + x(d[label]) + ',0)'; })
.attr('width', x.rangeBand )
.transition()
.order()
.transition()
.duration(animate)
.attr('x', 0 )
.attr('y', function(d) { return y(d.y) })
.attr('height', function(d) { return y.range()[0] - y(d.y) });
bars.selectAll('text')
.attr('x', 0 )
.attr('y', function(d) { return y(d.y) })
.attr('dx', x.rangeBand() / 2)
.text(function(d) { return d.y });
.attr('y', function(d) { return y(Math.max(0, d[field])); })
.attr('height', function(d) { return Math.abs(y(d[field]) - y(0)); });
g.select('.x.axis')
.attr('transform', 'translate(0,' + y.range()[0] + ')')
.call(xAxis);
g.select('.y.axis')
if (rotatedLabel) {
g.select('.x.axis').selectAll('text').attr('text-anchor','start').attr("transform", function(d) {
return "rotate(35)translate(" + this.getBBox().height/2 + "," + '0' + ")";
});
}
if (!showLabels) {
g.select('.x.axis').selectAll('text').attr('fill', 'rgba(0,0,0,0)');
g.select('.x.axis').selectAll('line').attr('style', 'opacity: 0');
}
/*else {
g.select('.x.axis').selectAll('text').attr('fill', 'rgba(0,0,0,1)');
g.select('.x.axis').selectAll('line').attr('style', 'opacity: 1');
}*/
g.select('.y.axis')
.call(yAxis);
});
@ -541,7 +647,7 @@ nv.models.bar = function() {
chart.width = function(_) {
if (!arguments.length) return width;
if (margin.left + margin.right + 20 > _)
width = margin.left + margin.right + 20 // Min width
width = margin.left + margin.right + 20; // Min width
else
width = _;
return chart;
@ -550,7 +656,7 @@ nv.models.bar = function() {
chart.height = function(_) {
if (!arguments.length) return height;
if (margin.top + margin.bottom + 20 > _)
height = margin.top + margin.bottom + 20 // Min height
height = margin.top + margin.bottom + 20; // Min height
else
height = _;
return chart;
@ -562,6 +668,42 @@ nv.models.bar = function() {
return chart;
};
chart.labelField = function(_) {
if (!arguments.length) return (label);
label = _;
return chart;
};
chart.dataField = function(_) {
if (!arguments.length) return (field);
field = _;
return chart;
};
chart.id = function(_) {
if (!arguments.length) return id;
id = _;
return chart;
};
chart.rotatedLabel = function(_) {
if (!arguments.length) return rotatedLabel;
rotatedLabel = _;
return chart;
};
chart.showLabels = function(_) {
if (!arguments.length) return (showLabels);
showLabels = _;
return chart;
};
chart.title = function(_) {
if (!arguments.length) return (title);
title = _;
return chart;
};
chart.xaxis = {};
// Expose the x-axis' tickFormat method.
d3.rebind(chart.xaxis, xAxis, 'tickFormat');
@ -570,8 +712,273 @@ nv.models.bar = function() {
// Expose the y-axis' tickFormat method.
d3.rebind(chart.yaxis, yAxis, 'tickFormat');
chart.dispatch = dispatch;
return chart;
}
nv.models.pie = function() {
var margin = {top: 20, right: 20, bottom: 20, left: 20},
width = 500,
height = 500,
animate = 2000,
radius = Math.min(width-(margin.right+margin.left), height-(margin.top+margin.bottom)) / 2,
label ='label',
field ='y',
id = Math.floor(Math.random() * 10000), //Create semi-unique ID in case user doesn't select one
color = d3.scale.category20(),
showLabels = true,
donut = false,
title = '';
var lastWidth = 0,
lastHeight = 0;
var dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'tooltipShow', 'tooltipHide');
function chart(selection) {
selection.each(function(data) {
var svg = d3.select(this)
.on("click", function(d,i) {
dispatch.chartClick({
data: d,
index: i,
pos: d3.event,
id: id
});
});
var background = svg.selectAll('svg.margin').data([data]);
var parent = background.enter();
parent.append("text")
.attr("class", "title")
.attr("dy", ".91em")
.attr("text-anchor", "start")
.text(title);
parent.append('svg')
.attr('class','margin')
.attr('x', margin.left)
.attr('y', margin.top)
.style('overflow','visible');
var wrap = background.selectAll('g.wrap').data([data]);
wrap.exit().remove();
var wEnter = wrap.enter();
wEnter
.append('g')
.attr('class', 'wrap')
.attr('id','wrap-'+id)
.append('g')
.attr('class', 'pie');
wrap
.attr('width', width) //-(margin.left+margin.right))
.attr('height', height) //-(margin.top+margin.bottom))
.attr("transform", "translate(" + radius + "," + radius + ")");
var arc = d3.svg.arc()
.outerRadius((radius-(radius / 5)));
if (donut) arc.innerRadius(radius / 2);
// Setup the Pie chart and choose the data element
var pie = d3.layout.pie()
.value(function (d) { return d[field]; });
var slices = background.select('.pie').selectAll(".slice")
.data(pie);
slices.exit().remove();
var ae = slices.enter().append("svg:g")
.attr("class", "slice")
.on('mouseover', function(d,i){
d3.select(this).classed('hover', true);
dispatch.tooltipShow({
label: d.data[label],
value: d.data[field],
data: d.data,
index: i,
pos: [d3.event.pageX, d3.event.pageY],
id: id
});
})
.on('mouseout', function(d,i){
d3.select(this).classed('hover', false);
dispatch.tooltipHide({
label: d.data[label],
value: d.data[field],
data: d.data,
index: i,
id: id
});
})
.on('click', function(d,i) {
dispatch.elementClick({
label: d.data[label],
value: d.data[field],
data: d.data,
index: i,
pos: d3.event,
id: id
});
d3.event.stopPropagation();
})
.on('dblclick', function(d,i) {
dispatch.elementDblClick({
label: d.data[label],
value: d.data[field],
data: d.data,
index: i,
pos: d3.event,
id: id
});
d3.event.stopPropagation();
});
var paths = ae.append("svg:path")
.attr('class','path')
.attr("fill", function(d, i) { return color(i); });
//.attr('d', arc);
slices.select('.path')
.attr('d', arc)
.transition()
.ease("bounce")
.duration(animate)
.attrTween("d", tweenPie);
if (showLabels) {
// This does the normal label
ae.append("text");
slices.select("text")
.transition()
.duration(animate)
.ease('bounce')
.attr("transform", function(d) {
d.outerRadius = radius + 10; // Set Outer Coordinate
d.innerRadius = radius + 15; // Set Inner Coordinate
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle") //center the text on it's origin
.style("font", "bold 12px Arial")
.text(function(d, i) { return d.data[label]; });
}
// Computes the angle of an arc, converting from radians to degrees.
function angle(d) {
var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
return a > 90 ? a - 180 : a;
}
function tweenPie(b) {
b.innerRadius = 0;
var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
return function(t) {
return arc(i(t));
};
}
});
return chart;
}
chart.margin = function(_) {
if (!arguments.length) return margin;
margin = _;
return chart;
};
chart.width = function(_) {
if (!arguments.length) return width;
if (margin.left + margin.right + 20 > _) {
width = margin.left + margin.right + 20; // Min width
} else {
width = _;
}
radius = Math.min(width-(margin.left+margin.right), height-(margin.top+margin.bottom)) / 2;
return chart;
};
chart.height = function(_) {
if (!arguments.length) return height;
if (margin.top + margin.bottom + 20 > _) {
height = margin.top + margin.bottom + 20; // Min height
} else {
height = _;
}
radius = Math.min(width-(margin.left+margin.right), height-(margin.top+margin.bottom)) / 2;
return chart;
};
chart.animate = function(_) {
if (!arguments.length) return animate;
animate = _;
return chart;
};
chart.labelField = function(_) {
if (!arguments.length) return (label);
label = _;
return chart;
};
chart.dataField = function(_) {
if (!arguments.length) return (field);
field = _;
return chart;
};
chart.showLabels = function(_) {
if (!arguments.length) return (showLabels);
showLabels = _;
return chart;
};
chart.donut = function(_) {
if (!arguments.length) return (donut);
donut = _;
return chart;
};
chart.title = function(_) {
if (!arguments.length) return (title);
title = _;
return chart;
};
chart.id = function(_) {
if (!arguments.length) return id;
id = _;
return chart;
};
chart.dispatch = dispatch;
return chart;
}
//TODO: consider adding axes
// -How to deal with time vs generic linear, vs any other scale?
@ -596,6 +1003,8 @@ nv.models.line = function() {
x0, y0;
function chart(selection) {
selection.each(function(data) {
var seriesData = data.map(function(d) {
@ -2329,7 +2738,8 @@ nv.models.stackedArea = function() {
style = 'stack',
offset = 'zero',
order = 'default',
xDomain, yDomain;
xDomain, yDomain,
dispatch = d3.dispatch('tooltipShow', 'tooltipHide');
/************************************
* offset:
@ -2501,7 +2911,22 @@ nv.models.stackedArea = function() {
return chart;
};
chart.dispatch = lines.dispatch;
chart.dispatch = dispatch;
lines.dispatch.on('pointMouseover.tooltip', function(e) {
dispatch.tooltipShow({
point: e.point,
series: e.series,
pos: [e.pos[0] + margin.left, e.pos[1] + margin.top],
seriesIndex: e.seriesIndex,
pointIndex: e.pointIndex
});
});
lines.dispatch.on('pointMouseout.tooltip', function(e) {
dispatch.tooltipHide(e);
});
return chart;
}
@ -2630,7 +3055,7 @@ nv.models.stackedAreaWithLegend = function() {
});
*/
stacked.dispatch.on('pointMouseover.tooltip', function(e) {
stacked.dispatch.on('tooltipShow', function(e) {
//disable tooltips when value ~= 0
//// TODO: consider removing points from voronoi that have 0 value instead of this hack
if (!Math.round(getY(e.point) * 100)) { // 100 will not be good for very small numbers... will have to think about making this valu dynamic, based on data range
@ -2641,13 +3066,13 @@ nv.models.stackedAreaWithLegend = function() {
dispatch.tooltipShow({
point: e.point,
series: e.series,
pos: [e.pos[0] + margin.left, e.pos[1] + margin.top],
pos: [e.pos[0] + margin.left, e.pos[1] + margin.top],
seriesIndex: e.seriesIndex,
pointIndex: e.pointIndex
});
});
stacked.dispatch.on('pointMouseout.tooltip', function(e) {
stacked.dispatch.on('tooltipHide', function(e) {
dispatch.tooltipHide(e);
});
@ -2767,16 +3192,16 @@ nv.charts.line = function() {
var graph = nv.models.lineWithLegend(),
showTooltip = function(e) {
var offset = $(selector).offset(),
left = e.pos[0] + offset.left,
top = e.pos[1] + offset.top,
var offsetElement = document.getElementById(selector.substr(1)),
left = e.pos[0] + offsetElement.offsetLeft,
top = e.pos[1] + offsetElement.offsetTop,
formatX = graph.xAxis.tickFormat(),
formatY = graph.yAxis.tickFormat(),
x = formatX(graph.x()(e.point)),
y = formatY(graph.y()(e.point)),
content = tooltip(e.series.key, x, y, e, graph);
nvtooltip.show([left, top], content);
nv.tooltip.show([left, top], content);
};
//setting component defaults
@ -2823,16 +3248,17 @@ nv.charts.line = function() {
},
callback: function(graph) {
graph.dispatch.on('tooltipShow', showTooltip);
graph.dispatch.on('tooltipHide', nvtooltip.cleanup);
graph.dispatch.on('tooltipHide', nv.tooltip.cleanup);
//TODO: create resize queue and have nv core handle resize instead of binding all to window resize
$(window).resize(function() {
window.onResize =
function() {
// now that width and height are functions, should be automatic..of course you can always override them
d3.select(selector + ' svg')
.attr('width', graph.width()()) //need to set SVG dimensions, chart is not aware of the SVG component
.attr('height', graph.height()())
.call(graph);
});
};
}
});
@ -3242,4 +3668,4 @@ nv.charts.cumulativeLineChartDaily = function() {
return chart;
};
})();
})();

6
nv.d3.min.js vendored

File diff suppressed because one or more lines are too long

@ -15,16 +15,16 @@ nv.charts.line = function() {
var graph = nv.models.lineWithLegend(),
showTooltip = function(e) {
var offset = $(selector).offset(),
left = e.pos[0] + offset.left,
top = e.pos[1] + offset.top,
var offsetElement = document.getElementById(selector.substr(1)),
left = e.pos[0] + offsetElement.offsetLeft,
top = e.pos[1] + offsetElement.offsetTop,
formatX = graph.xAxis.tickFormat(),
formatY = graph.yAxis.tickFormat(),
x = formatX(graph.x()(e.point)),
y = formatY(graph.y()(e.point)),
content = tooltip(e.series.key, x, y, e, graph);
nvtooltip.show([left, top], content);
nv.tooltip.show([left, top], content);
};
//setting component defaults
@ -71,16 +71,17 @@ nv.charts.line = function() {
},
callback: function(graph) {
graph.dispatch.on('tooltipShow', showTooltip);
graph.dispatch.on('tooltipHide', nvtooltip.cleanup);
graph.dispatch.on('tooltipHide', nv.tooltip.cleanup);
//TODO: create resize queue and have nv core handle resize instead of binding all to window resize
$(window).resize(function() {
window.onResize =
function() {
// now that width and height are functions, should be automatic..of course you can always override them
d3.select(selector + ' svg')
.attr('width', graph.width()()) //need to set SVG dimensions, chart is not aware of the SVG component
.attr('height', graph.height()())
.call(graph);
});
};
}
});

@ -1,11 +1,13 @@
var nv = {
version: '0.0.1',
version: '0.0.1a',
dev: true //set false when in production
};
window.nv = nv;
nv.tooltip = {}; // For the tooltip system
nv.utils = {}; // Utility subsystem
nv.models = {}; //stores all the possible models/components
nv.charts = {}; //stores all the ready to use charts
nv.graphs = []; //stores all the graphs currently on the page
@ -14,19 +16,6 @@ nv.log = {}; //stores some statistics and potential error messages
nv.dispatch = d3.dispatch('render_start', 'render_end');
// ********************************************
// Public Helper functions, not part of NV
window.log = function(obj) {
if ((typeof(window.console) === 'object')
&& (typeof(window.console.log) === 'function'))
console.log.apply(console, arguments);
return obj;
};
// ********************************************
// Public Core NV functions
@ -38,7 +27,7 @@ nv.dispatch.on('render_start', function(e) {
nv.dispatch.on('render_end', function(e) {
nv.log.endTime = +new Date;
nv.log.totalTime = nv.log.endTime - nv.log.startTime;
if (nv.dev) log('total', nv.log.totalTime); //used for development, to keep track of graph generation times
if (nv.dev && console.log) console.log('total', nv.log.totalTime); //used for development, to keep track of graph generation times
});
@ -82,7 +71,6 @@ nv.addGraph = function(obj) {
};
nv.identity = function(d) { return d };
@ -91,9 +79,6 @@ nv.strip = function(s) {
}
/* An ugly implementation to get month end axis dates
* Will hopefully refactor sooner than later
*/
@ -139,4 +124,29 @@ d3.time.monthEnds = d3_time_range(d3.time.monthEnd, function(date) {
);
nv.utils.windowSize = function() {
// Sane defaults
var size = {width: 640, height: 480};
// Earlier IE uses Doc.body
if (document.body && document.body.offsetWidth) {
size.width = document.body.offsetWidth;
size.height = document.body.offsetHeight;
}
// IE can use depending on mode it is in
if (document.compatMode=='CSS1Compat' &&
document.documentElement &&
document.documentElement.offsetWidth ) {
size.width = document.documentElement.offsetWidth;
size.height = document.documentElement.offsetHeight;
}
// Most recent browsers use
if (window.innerWidth && window.innerHeight) {
size.width = window.innerWidth;
size.height = window.innerHeight;
}
return (size);
};

@ -11,6 +11,7 @@
}
/********************
* TOOLTIP CSS
*/
@ -20,6 +21,7 @@
background-color: rgba(255,255,255,1);
padding: 10px;
border: 1px solid #ddd;
z-index: 10000;
font-family: Arial;
font-size: 13px;
@ -77,7 +79,9 @@ text {
font: 12px sans-serif;
}
svg .title {
font: bold 14px Arial;
}
/**********
* Brush
@ -137,8 +141,13 @@ text {
* Bars
*/
.bars .negative rect {
zfill: brown;
cursor: pointer;
}
.bars rect {
fill: steelblue;
zfill: steelblue;
cursor: pointer;
}
@ -154,7 +163,16 @@ text {
fill: rgba(0,0,0,1);
}
.x.axis text {
transform: rotate(90);
}
/***********
* Pie Chart
*/
.pie .hover path {
fill: lightblue;
}
/**********
* Lines

@ -1,32 +1,66 @@
nv.models.bar = function() {
var margin = {top: 20, right: 10, bottom: 20, left: 60},
var margin = {top: 20, right: 10, bottom: 80, left: 60},
width = 960,
height = 500,
animate = 500;
animate = 500,
label ='label',
rotatedLabel = true,
showLabels = true,
id = Math.floor(Math.random() * 10000), //Create semi-unique ID in case user doesn't select one
color = d3.scale.category20(),
field ='y',
title = '';
var x = d3.scale.ordinal(),
y = d3.scale.linear(),
xAxis = d3.svg.axis().scale(x).orient('bottom').ticks(5),
yAxis = d3.svg.axis().scale(y).orient('left');
xAxis = d3.svg.axis().scale(x).orient('bottom'),
yAxis = d3.svg.axis().scale(y).orient('left'),
dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'tooltipShow', 'tooltipHide');
function chart(selection) {
selection.each(function(data) {
//x .domain(data.map(function(d,i) { return d.label }))
x .domain(["One", "Two", "Three", "Four", "Five"])
x .domain(data.map(function(d,i) { return d[label]; }))
.rangeRoundBands([0, width - margin.left - margin.right], .1);
y .domain([0, d3.max(data, function(d) { return d.y; })])
.range([height - margin.top - margin.bottom, 0]);
var min = d3.min(data, function(d) { return d[field] });
var max = d3.max(data, function(d) { return d[field] });
var x0 = Math.max(-min, max);
var x1 = -x0;
// If we have no negative values, then lets stack this with just positive bars
if (min >= 0) x1 = 0;
y .domain([x1, x0])
.range([height - margin.top - margin.bottom, 0])
.nice();
xAxis.ticks( width / 100 );
yAxis.ticks( height / 36 ).tickSize(-(width - margin.right - margin.left), 0);
yAxis.tickSize(-(width - margin.right - margin.left), 0);
var parent = d3.select(this)
.on("click", function(d,i) {
dispatch.chartClick({
data: d,
index: i,
pos: d3.event,
id: id
});
});
var wrap = parent.selectAll('g.wrap').data([data]);
var gEnter = wrap.enter();
gEnter.append("text")
.attr("class", "title")
.attr("dy", ".91em")
.attr("text-anchor", "start")
.text(title);
gEnter = gEnter.append('g').attr('class', 'wrap').attr('id','wrap-'+id).append('g');
var wrap = d3.select(this).selectAll('g.wrap').data([data]);
var gEnter = wrap.enter().append('g').attr('class', 'wrap').append('g');
gEnter.append('g').attr('class', 'x axis');
gEnter.append('g').attr('class', 'y axis');
@ -41,43 +75,95 @@ nv.models.bar = function() {
var bars = wrap.select('.bars').selectAll('.bar')
.data(function(d) { return d });
bars.exit().remove();
.data(function(d) { return d; });
bars.exit().remove();
var barsEnter = bars.enter().append('g')
.attr('class', 'bar')
.on('mouseover', function(d,i){ d3.select(this).classed('hover', true) })
.on('mouseout', function(d,i){ d3.select(this).classed('hover', false) });
barsEnter.append('rect')
.attr('y', function(d) { return y(0) });
barsEnter.append('text')
.attr('text-anchor', 'middle')
.attr('dy', '-4px');
bars
.attr('transform', function(d,i) { return 'translate(' + x(d.label) + ',0)' })
bars.selectAll('rect')
.order()
var barsEnter = bars.enter().append('svg:rect')
.attr('class', function(d) { return d[field] < 0 ? "bar negative" : "bar positive"})
.attr("fill", function(d, i) { return color(i); })
.attr('x', 0 )
.on('mouseover', function(d,i){
d3.select(this).classed('hover', true);
dispatch.tooltipShow({
label: d[label],
value: d[field],
data: d,
index: i,
// TODO: Calculate the center to the bar
pos: [d3.event.pageX, d3.event.pageY],
id: id
});
})
.on('mouseout', function(d,i){
d3.select(this).classed('hover', false);
dispatch.tooltipHide({
label: d[label],
value: d[field],
data: d,
index: i,
id: id
});
})
.on('click', function(d,i) {
dispatch.elementClick({
label: d[label],
value: d[field],
data: d,
index: i,
pos: d3.event,
id: id
});
d3.event.stopPropagation();
})
.on('dblclick', function(d,i) {
dispatch.elementDblClick({
label: d[label],
value: d[field],
data: d,
index: i,
pos: d3.event,
id: id
});
d3.event.stopPropagation();
});
bars
.attr('class', function(d) { return d[field] < 0 ? "bar negative" : "bar positive"})
.attr('transform', function(d,i) { return 'translate(' + x(d[label]) + ',0)'; })
.attr('width', x.rangeBand )
.transition()
.order()
.transition()
.duration(animate)
.attr('x', 0 )
.attr('y', function(d) { return y(d.y) })
.attr('height', function(d) { return y.range()[0] - y(d.y) });
bars.selectAll('text')
.attr('x', 0 )
.attr('y', function(d) { return y(d.y) })
.attr('dx', x.rangeBand() / 2)
.text(function(d) { return d.y });
.attr('y', function(d) { return y(Math.max(0, d[field])); })
.attr('height', function(d) { return Math.abs(y(d[field]) - y(0)); });
g.select('.x.axis')
.attr('transform', 'translate(0,' + y.range()[0] + ')')
.call(xAxis);
g.select('.y.axis')
if (rotatedLabel) {
g.select('.x.axis').selectAll('text').attr('text-anchor','start').attr("transform", function(d) {
return "rotate(35)translate(" + this.getBBox().height/2 + "," + '0' + ")";
});
}
if (!showLabels) {
g.select('.x.axis').selectAll('text').attr('fill', 'rgba(0,0,0,0)');
g.select('.x.axis').selectAll('line').attr('style', 'opacity: 0');
}
/*else {
g.select('.x.axis').selectAll('text').attr('fill', 'rgba(0,0,0,1)');
g.select('.x.axis').selectAll('line').attr('style', 'opacity: 1');
}*/
g.select('.y.axis')
.call(yAxis);
});
@ -93,7 +179,7 @@ nv.models.bar = function() {
chart.width = function(_) {
if (!arguments.length) return width;
if (margin.left + margin.right + 20 > _)
width = margin.left + margin.right + 20 // Min width
width = margin.left + margin.right + 20; // Min width
else
width = _;
return chart;
@ -102,7 +188,7 @@ nv.models.bar = function() {
chart.height = function(_) {
if (!arguments.length) return height;
if (margin.top + margin.bottom + 20 > _)
height = margin.top + margin.bottom + 20 // Min height
height = margin.top + margin.bottom + 20; // Min height
else
height = _;
return chart;
@ -114,6 +200,42 @@ nv.models.bar = function() {
return chart;
};
chart.labelField = function(_) {
if (!arguments.length) return (label);
label = _;
return chart;
};
chart.dataField = function(_) {
if (!arguments.length) return (field);
field = _;
return chart;
};
chart.id = function(_) {
if (!arguments.length) return id;
id = _;
return chart;
};
chart.rotatedLabel = function(_) {
if (!arguments.length) return rotatedLabel;
rotatedLabel = _;
return chart;
};
chart.showLabels = function(_) {
if (!arguments.length) return (showLabels);
showLabels = _;
return chart;
};
chart.title = function(_) {
if (!arguments.length) return (title);
title = _;
return chart;
};
chart.xaxis = {};
// Expose the x-axis' tickFormat method.
d3.rebind(chart.xaxis, xAxis, 'tickFormat');
@ -122,5 +244,7 @@ nv.models.bar = function() {
// Expose the y-axis' tickFormat method.
d3.rebind(chart.yaxis, yAxis, 'tickFormat');
chart.dispatch = dispatch;
return chart;
}

@ -22,6 +22,8 @@ nv.models.line = function() {
x0, y0;
function chart(selection) {
selection.each(function(data) {
var seriesData = data.map(function(d) {

@ -0,0 +1,263 @@
nv.models.pie = function() {
var margin = {top: 20, right: 20, bottom: 20, left: 20},
width = 500,
height = 500,
animate = 2000,
radius = Math.min(width-(margin.right+margin.left), height-(margin.top+margin.bottom)) / 2,
label ='label',
field ='y',
id = Math.floor(Math.random() * 10000), //Create semi-unique ID in case user doesn't select one
color = d3.scale.category20(),
showLabels = true,
donut = false,
title = '';
var lastWidth = 0,
lastHeight = 0;
var dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'tooltipShow', 'tooltipHide');
function chart(selection) {
selection.each(function(data) {
var svg = d3.select(this)
.on("click", function(d,i) {
dispatch.chartClick({
data: d,
index: i,
pos: d3.event,
id: id
});
});
var background = svg.selectAll('svg.margin').data([data]);
var parent = background.enter();
parent.append("text")
.attr("class", "title")
.attr("dy", ".91em")
.attr("text-anchor", "start")
.text(title);
parent.append('svg')
.attr('class','margin')
.attr('x', margin.left)
.attr('y', margin.top)
.style('overflow','visible');
var wrap = background.selectAll('g.wrap').data([data]);
wrap.exit().remove();
var wEnter = wrap.enter();
wEnter
.append('g')
.attr('class', 'wrap')
.attr('id','wrap-'+id)
.append('g')
.attr('class', 'pie');
wrap
.attr('width', width) //-(margin.left+margin.right))
.attr('height', height) //-(margin.top+margin.bottom))
.attr("transform", "translate(" + radius + "," + radius + ")");
var arc = d3.svg.arc()
.outerRadius((radius-(radius / 5)));
if (donut) arc.innerRadius(radius / 2);
// Setup the Pie chart and choose the data element
var pie = d3.layout.pie()
.value(function (d) { return d[field]; });
var slices = background.select('.pie').selectAll(".slice")
.data(pie);
slices.exit().remove();
var ae = slices.enter().append("svg:g")
.attr("class", "slice")
.on('mouseover', function(d,i){
d3.select(this).classed('hover', true);
dispatch.tooltipShow({
label: d.data[label],
value: d.data[field],
data: d.data,
index: i,
pos: [d3.event.pageX, d3.event.pageY],
id: id
});
})
.on('mouseout', function(d,i){
d3.select(this).classed('hover', false);
dispatch.tooltipHide({
label: d.data[label],
value: d.data[field],
data: d.data,
index: i,
id: id
});
})
.on('click', function(d,i) {
dispatch.elementClick({
label: d.data[label],
value: d.data[field],
data: d.data,
index: i,
pos: d3.event,
id: id
});
d3.event.stopPropagation();
})
.on('dblclick', function(d,i) {
dispatch.elementDblClick({
label: d.data[label],
value: d.data[field],
data: d.data,
index: i,
pos: d3.event,
id: id
});
d3.event.stopPropagation();
});
var paths = ae.append("svg:path")
.attr('class','path')
.attr("fill", function(d, i) { return color(i); });
//.attr('d', arc);
slices.select('.path')
.attr('d', arc)
.transition()
.ease("bounce")
.duration(animate)
.attrTween("d", tweenPie);
if (showLabels) {
// This does the normal label
ae.append("text");
slices.select("text")
.transition()
.duration(animate)
.ease('bounce')
.attr("transform", function(d) {
d.outerRadius = radius + 10; // Set Outer Coordinate
d.innerRadius = radius + 15; // Set Inner Coordinate
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle") //center the text on it's origin
.style("font", "bold 12px Arial")
.text(function(d, i) { return d.data[label]; });
}
// Computes the angle of an arc, converting from radians to degrees.
function angle(d) {
var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
return a > 90 ? a - 180 : a;
}
function tweenPie(b) {
b.innerRadius = 0;
var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
return function(t) {
return arc(i(t));
};
}
});
return chart;
}
chart.margin = function(_) {
if (!arguments.length) return margin;
margin = _;
return chart;
};
chart.width = function(_) {
if (!arguments.length) return width;
if (margin.left + margin.right + 20 > _) {
width = margin.left + margin.right + 20; // Min width
} else {
width = _;
}
radius = Math.min(width-(margin.left+margin.right), height-(margin.top+margin.bottom)) / 2;
return chart;
};
chart.height = function(_) {
if (!arguments.length) return height;
if (margin.top + margin.bottom + 20 > _) {
height = margin.top + margin.bottom + 20; // Min height
} else {
height = _;
}
radius = Math.min(width-(margin.left+margin.right), height-(margin.top+margin.bottom)) / 2;
return chart;
};
chart.animate = function(_) {
if (!arguments.length) return animate;
animate = _;
return chart;
};
chart.labelField = function(_) {
if (!arguments.length) return (label);
label = _;
return chart;
};
chart.dataField = function(_) {
if (!arguments.length) return (field);
field = _;
return chart;
};
chart.showLabels = function(_) {
if (!arguments.length) return (showLabels);
showLabels = _;
return chart;
};
chart.donut = function(_) {
if (!arguments.length) return (donut);
donut = _;
return chart;
};
chart.title = function(_) {
if (!arguments.length) return (title);
title = _;
return chart;
};
chart.id = function(_) {
if (!arguments.length) return id;
id = _;
return chart;
};
chart.dispatch = dispatch;
return chart;
}

@ -9,7 +9,8 @@ nv.models.stackedArea = function() {
style = 'stack',
offset = 'zero',
order = 'default',
xDomain, yDomain;
xDomain, yDomain,
dispatch = d3.dispatch('tooltipShow', 'tooltipHide');
/************************************
* offset:
@ -181,7 +182,22 @@ nv.models.stackedArea = function() {
return chart;
};
chart.dispatch = lines.dispatch;
chart.dispatch = dispatch;
lines.dispatch.on('pointMouseover.tooltip', function(e) {
dispatch.tooltipShow({
point: e.point,
series: e.series,
pos: [e.pos[0] + margin.left, e.pos[1] + margin.top],
seriesIndex: e.seriesIndex,
pointIndex: e.pointIndex
});
});
lines.dispatch.on('pointMouseout.tooltip', function(e) {
dispatch.tooltipHide(e);
});
return chart;
}

@ -123,7 +123,7 @@ nv.models.stackedAreaWithLegend = function() {
});
*/
stacked.dispatch.on('pointMouseover.tooltip', function(e) {
stacked.dispatch.on('tooltipShow', function(e) {
//disable tooltips when value ~= 0
//// TODO: consider removing points from voronoi that have 0 value instead of this hack
if (!Math.round(getY(e.point) * 100)) { // 100 will not be good for very small numbers... will have to think about making this valu dynamic, based on data range
@ -134,13 +134,13 @@ nv.models.stackedAreaWithLegend = function() {
dispatch.tooltipShow({
point: e.point,
series: e.series,
pos: [e.pos[0] + margin.left, e.pos[1] + margin.top],
pos: [e.pos[0] + margin.left, e.pos[1] + margin.top],
seriesIndex: e.seriesIndex,
pointIndex: e.pointIndex
});
});
stacked.dispatch.on('pointMouseout.tooltip', function(e) {
stacked.dispatch.on('tooltipHide', function(e) {
dispatch.tooltipHide(e);
});

@ -1 +1 @@
})();
})();

@ -3,27 +3,33 @@
* A no frills tooltip implementation.
*****/
(function($) {
var nvtooltip = window.nvtooltip = {};
(function() {
var nvtooltip = window.nv.tooltip = {};
nvtooltip.show = function(pos, content, gravity, dist) {
var container = $('<div class="nvtooltip">');
var container = document.createElement("div");
container.className = "nvtooltip";
gravity = gravity || 's';
dist = dist || 20;
container
.html(content)
.css({left: -1000, top: -1000, opacity: 0})
.appendTo('body'); //append the container out of view so we can get measurements
var height = container.height() + parseInt(container.css('padding-top')) + parseInt(container.css('padding-bottom')),
width = container.width() + parseInt(container.css('padding-left')) + parseInt(container.css('padding-right')),
windowWidth = $(window).width(),
windowHeight = $(window).height(),
scrollTop = $('body').scrollTop(),
scrollLeft = $('body').scrollLeft(),
var body = document.getElementsByTagName("body")[0];
container.innerHTML = content;
container.style.left = 1;
container.style.top = 1;
container.style.opacity = 0;
body.appendChild(container);
var height = parseInt(container.offsetHeight),
width = parseInt(container.offsetWidth),
windowWidth = nv.utils.windowSize().width,
windowHeight = nv.utils.windowSize().height,
scrollTop = body.scrollTop,
scrollLeft = body.scrollLeft,
left, top;
@ -59,30 +65,34 @@
}
container
.css({
left: left,
top: top,
opacity: 1
});
container.style.left = left+"px";
container.style.top = top+"px";
container.style.opacity = 1;
return container;
};
nvtooltip.cleanup = function() {
var tooltips = $('.nvtooltip');
tooltips.css({
'transition-delay': '0 !important',
'-moz-transition-delay': '0 !important',
'-webkit-transition-delay': '0 !important'
});
// Find the tooltips, mark them for removal by this class (so others cleanups won't find it)
var tooltips = document.getElementsByClassName('nvtooltip');
var purging = [];
while(tooltips.length) {
purging.push(tooltips[0]);
tooltips[0].style.transitionDelay = "0 !important";
tooltips[0].style.opacity = 0;
tooltips[0].className = "nvtooltip-pending-removal";
}
tooltips.css('opacity',0);
setTimeout(function() {
setTimeout(function() {
tooltips.remove()
while (purging.length) {
var removeMe = purging.pop();
removeMe.parentNode.removeChild(removeMe);
}
}, 500);
};
})(jQuery);
})();
Loading…
Cancel
Save