You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by de...@apache.org on 2014/03/25 20:19:26 UTC
[1/6] Updating d3 to v3.4.3 and nv.d3 to v1.1.15
Repository: couchdb
Updated Branches:
refs/heads/master 0fb5aa9e6 -> 7296e53c8
http://git-wip-us.apache.org/repos/asf/couchdb/blob/95d6d6b0/src/fauxton/assets/js/libs/nv.d3.js
----------------------------------------------------------------------
diff --git a/src/fauxton/assets/js/libs/nv.d3.js b/src/fauxton/assets/js/libs/nv.d3.js
index 936b406..4ddf400 100755
--- a/src/fauxton/assets/js/libs/nv.d3.js
+++ b/src/fauxton/assets/js/libs/nv.d3.js
@@ -2,14 +2,15 @@
var nv = window.nv || {};
-nv.version = '0.0.1a';
+
+nv.version = '1.1.15b';
nv.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.tooltip = nv.tooltip || {}; // For the tooltip system
+nv.utils = nv.utils || {}; // Utility subsystem
+nv.models = 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
nv.logs = {}; //stores some statistics and potential error messages
@@ -35,10 +36,13 @@ if (nv.dev) {
// Public Core NV functions
// Logs all arguments, and returns the last so you can test things in place
+// Note: in IE8 console.log is an object not a function, and if modernizr is used
+// then calling Function.prototype.bind with with anything other than a function
+// causes a TypeError to be thrown.
nv.log = function() {
if (nv.dev && console.log && console.log.apply)
console.log.apply(console, arguments)
- else if (nv.dev && console.log && Function.prototype.bind) {
+ else if (nv.dev && typeof console.log == "function" && Function.prototype.bind) {
var log = Function.prototype.bind.call(console.log, console);
log.apply(console, arguments);
}
@@ -64,7 +68,10 @@ nv.render = function render(step) {
nv.render.queue.splice(0, i);
if (nv.render.queue.length) setTimeout(arguments.callee, 0);
- else { nv.render.active = false; nv.dispatch.render_end(); }
+ else {
+ nv.dispatch.render_end();
+ nv.render.active = false;
+ }
}, 0);
};
@@ -117,137 +124,744 @@ d3.time.monthEnds = d3_time_range(d3.time.monthEnd, function(date) {
}
);
+/* Utility class to handle creation of an interactive layer.
+This places a rectangle on top of the chart. When you mouse move over it, it sends a dispatch
+containing the X-coordinate. It can also render a vertical line where the mouse is located.
+
+dispatch.elementMousemove is the important event to latch onto. It is fired whenever the mouse moves over
+the rectangle. The dispatch is given one object which contains the mouseX/Y location.
+It also has 'pointXValue', which is the conversion of mouseX to the x-axis scale.
+*/
+nv.interactiveGuideline = function() {
+ "use strict";
+ var tooltip = nv.models.tooltip();
+ //Public settings
+ var width = null
+ , height = null
+ //Please pass in the bounding chart's top and left margins
+ //This is important for calculating the correct mouseX/Y positions.
+ , margin = {left: 0, top: 0}
+ , xScale = d3.scale.linear()
+ , yScale = d3.scale.linear()
+ , dispatch = d3.dispatch('elementMousemove', 'elementMouseout','elementDblclick')
+ , showGuideLine = true
+ , svgContainer = null
+ //Must pass in the bounding chart's <svg> container.
+ //The mousemove event is attached to this container.
+ ;
+
+ //Private variables
+ var isMSIE = navigator.userAgent.indexOf("MSIE") !== -1 //Check user-agent for Microsoft Internet Explorer.
+ ;
+
+
+ function layer(selection) {
+ selection.each(function(data) {
+ var container = d3.select(this);
+
+ var availableWidth = (width || 960), availableHeight = (height || 400);
+
+ var wrap = container.selectAll("g.nv-wrap.nv-interactiveLineLayer").data([data]);
+ var wrapEnter = wrap.enter()
+ .append("g").attr("class", " nv-wrap nv-interactiveLineLayer");
+
+
+ wrapEnter.append("g").attr("class","nv-interactiveGuideLine");
+
+ if (!svgContainer) {
+ return;
+ }
+
+ function mouseHandler() {
+ var d3mouse = d3.mouse(this);
+ var mouseX = d3mouse[0];
+ var mouseY = d3mouse[1];
+ var subtractMargin = true;
+ var mouseOutAnyReason = false;
+ if (isMSIE) {
+ /*
+ D3.js (or maybe SVG.getScreenCTM) has a nasty bug in Internet Explorer 10.
+ d3.mouse() returns incorrect X,Y mouse coordinates when mouse moving
+ over a rect in IE 10.
+ However, d3.event.offsetX/Y also returns the mouse coordinates
+ relative to the triggering <rect>. So we use offsetX/Y on IE.
+ */
+ mouseX = d3.event.offsetX;
+ mouseY = d3.event.offsetY;
+
+ /*
+ On IE, if you attach a mouse event listener to the <svg> container,
+ it will actually trigger it for all the child elements (like <path>, <circle>, etc).
+ When this happens on IE, the offsetX/Y is set to where ever the child element
+ is located.
+ As a result, we do NOT need to subtract margins to figure out the mouse X/Y
+ position under this scenario. Removing the line below *will* cause
+ the interactive layer to not work right on IE.
+ */
+ if(d3.event.target.tagName !== "svg")
+ subtractMargin = false;
+
+ if (d3.event.target.className.baseVal.match("nv-legend"))
+ mouseOutAnyReason = true;
+
+ }
+
+ if(subtractMargin) {
+ mouseX -= margin.left;
+ mouseY -= margin.top;
+ }
+
+ /* If mouseX/Y is outside of the chart's bounds,
+ trigger a mouseOut event.
+ */
+ if (mouseX < 0 || mouseY < 0
+ || mouseX > availableWidth || mouseY > availableHeight
+ || (d3.event.relatedTarget && d3.event.relatedTarget.ownerSVGElement === undefined)
+ || mouseOutAnyReason
+ )
+ {
+ if (isMSIE) {
+ if (d3.event.relatedTarget
+ && d3.event.relatedTarget.ownerSVGElement === undefined
+ && d3.event.relatedTarget.className.match(tooltip.nvPointerEventsClass)) {
+ return;
+ }
+ }
+ dispatch.elementMouseout({
+ mouseX: mouseX,
+ mouseY: mouseY
+ });
+ layer.renderGuideLine(null); //hide the guideline
+ return;
+ }
+
+ var pointXValue = xScale.invert(mouseX);
+ dispatch.elementMousemove({
+ mouseX: mouseX,
+ mouseY: mouseY,
+ pointXValue: pointXValue
+ });
+
+ //If user double clicks the layer, fire a elementDblclick dispatch.
+ if (d3.event.type === "dblclick") {
+ dispatch.elementDblclick({
+ mouseX: mouseX,
+ mouseY: mouseY,
+ pointXValue: pointXValue
+ });
+ }
+ }
+
+ svgContainer
+ .on("mousemove",mouseHandler, true)
+ .on("mouseout" ,mouseHandler,true)
+ .on("dblclick" ,mouseHandler)
+ ;
+
+ //Draws a vertical guideline at the given X postion.
+ layer.renderGuideLine = function(x) {
+ if (!showGuideLine) return;
+ var line = wrap.select(".nv-interactiveGuideLine")
+ .selectAll("line")
+ .data((x != null) ? [nv.utils.NaNtoZero(x)] : [], String);
+
+ line.enter()
+ .append("line")
+ .attr("class", "nv-guideline")
+ .attr("x1", function(d) { return d;})
+ .attr("x2", function(d) { return d;})
+ .attr("y1", availableHeight)
+ .attr("y2",0)
+ ;
+ line.exit().remove();
+
+ }
+ });
+ }
+
+ layer.dispatch = dispatch;
+ layer.tooltip = tooltip;
+
+ layer.margin = function(_) {
+ if (!arguments.length) return margin;
+ margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
+ margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
+ return layer;
+ };
+
+ layer.width = function(_) {
+ if (!arguments.length) return width;
+ width = _;
+ return layer;
+ };
+
+ layer.height = function(_) {
+ if (!arguments.length) return height;
+ height = _;
+ return layer;
+ };
+
+ layer.xScale = function(_) {
+ if (!arguments.length) return xScale;
+ xScale = _;
+ return layer;
+ };
+
+ layer.showGuideLine = function(_) {
+ if (!arguments.length) return showGuideLine;
+ showGuideLine = _;
+ return layer;
+ };
+
+ layer.svgContainer = function(_) {
+ if (!arguments.length) return svgContainer;
+ svgContainer = _;
+ return layer;
+ };
+
+
+ return layer;
+};
+
+/* Utility class that uses d3.bisect to find the index in a given array, where a search value can be inserted.
+This is different from normal bisectLeft; this function finds the nearest index to insert the search value.
+
+For instance, lets say your array is [1,2,3,5,10,30], and you search for 28.
+Normal d3.bisectLeft will return 4, because 28 is inserted after the number 10. But interactiveBisect will return 5
+because 28 is closer to 30 than 10.
+
+Unit tests can be found in: interactiveBisectTest.html
+
+Has the following known issues:
+ * Will not work if the data points move backwards (ie, 10,9,8,7, etc) or if the data points are in random order.
+ * Won't work if there are duplicate x coordinate values.
+*/
+nv.interactiveBisect = function (values, searchVal, xAccessor) {
+ "use strict";
+ if (! values instanceof Array) return null;
+ if (typeof xAccessor !== 'function') xAccessor = function(d,i) { return d.x;}
+
+ var bisect = d3.bisector(xAccessor).left;
+ var index = d3.max([0, bisect(values,searchVal) - 1]);
+ var currentValue = xAccessor(values[index], index);
+ if (typeof currentValue === 'undefined') currentValue = index;
+
+ if (currentValue === searchVal) return index; //found exact match
-/*****
- * A no-frills tooltip implementation.
- *****/
+ var nextIndex = d3.min([index+1, values.length - 1]);
+ var nextValue = xAccessor(values[nextIndex], nextIndex);
+ if (typeof nextValue === 'undefined') nextValue = nextIndex;
+ if (Math.abs(nextValue - searchVal) >= Math.abs(currentValue - searchVal))
+ return index;
+ else
+ return nextIndex
+};
+
+/*
+Returns the index in the array "values" that is closest to searchVal.
+Only returns an index if searchVal is within some "threshold".
+Otherwise, returns null.
+*/
+nv.nearestValueIndex = function (values, searchVal, threshold) {
+ "use strict";
+ var yDistMax = Infinity, indexToHighlight = null;
+ values.forEach(function(d,i) {
+ var delta = Math.abs(searchVal - d);
+ if ( delta <= yDistMax && delta < threshold) {
+ yDistMax = delta;
+ indexToHighlight = i;
+ }
+ });
+ return indexToHighlight;
+};/* Tooltip rendering model for nvd3 charts.
+window.nv.models.tooltip is the updated,new way to render tooltips.
+window.nv.tooltip.show is the old tooltip code.
+window.nv.tooltip.* also has various helper methods.
+*/
(function() {
+ "use strict";
+ window.nv.tooltip = {};
+
+ /* Model which can be instantiated to handle tooltip rendering.
+ Example usage:
+ var tip = nv.models.tooltip().gravity('w').distance(23)
+ .data(myDataObject);
+
+ tip(); //just invoke the returned function to render tooltip.
+ */
+ window.nv.models.tooltip = function() {
+ var content = null //HTML contents of the tooltip. If null, the content is generated via the data variable.
+ , data = null /* Tooltip data. If data is given in the proper format, a consistent tooltip is generated.
+ Format of data:
+ {
+ key: "Date",
+ value: "August 2009",
+ series: [
+ {
+ key: "Series 1",
+ value: "Value 1",
+ color: "#000"
+ },
+ {
+ key: "Series 2",
+ value: "Value 2",
+ color: "#00f"
+ }
+ ]
- var nvtooltip = window.nv.tooltip = {};
+ }
- nvtooltip.show = function(pos, content, gravity, dist, parentContainer, classes) {
+ */
+ , gravity = 'w' //Can be 'n','s','e','w'. Determines how tooltip is positioned.
+ , distance = 50 //Distance to offset tooltip from the mouse location.
+ , snapDistance = 25 //Tolerance allowed before tooltip is moved from its current position (creates 'snapping' effect)
+ , fixedTop = null //If not null, this fixes the top position of the tooltip.
+ , classes = null //Attaches additional CSS classes to the tooltip DIV that is created.
+ , chartContainer = null //Parent DIV, of the SVG Container that holds the chart.
+ , tooltipElem = null //actual DOM element representing the tooltip.
+ , position = {left: null, top: null} //Relative position of the tooltip inside chartContainer.
+ , enabled = true //True -> tooltips are rendered. False -> don't render tooltips.
+ //Generates a unique id when you create a new tooltip() object
+ , id = "nvtooltip-" + Math.floor(Math.random() * 100000)
+ ;
+
+ //CSS class to specify whether element should not have mouse events.
+ var nvPointerEventsClass = "nv-pointer-events-none";
+
+ //Format function for the tooltip values column
+ var valueFormatter = function(d,i) {
+ return d;
+ };
- var container = document.createElement('div');
- container.className = 'nvtooltip ' + (classes ? classes : 'xy-tooltip');
+ //Format function for the tooltip header value.
+ var headerFormatter = function(d) {
+ return d;
+ };
- gravity = gravity || 's';
- dist = dist || 20;
+ //By default, the tooltip model renders a beautiful table inside a DIV.
+ //You can override this function if a custom tooltip is desired.
+ var contentGenerator = function(d) {
+ if (content != null) return content;
+
+ if (d == null) return '';
+
+ var table = d3.select(document.createElement("table"));
+ var theadEnter = table.selectAll("thead")
+ .data([d])
+ .enter().append("thead");
+ theadEnter.append("tr")
+ .append("td")
+ .attr("colspan",3)
+ .append("strong")
+ .classed("x-value",true)
+ .html(headerFormatter(d.value));
+
+ var tbodyEnter = table.selectAll("tbody")
+ .data([d])
+ .enter().append("tbody");
+ var trowEnter = tbodyEnter.selectAll("tr")
+ .data(function(p) { return p.series})
+ .enter()
+ .append("tr")
+ .classed("highlight", function(p) { return p.highlight})
+ ;
+
+ trowEnter.append("td")
+ .classed("legend-color-guide",true)
+ .append("div")
+ .style("background-color", function(p) { return p.color});
+ trowEnter.append("td")
+ .classed("key",true)
+ .html(function(p) {return p.key});
+ trowEnter.append("td")
+ .classed("value",true)
+ .html(function(p,i) { return valueFormatter(p.value,i) });
+
+
+ trowEnter.selectAll("td").each(function(p) {
+ if (p.highlight) {
+ var opacityScale = d3.scale.linear().domain([0,1]).range(["#fff",p.color]);
+ var opacity = 0.6;
+ d3.select(this)
+ .style("border-bottom-color", opacityScale(opacity))
+ .style("border-top-color", opacityScale(opacity))
+ ;
+ }
+ });
- var body = parentContainer;
- if ( !parentContainer || parentContainer.tagName.match(/g|svg/i)) {
- //If the parent element is an SVG element, place tooltip in the <body> element.
- body = document.getElementsByTagName('body')[0];
- }
+ var html = table.node().outerHTML;
+ if (d.footer !== undefined)
+ html += "<div class='footer'>" + d.footer + "</div>";
+ return html;
- container.innerHTML = content;
- container.style.left = 0;
- container.style.top = 0;
- 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 = window.scrollY,
- scrollLeft = window.scrollX,
- left, top;
-
- windowHeight = window.innerWidth >= document.body.scrollWidth ? windowHeight : windowHeight - 16;
- windowWidth = window.innerHeight >= document.body.scrollHeight ? windowWidth : windowWidth - 16;
-
- var tooltipTop = function ( Elem ) {
- var offsetTop = top;
- do {
- if( !isNaN( Elem.offsetTop ) ) {
- offsetTop += (Elem.offsetTop);
+ };
+
+ var dataSeriesExists = function(d) {
+ if (d && d.series && d.series.length > 0) return true;
+
+ return false;
+ };
+
+ //In situations where the chart is in a 'viewBox', re-position the tooltip based on how far chart is zoomed.
+ function convertViewBoxRatio() {
+ if (chartContainer) {
+ var svg = d3.select(chartContainer);
+ if (svg.node().tagName !== "svg") {
+ svg = svg.select("svg");
+ }
+ var viewBox = (svg.node()) ? svg.attr('viewBox') : null;
+ if (viewBox) {
+ viewBox = viewBox.split(' ');
+ var ratio = parseInt(svg.style('width')) / viewBox[2];
+
+ position.left = position.left * ratio;
+ position.top = position.top * ratio;
+ }
}
- } while( Elem = Elem.offsetParent );
- return offsetTop;
- }
+ }
- var tooltipLeft = function ( Elem ) {
- var offsetLeft = left;
- do {
- if( !isNaN( Elem.offsetLeft ) ) {
- offsetLeft += (Elem.offsetLeft);
+ //Creates new tooltip container, or uses existing one on DOM.
+ function getTooltipContainer(newContent) {
+ var body;
+ if (chartContainer)
+ body = d3.select(chartContainer);
+ else
+ body = d3.select("body");
+
+ var container = body.select(".nvtooltip");
+ if (container.node() === null) {
+ //Create new tooltip div if it doesn't exist on DOM.
+ container = body.append("div")
+ .attr("class", "nvtooltip " + (classes? classes: "xy-tooltip"))
+ .attr("id",id)
+ ;
}
- } while( Elem = Elem.offsetParent );
- return offsetLeft;
- }
+
- switch (gravity) {
- case 'e':
- left = pos[0] - width - dist;
- top = pos[1] - (height / 2);
- var tLeft = tooltipLeft(container);
- var tTop = tooltipTop(container);
- if (tLeft < scrollLeft) left = pos[0] + dist > scrollLeft ? pos[0] + dist : scrollLeft - tLeft + left;
- if (tTop < scrollTop) top = scrollTop - tTop + top;
- if (tTop + height > scrollTop + windowHeight) top = scrollTop + windowHeight - tTop + top - height;
- break;
- case 'w':
- left = pos[0] + dist;
- top = pos[1] - (height / 2);
- if (tLeft + width > windowWidth) left = pos[0] - width - dist;
- if (tTop < scrollTop) top = scrollTop + 5;
- if (tTop + height > scrollTop + windowHeight) top = scrollTop - height - 5;
- break;
- case 'n':
- left = pos[0] - (width / 2) - 5;
- top = pos[1] + dist;
- var tLeft = tooltipLeft(container);
- var tTop = tooltipTop(container);
- if (tLeft < scrollLeft) left = scrollLeft + 5;
- if (tLeft + width > windowWidth) left = left - width/2 + 5;
- if (tTop + height > scrollTop + windowHeight) top = scrollTop + windowHeight - tTop + top - height;
- break;
- case 's':
- left = pos[0] - (width / 2);
- top = pos[1] - height - dist;
- var tLeft = tooltipLeft(container);
- var tTop = tooltipTop(container);
- if (tLeft < scrollLeft) left = scrollLeft + 5;
- if (tLeft + width > windowWidth) left = left - width/2 + 5;
- if (scrollTop > tTop) top = scrollTop;
- break;
- }
+ container.node().innerHTML = newContent;
+ container.style("top",0).style("left",0).style("opacity",0);
+ container.selectAll("div, table, td, tr").classed(nvPointerEventsClass,true)
+ container.classed(nvPointerEventsClass,true);
+ return container.node();
+ }
+
- container.style.left = left+'px';
- container.style.top = top+'px';
- container.style.opacity = 1;
- container.style.position = 'absolute'; //fix scroll bar issue
- container.style.pointerEvents = 'none'; //fix scroll bar issue
+ //Draw the tooltip onto the DOM.
+ function nvtooltip() {
+ if (!enabled) return;
+ if (!dataSeriesExists(data)) return;
+
+ convertViewBoxRatio();
+
+ var left = position.left;
+ var top = (fixedTop != null) ? fixedTop : position.top;
+ var container = getTooltipContainer(contentGenerator(data));
+ tooltipElem = container;
+ if (chartContainer) {
+ var svgComp = chartContainer.getElementsByTagName("svg")[0];
+ var boundRect = (svgComp) ? svgComp.getBoundingClientRect() : chartContainer.getBoundingClientRect();
+ var svgOffset = {left:0,top:0};
+ if (svgComp) {
+ var svgBound = svgComp.getBoundingClientRect();
+ var chartBound = chartContainer.getBoundingClientRect();
+ var svgBoundTop = svgBound.top;
+
+ //Defensive code. Sometimes, svgBoundTop can be a really negative
+ // number, like -134254. That's a bug.
+ // If such a number is found, use zero instead. FireFox bug only
+ if (svgBoundTop < 0) {
+ var containerBound = chartContainer.getBoundingClientRect();
+ svgBoundTop = (Math.abs(svgBoundTop) > containerBound.height) ? 0 : svgBoundTop;
+ }
+ svgOffset.top = Math.abs(svgBoundTop - chartBound.top);
+ svgOffset.left = Math.abs(svgBound.left - chartBound.left);
+ }
+ //If the parent container is an overflow <div> with scrollbars, subtract the scroll offsets.
+ //You need to also add any offset between the <svg> element and its containing <div>
+ //Finally, add any offset of the containing <div> on the whole page.
+ left += chartContainer.offsetLeft + svgOffset.left - 2*chartContainer.scrollLeft;
+ top += chartContainer.offsetTop + svgOffset.top - 2*chartContainer.scrollTop;
+ }
- return container;
- };
+ if (snapDistance && snapDistance > 0) {
+ top = Math.floor(top/snapDistance) * snapDistance;
+ }
- nvtooltip.cleanup = function() {
+ nv.tooltip.calcTooltipPosition([left,top], gravity, distance, container);
+ return nvtooltip;
+ };
- // 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';
- }
+ nvtooltip.nvPointerEventsClass = nvPointerEventsClass;
+
+ nvtooltip.content = function(_) {
+ if (!arguments.length) return content;
+ content = _;
+ return nvtooltip;
+ };
+ //Returns tooltipElem...not able to set it.
+ nvtooltip.tooltipElem = function() {
+ return tooltipElem;
+ };
- setTimeout(function() {
+ nvtooltip.contentGenerator = function(_) {
+ if (!arguments.length) return contentGenerator;
+ if (typeof _ === 'function') {
+ contentGenerator = _;
+ }
+ return nvtooltip;
+ };
- while (purging.length) {
- var removeMe = purging.pop();
- removeMe.parentNode.removeChild(removeMe);
- }
- }, 500);
+ nvtooltip.data = function(_) {
+ if (!arguments.length) return data;
+ data = _;
+ return nvtooltip;
+ };
+
+ nvtooltip.gravity = function(_) {
+ if (!arguments.length) return gravity;
+ gravity = _;
+ return nvtooltip;
+ };
+
+ nvtooltip.distance = function(_) {
+ if (!arguments.length) return distance;
+ distance = _;
+ return nvtooltip;
+ };
+
+ nvtooltip.snapDistance = function(_) {
+ if (!arguments.length) return snapDistance;
+ snapDistance = _;
+ return nvtooltip;
+ };
+
+ nvtooltip.classes = function(_) {
+ if (!arguments.length) return classes;
+ classes = _;
+ return nvtooltip;
+ };
+
+ nvtooltip.chartContainer = function(_) {
+ if (!arguments.length) return chartContainer;
+ chartContainer = _;
+ return nvtooltip;
+ };
+
+ nvtooltip.position = function(_) {
+ if (!arguments.length) return position;
+ position.left = (typeof _.left !== 'undefined') ? _.left : position.left;
+ position.top = (typeof _.top !== 'undefined') ? _.top : position.top;
+ return nvtooltip;
+ };
+
+ nvtooltip.fixedTop = function(_) {
+ if (!arguments.length) return fixedTop;
+ fixedTop = _;
+ return nvtooltip;
+ };
+
+ nvtooltip.enabled = function(_) {
+ if (!arguments.length) return enabled;
+ enabled = _;
+ return nvtooltip;
+ };
+
+ nvtooltip.valueFormatter = function(_) {
+ if (!arguments.length) return valueFormatter;
+ if (typeof _ === 'function') {
+ valueFormatter = _;
+ }
+ return nvtooltip;
+ };
+
+ nvtooltip.headerFormatter = function(_) {
+ if (!arguments.length) return headerFormatter;
+ if (typeof _ === 'function') {
+ headerFormatter = _;
+ }
+ return nvtooltip;
+ };
+
+ //id() is a read-only function. You can't use it to set the id.
+ nvtooltip.id = function() {
+ return id;
+ };
+
+
+ return nvtooltip;
+ };
+
+
+ //Original tooltip.show function. Kept for backward compatibility.
+ // pos = [left,top]
+ nv.tooltip.show = function(pos, content, gravity, dist, parentContainer, classes) {
+
+ //Create new tooltip div if it doesn't exist on DOM.
+ var container = document.createElement('div');
+ container.className = 'nvtooltip ' + (classes ? classes : 'xy-tooltip');
+
+ var body = parentContainer;
+ if ( !parentContainer || parentContainer.tagName.match(/g|svg/i)) {
+ //If the parent element is an SVG element, place tooltip in the <body> element.
+ body = document.getElementsByTagName('body')[0];
+ }
+
+ container.style.left = 0;
+ container.style.top = 0;
+ container.style.opacity = 0;
+ container.innerHTML = content;
+ body.appendChild(container);
+
+ //If the parent container is an overflow <div> with scrollbars, subtract the scroll offsets.
+ if (parentContainer) {
+ pos[0] = pos[0] - parentContainer.scrollLeft;
+ pos[1] = pos[1] - parentContainer.scrollTop;
+ }
+ nv.tooltip.calcTooltipPosition(pos, gravity, dist, container);
+ };
+
+ //Looks up the ancestry of a DOM element, and returns the first NON-svg node.
+ nv.tooltip.findFirstNonSVGParent = function(Elem) {
+ while(Elem.tagName.match(/^g|svg$/i) !== null) {
+ Elem = Elem.parentNode;
+ }
+ return Elem;
};
+ //Finds the total offsetTop of a given DOM element.
+ //Looks up the entire ancestry of an element, up to the first relatively positioned element.
+ nv.tooltip.findTotalOffsetTop = function ( Elem, initialTop ) {
+ var offsetTop = initialTop;
+
+ do {
+ if( !isNaN( Elem.offsetTop ) ) {
+ offsetTop += (Elem.offsetTop);
+ }
+ } while( Elem = Elem.offsetParent );
+ return offsetTop;
+ };
+
+ //Finds the total offsetLeft of a given DOM element.
+ //Looks up the entire ancestry of an element, up to the first relatively positioned element.
+ nv.tooltip.findTotalOffsetLeft = function ( Elem, initialLeft) {
+ var offsetLeft = initialLeft;
+
+ do {
+ if( !isNaN( Elem.offsetLeft ) ) {
+ offsetLeft += (Elem.offsetLeft);
+ }
+ } while( Elem = Elem.offsetParent );
+ return offsetLeft;
+ };
+
+ //Global utility function to render a tooltip on the DOM.
+ //pos = [left,top] coordinates of where to place the tooltip, relative to the SVG chart container.
+ //gravity = how to orient the tooltip
+ //dist = how far away from the mouse to place tooltip
+ //container = tooltip DIV
+ nv.tooltip.calcTooltipPosition = function(pos, gravity, dist, container) {
+
+ var height = parseInt(container.offsetHeight),
+ width = parseInt(container.offsetWidth),
+ windowWidth = nv.utils.windowSize().width,
+ windowHeight = nv.utils.windowSize().height,
+ scrollTop = window.pageYOffset,
+ scrollLeft = window.pageXOffset,
+ left, top;
+
+ windowHeight = window.innerWidth >= document.body.scrollWidth ? windowHeight : windowHeight - 16;
+ windowWidth = window.innerHeight >= document.body.scrollHeight ? windowWidth : windowWidth - 16;
+
+ gravity = gravity || 's';
+ dist = dist || 20;
+
+ var tooltipTop = function ( Elem ) {
+ return nv.tooltip.findTotalOffsetTop(Elem, top);
+ };
+
+ var tooltipLeft = function ( Elem ) {
+ return nv.tooltip.findTotalOffsetLeft(Elem,left);
+ };
+
+ switch (gravity) {
+ case 'e':
+ left = pos[0] - width - dist;
+ top = pos[1] - (height / 2);
+ var tLeft = tooltipLeft(container);
+ var tTop = tooltipTop(container);
+ if (tLeft < scrollLeft) left = pos[0] + dist > scrollLeft ? pos[0] + dist : scrollLeft - tLeft + left;
+ if (tTop < scrollTop) top = scrollTop - tTop + top;
+ if (tTop + height > scrollTop + windowHeight) top = scrollTop + windowHeight - tTop + top - height;
+ break;
+ case 'w':
+ left = pos[0] + dist;
+ top = pos[1] - (height / 2);
+ var tLeft = tooltipLeft(container);
+ var tTop = tooltipTop(container);
+ if (tLeft + width > windowWidth) left = pos[0] - width - dist;
+ if (tTop < scrollTop) top = scrollTop + 5;
+ if (tTop + height > scrollTop + windowHeight) top = scrollTop + windowHeight - tTop + top - height;
+ break;
+ case 'n':
+ left = pos[0] - (width / 2) - 5;
+ top = pos[1] + dist;
+ var tLeft = tooltipLeft(container);
+ var tTop = tooltipTop(container);
+ if (tLeft < scrollLeft) left = scrollLeft + 5;
+ if (tLeft + width > windowWidth) left = left - width/2 + 5;
+ if (tTop + height > scrollTop + windowHeight) top = scrollTop + windowHeight - tTop + top - height;
+ break;
+ case 's':
+ left = pos[0] - (width / 2);
+ top = pos[1] - height - dist;
+ var tLeft = tooltipLeft(container);
+ var tTop = tooltipTop(container);
+ if (tLeft < scrollLeft) left = scrollLeft + 5;
+ if (tLeft + width > windowWidth) left = left - width/2 + 5;
+ if (scrollTop > tTop) top = scrollTop;
+ break;
+ case 'none':
+ left = pos[0];
+ top = pos[1] - dist;
+ var tLeft = tooltipLeft(container);
+ var tTop = tooltipTop(container);
+ break;
+ }
+
+
+ container.style.left = left+'px';
+ container.style.top = top+'px';
+ container.style.opacity = 1;
+ container.style.position = 'absolute';
+
+ return container;
+ };
+
+ //Global utility function to remove tooltips from the DOM.
+ nv.tooltip.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);
+ };
})();
@@ -282,6 +896,7 @@ nv.utils.windowSize = function() {
// Easy way to bind multiple functions to window.onresize
// TODO: give a way to remove a function after its bound, other than removing all of them
nv.utils.windowResize = function(fun){
+ if (fun === undefined) return;
var oldresize = window.onresize;
window.onresize = function(e) {
@@ -356,20 +971,53 @@ nv.utils.pjax = function(links, content) {
}
/* For situations where we want to approximate the width in pixels for an SVG:text element.
-Most common instance is when the element is in a display:none; container.
+Most common instance is when the element is in a display:none; container.
Forumla is : text.length * font-size * constant_factor
*/
nv.utils.calcApproxTextWidth = function (svgTextElem) {
- if (svgTextElem instanceof d3.selection) {
+ if (typeof svgTextElem.style === 'function'
+ && typeof svgTextElem.text === 'function') {
var fontSize = parseInt(svgTextElem.style("font-size").replace("px",""));
var textLength = svgTextElem.text().length;
- return textLength * fontSize * 0.5;
+ return textLength * fontSize * 0.5;
}
return 0;
};
-nv.models.axis = function() {
+/* Numbers that are undefined, null or NaN, convert them to zeros.
+*/
+nv.utils.NaNtoZero = function(n) {
+ if (typeof n !== 'number'
+ || isNaN(n)
+ || n === null
+ || n === Infinity) return 0;
+
+ return n;
+};
+
+/*
+Snippet of code you can insert into each nv.models.* to give you the ability to
+do things like:
+chart.options({
+ showXAxis: true,
+ tooltips: true
+});
+
+To enable in the chart:
+chart.options = nv.utils.optionsFunc.bind(chart);
+*/
+nv.utils.optionsFunc = function(args) {
+ if (args) {
+ d3.map(args).forEach((function(key,value) {
+ if (typeof this[key] === "function") {
+ this[key](value);
+ }
+ }).bind(this));
+ }
+ return this;
+};nv.models.axis = function() {
+ "use strict";
//============================================================
// Public Variables with Default Settings
//------------------------------------------------------------
@@ -389,6 +1037,7 @@ nv.models.axis = function() {
, staggerLabels = false
, isOrdinal = false
, ticks = null
+ , axisLabelDistance = 12 //The larger this number is, the closer the axis label is to the axis.
;
axis
@@ -434,8 +1083,7 @@ nv.models.axis = function() {
//TODO: consider calculating width/height based on whether or not label is added, for reference in charts using this component
- d3.transition(g)
- .call(axis);
+ g.transition().call(axis);
scale0 = scale0 || axis.scale();
@@ -465,14 +1113,14 @@ nv.models.axis = function() {
return 'translate(' + scale(d) + ',0)'
})
.select('text')
- .attr('dy', '0em')
+ .attr('dy', '-0.5em')
.attr('y', -axis.tickPadding())
.attr('text-anchor', 'middle')
.text(function(d,i) {
var v = fmt(d);
return ('' + v).match('NaN') ? '' : v;
});
- d3.transition(axisMaxMin)
+ axisMaxMin.transition()
.attr('transform', function(d,i) {
return 'translate(' + scale.range()[i] + ',0)'
});
@@ -494,7 +1142,7 @@ nv.models.axis = function() {
//Rotate all xTicks
xTicks
.attr('transform', function(d,i,j) { return 'rotate(' + rotateLabels + ' 0,0)' })
- .attr('text-anchor', rotateLabels%360 > 0 ? 'start' : 'end');
+ .style('text-anchor', rotateLabels%360 > 0 ? 'start' : 'end');
}
axisLabel.enter().append('text').attr('class', 'nv-axislabel');
var w = (scale.range().length==2) ? scale.range()[1] : (scale.range()[scale.range().length-1]+(scale.range()[1]-scale.range()[0]));
@@ -517,12 +1165,12 @@ nv.models.axis = function() {
.attr('dy', '.71em')
.attr('y', axis.tickPadding())
.attr('transform', function(d,i,j) { return 'rotate(' + rotateLabels + ' 0,0)' })
- .attr('text-anchor', rotateLabels ? (rotateLabels%360 > 0 ? 'start' : 'end') : 'middle')
+ .style('text-anchor', rotateLabels ? (rotateLabels%360 > 0 ? 'start' : 'end') : 'middle')
.text(function(d,i) {
var v = fmt(d);
return ('' + v).match('NaN') ? '' : v;
});
- d3.transition(axisMaxMin)
+ axisMaxMin.transition()
.attr('transform', function(d,i) {
//return 'translate(' + scale.range()[i] + ',0)'
//return 'translate(' + scale(d) + ',0)'
@@ -537,7 +1185,7 @@ nv.models.axis = function() {
case 'right':
axisLabel.enter().append('text').attr('class', 'nv-axislabel');
axisLabel
- .attr('text-anchor', rotateYLabel ? 'middle' : 'begin')
+ .style('text-anchor', rotateYLabel ? 'middle' : 'begin')
.attr('transform', rotateYLabel ? 'rotate(90)' : '')
.attr('y', rotateYLabel ? (-Math.max(margin.right,width) + 12) : -10) //TODO: consider calculating this based on largest tick width... OR at least expose this on chart
.attr('x', rotateYLabel ? (scale.range()[0] / 2) : axis.tickPadding());
@@ -555,12 +1203,12 @@ nv.models.axis = function() {
.attr('dy', '.32em')
.attr('y', 0)
.attr('x', axis.tickPadding())
- .attr('text-anchor', 'start')
+ .style('text-anchor', 'start')
.text(function(d,i) {
var v = fmt(d);
return ('' + v).match('NaN') ? '' : v;
});
- d3.transition(axisMaxMin)
+ axisMaxMin.transition()
.attr('transform', function(d,i) {
return 'translate(0,' + scale.range()[i] + ')'
})
@@ -579,9 +1227,9 @@ nv.models.axis = function() {
*/
axisLabel.enter().append('text').attr('class', 'nv-axislabel');
axisLabel
- .attr('text-anchor', rotateYLabel ? 'middle' : 'end')
+ .style('text-anchor', rotateYLabel ? 'middle' : 'end')
.attr('transform', rotateYLabel ? 'rotate(-90)' : '')
- .attr('y', rotateYLabel ? (-Math.max(margin.left,width) + 12) : -10) //TODO: consider calculating this based on largest tick width... OR at least expose this on chart
+ .attr('y', rotateYLabel ? (-Math.max(margin.left,width) + axisLabelDistance) : -10) //TODO: consider calculating this based on largest tick width... OR at least expose this on chart
.attr('x', rotateYLabel ? (-scale.range()[0] / 2) : -axis.tickPadding());
if (showMaxMin) {
var axisMaxMin = wrap.selectAll('g.nv-axisMaxMin')
@@ -602,7 +1250,7 @@ nv.models.axis = function() {
var v = fmt(d);
return ('' + v).match('NaN') ? '' : v;
});
- d3.transition(axisMaxMin)
+ axisMaxMin.transition()
.attr('transform', function(d,i) {
return 'translate(0,' + scale.range()[i] + ')'
})
@@ -623,7 +1271,7 @@ nv.models.axis = function() {
if (scale(d) < scale.range()[1] + 10 || scale(d) > scale.range()[0] - 10) { // 10 is assuming text height is 16... if d is 0, leave it!
if (d > 1e-10 || d < -1e-10) // accounts for minor floating point errors... though could be problematic if the scale is EXTREMELY SMALL
d3.select(this).attr('opacity', 0);
-
+
d3.select(this).select('text').attr('opacity', 0); // Don't remove the ZERO line!!
}
});
@@ -688,6 +1336,8 @@ nv.models.axis = function() {
d3.rebind(chart, axis, 'orient', 'tickValues', 'tickSubdivide', 'tickSize', 'tickPadding', 'tickFormat');
d3.rebind(chart, scale, 'domain', 'range', 'rangeBand', 'rangeBands'); //these are also accessible by chart.scale(), but added common ones directly for ease of use
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
chart.margin = function(_) {
if(!arguments.length) return margin;
margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
@@ -760,71 +1410,79 @@ nv.models.axis = function() {
return chart;
};
+ chart.axisLabelDistance = function(_) {
+ if (!arguments.length) return axisLabelDistance;
+ axisLabelDistance = _;
+ return chart;
+ };
//============================================================
return chart;
}
-
-// 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() {
-
+//TODO: consider deprecating and using multibar with single series for this
+nv.models.historicalBar = function() {
+ "use strict";
//============================================================
// 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
- , color = nv.utils.getColor(['#1f77b4'])
- , dispatch = d3.dispatch('elementMouseover', 'elementMouseout')
+ , width = 960
+ , height = 500
+ , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
+ , x = d3.scale.linear()
+ , y = d3.scale.linear()
+ , getX = function(d) { return d.x }
+ , getY = function(d) { return d.y }
+ , forceX = []
+ , forceY = [0]
+ , padData = false
+ , clipEdge = true
+ , color = nv.utils.defaultColor()
+ , xDomain
+ , yDomain
+ , xRange
+ , yRange
+ , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout')
+ , interactive = true
;
//============================================================
function chart(selection) {
- selection.each(function(d, i) {
+ selection.each(function(data) {
var availableWidth = width - margin.left - margin.right,
availableHeight = height - margin.top - margin.bottom,
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),
- measurez = measures.call(this, d, i).slice().sort(d3.descending);
-
//------------------------------------------------------------
// Setup Scales
- // Compute the new x-scale.
- var x1 = d3.scale.linear()
- .domain( d3.extent(d3.merge([forceX, rangez])) )
- .range(reverse ? [availableWidth, 0] : [0, availableWidth]);
+ x .domain(xDomain || d3.extent(data[0].values.map(getX).concat(forceX) ))
- // Retrieve the old x-scale, if this is an update.
- var x0 = this.__chart__ || d3.scale.linear()
- .domain([0, Infinity])
- .range(x1.range());
+ if (padData)
+ x.range(xRange || [availableWidth * .5 / data[0].values.length, availableWidth * (data[0].values.length - .5) / data[0].values.length ]);
+ else
+ x.range(xRange || [0, availableWidth]);
- // Stash the new scale.
- this.__chart__ = x1;
+ y .domain(yDomain || d3.extent(data[0].values.map(getY).concat(forceY) ))
+ .range(yRange || [availableHeight, 0]);
+ // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point
- var rangeMin = d3.min(rangez), //rangez[2]
- rangeMax = d3.max(rangez), //rangez[0]
- rangeAvg = rangez[1];
+ if (x.domain()[0] === x.domain()[1])
+ x.domain()[0] ?
+ x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01])
+ : x.domain([-1,1]);
+
+ if (y.domain()[0] === y.domain()[1])
+ y.domain()[0] ?
+ y.domain([y.domain()[0] + y.domain()[0] * 0.01, y.domain()[1] - y.domain()[1] * 0.01])
+ : y.domain([-1,1]);
//------------------------------------------------------------
@@ -832,63 +1490,397 @@ nv.models.bullet = function() {
//------------------------------------------------------------
// 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 wrap = container.selectAll('g.nv-wrap.nv-historicalBar-' + id).data([data[0].values]);
+ var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-historicalBar-' + id);
+ var defsEnter = wrapEnter.append('defs');
var gEnter = wrapEnter.append('g');
var g = wrap.select('g');
- gEnter.append('rect').attr('class', 'nv-range nv-rangeMax');
- gEnter.append('rect').attr('class', 'nv-range nv-rangeAvg');
- gEnter.append('rect').attr('class', 'nv-range nv-rangeMin');
- gEnter.append('rect').attr('class', 'nv-measure');
- gEnter.append('path').attr('class', 'nv-markerTriangle');
+ gEnter.append('g').attr('class', 'nv-bars');
wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
//------------------------------------------------------------
+ container
+ .on('click', function(d,i) {
+ dispatch.chartClick({
+ data: d,
+ index: i,
+ pos: d3.event,
+ id: id
+ });
+ });
- 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 xp0 = function(d) { return d < 0 ? x0(d) : x0(0) },
- xp1 = function(d) { return d < 0 ? x1(d) : x1(0) };
+ defsEnter.append('clipPath')
+ .attr('id', 'nv-chart-clip-path-' + id)
+ .append('rect');
- g.select('rect.nv-rangeMax')
- .attr('height', availableHeight)
- .attr('width', w1(rangeMax > 0 ? rangeMax : rangeMin))
- .attr('x', xp1(rangeMax > 0 ? rangeMax : rangeMin))
- .datum(rangeMax > 0 ? rangeMax : rangeMin)
- /*
- .attr('x', rangeMin < 0 ?
- rangeMax > 0 ?
- x1(rangeMin)
- : x1(rangeMax)
- : x1(0))
- */
+ wrap.select('#nv-chart-clip-path-' + id + ' rect')
+ .attr('width', availableWidth)
+ .attr('height', availableHeight);
- g.select('rect.nv-rangeAvg')
- .attr('height', availableHeight)
- .attr('width', w1(rangeAvg))
- .attr('x', xp1(rangeAvg))
- .datum(rangeAvg)
- /*
- .attr('width', rangeMax <= 0 ?
- x1(rangeMax) - x1(rangeAvg)
- : x1(rangeAvg) - x1(rangeMin))
- .attr('x', rangeMax <= 0 ?
- x1(rangeAvg)
- : x1(rangeMin))
- */
+ g .attr('clip-path', clipEdge ? 'url(#nv-chart-clip-path-' + id + ')' : '');
- g.select('rect.nv-rangeMin')
- .attr('height', availableHeight)
- .attr('width', w1(rangeMax))
- .attr('x', xp1(rangeMax))
- .attr('width', w1(rangeMax > 0 ? rangeMin : rangeMax))
- .attr('x', xp1(rangeMax > 0 ? rangeMin : rangeMax))
- .datum(rangeMax > 0 ? rangeMin : rangeMax)
+
+
+ var bars = wrap.select('.nv-bars').selectAll('.nv-bar')
+ .data(function(d) { return d }, function(d,i) {return getX(d,i)});
+
+ bars.exit().remove();
+
+
+ var barsEnter = bars.enter().append('rect')
+ //.attr('class', function(d,i,j) { return (getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive') + ' nv-bar-' + j + '-' + i })
+ .attr('x', 0 )
+ .attr('y', function(d,i) { return nv.utils.NaNtoZero(y(Math.max(0, getY(d,i)))) })
+ .attr('height', function(d,i) { return nv.utils.NaNtoZero(Math.abs(y(getY(d,i)) - y(0))) })
+ .attr('transform', function(d,i) { return 'translate(' + (x(getX(d,i)) - availableWidth / data[0].values.length * .45) + ',0)'; })
+ .on('mouseover', function(d,i) {
+ if (!interactive) return;
+ d3.select(this).classed('hover', true);
+ dispatch.elementMouseover({
+ point: d,
+ series: data[0],
+ pos: [x(getX(d,i)), y(getY(d,i))], // TODO: Figure out why the value appears to be shifted
+ pointIndex: i,
+ seriesIndex: 0,
+ e: d3.event
+ });
+
+ })
+ .on('mouseout', function(d,i) {
+ if (!interactive) return;
+ d3.select(this).classed('hover', false);
+ dispatch.elementMouseout({
+ point: d,
+ series: data[0],
+ pointIndex: i,
+ seriesIndex: 0,
+ e: d3.event
+ });
+ })
+ .on('click', function(d,i) {
+ if (!interactive) return;
+ dispatch.elementClick({
+ //label: d[label],
+ value: getY(d,i),
+ data: d,
+ index: i,
+ pos: [x(getX(d,i)), y(getY(d,i))],
+ e: d3.event,
+ id: id
+ });
+ d3.event.stopPropagation();
+ })
+ .on('dblclick', function(d,i) {
+ if (!interactive) return;
+ dispatch.elementDblClick({
+ //label: d[label],
+ value: getY(d,i),
+ data: d,
+ index: i,
+ pos: [x(getX(d,i)), y(getY(d,i))],
+ e: d3.event,
+ id: id
+ });
+ d3.event.stopPropagation();
+ });
+
+ bars
+ .attr('fill', function(d,i) { return color(d, i); })
+ .attr('class', function(d,i,j) { return (getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive') + ' nv-bar-' + j + '-' + i })
+ .transition()
+ .attr('transform', function(d,i) { return 'translate(' + (x(getX(d,i)) - availableWidth / data[0].values.length * .45) + ',0)'; })
+ //TODO: better width calculations that don't assume always uniform data spacing;w
+ .attr('width', (availableWidth / data[0].values.length) * .9 );
+
+
+ bars.transition()
+ .attr('y', function(d,i) {
+ var rval = getY(d,i) < 0 ?
+ y(0) :
+ y(0) - y(getY(d,i)) < 1 ?
+ y(0) - 1 :
+ y(getY(d,i));
+ return nv.utils.NaNtoZero(rval);
+ })
+ .attr('height', function(d,i) { return nv.utils.NaNtoZero(Math.max(Math.abs(y(getY(d,i)) - y(0)),1)) });
+
+ });
+
+ return chart;
+ }
+
+ //Create methods to allow outside functions to highlight a specific bar.
+ chart.highlightPoint = function(pointIndex, isHoverOver) {
+ d3.select(".nv-historicalBar-" + id)
+ .select(".nv-bars .nv-bar-0-" + pointIndex)
+ .classed("hover", isHoverOver)
+ ;
+ };
+
+ chart.clearHighlights = function() {
+ d3.select(".nv-historicalBar-" + id)
+ .select(".nv-bars .nv-bar.hover")
+ .classed("hover", false)
+ ;
+ };
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ chart.dispatch = dispatch;
+
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart.x = function(_) {
+ if (!arguments.length) return getX;
+ getX = _;
+ return chart;
+ };
+
+ chart.y = function(_) {
+ if (!arguments.length) return getY;
+ getY = _;
+ 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.width = function(_) {
+ if (!arguments.length) return width;
+ width = _;
+ return chart;
+ };
+
+ chart.height = function(_) {
+ if (!arguments.length) return height;
+ height = _;
+ return chart;
+ };
+
+ chart.xScale = function(_) {
+ if (!arguments.length) return x;
+ x = _;
+ return chart;
+ };
+
+ chart.yScale = function(_) {
+ if (!arguments.length) return y;
+ y = _;
+ return chart;
+ };
+
+ chart.xDomain = function(_) {
+ if (!arguments.length) return xDomain;
+ xDomain = _;
+ return chart;
+ };
+
+ chart.yDomain = function(_) {
+ if (!arguments.length) return yDomain;
+ yDomain = _;
+ return chart;
+ };
+
+ chart.xRange = function(_) {
+ if (!arguments.length) return xRange;
+ xRange = _;
+ return chart;
+ };
+
+ chart.yRange = function(_) {
+ if (!arguments.length) return yRange;
+ yRange = _;
+ return chart;
+ };
+
+ chart.forceX = function(_) {
+ if (!arguments.length) return forceX;
+ forceX = _;
+ return chart;
+ };
+
+ chart.forceY = function(_) {
+ if (!arguments.length) return forceY;
+ forceY = _;
+ return chart;
+ };
+
+ chart.padData = function(_) {
+ if (!arguments.length) return padData;
+ padData = _;
+ return chart;
+ };
+
+ chart.clipEdge = function(_) {
+ if (!arguments.length) return clipEdge;
+ clipEdge = _;
+ return chart;
+ };
+
+ chart.color = function(_) {
+ if (!arguments.length) return color;
+ color = nv.utils.getColor(_);
+ return chart;
+ };
+
+ chart.id = function(_) {
+ if (!arguments.length) return id;
+ id = _;
+ return chart;
+ };
+
+ chart.interactive = function(_) {
+ if(!arguments.length) return interactive;
+ interactive = false;
+ return chart;
+ };
+
+ //============================================================
+
+
+ return chart;
+}
+
+// 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() {
+ "use strict";
+ //============================================================
+ // 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 }
+ , rangeLabels = function(d) { return d.rangeLabels ? d.rangeLabels : [] }
+ , markerLabels = function(d) { return d.markerLabels ? d.markerLabels : [] }
+ , measureLabels = function(d) { return d.measureLabels ? d.measureLabels : [] }
+ , forceX = [0] // List of numbers to Force into the X scale (ie. 0, or a max / min, etc.)
+ , width = 380
+ , height = 30
+ , tickFormat = null
+ , color = nv.utils.getColor(['#1f77b4'])
+ , 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);
+
+ 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),
+ rangeLabelz = rangeLabels.call(this, d, i).slice(),
+ markerLabelz = markerLabels.call(this, d, i).slice(),
+ measureLabelz = measureLabels.call(this, d, i).slice();
+
+
+ //------------------------------------------------------------
+ // Setup Scales
+
+ // Compute the new x-scale.
+ var x1 = d3.scale.linear()
+ .domain( d3.extent(d3.merge([forceX, rangez])) )
+ .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;
+
+
+ var rangeMin = d3.min(rangez), //rangez[2]
+ rangeMax = d3.max(rangez), //rangez[0]
+ rangeAvg = rangez[1];
+
+ //------------------------------------------------------------
+
+
+ //------------------------------------------------------------
+ // 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');
+
+ gEnter.append('rect').attr('class', 'nv-range nv-rangeMax');
+ gEnter.append('rect').attr('class', 'nv-range nv-rangeAvg');
+ gEnter.append('rect').attr('class', 'nv-range nv-rangeMin');
+ gEnter.append('rect').attr('class', 'nv-measure');
+ gEnter.append('path').attr('class', 'nv-markerTriangle');
+
+ 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)) };
+ var xp0 = function(d) { return d < 0 ? x0(d) : x0(0) },
+ xp1 = function(d) { return d < 0 ? x1(d) : x1(0) };
+
+
+ g.select('rect.nv-rangeMax')
+ .attr('height', availableHeight)
+ .attr('width', w1(rangeMax > 0 ? rangeMax : rangeMin))
+ .attr('x', xp1(rangeMax > 0 ? rangeMax : rangeMin))
+ .datum(rangeMax > 0 ? rangeMax : rangeMin)
+ /*
+ .attr('x', rangeMin < 0 ?
+ rangeMax > 0 ?
+ x1(rangeMin)
+ : x1(rangeMax)
+ : x1(0))
+ */
+
+ g.select('rect.nv-rangeAvg')
+ .attr('height', availableHeight)
+ .attr('width', w1(rangeAvg))
+ .attr('x', xp1(rangeAvg))
+ .datum(rangeAvg)
+ /*
+ .attr('width', rangeMax <= 0 ?
+ x1(rangeMax) - x1(rangeAvg)
+ : x1(rangeAvg) - x1(rangeMin))
+ .attr('x', rangeMax <= 0 ?
+ x1(rangeAvg)
+ : x1(rangeMin))
+ */
+
+ g.select('rect.nv-rangeMin')
+ .attr('height', availableHeight)
+ .attr('width', w1(rangeMax))
+ .attr('x', xp1(rangeMax))
+ .attr('width', w1(rangeMax > 0 ? rangeMin : rangeMax))
+ .attr('x', xp1(rangeMax > 0 ? rangeMin : rangeMax))
+ .datum(rangeMax > 0 ? rangeMin : rangeMax)
/*
.attr('width', rangeMax <= 0 ?
x1(rangeAvg) - x1(rangeMin)
@@ -909,14 +1901,14 @@ nv.models.bullet = function() {
.on('mouseover', function() {
dispatch.elementMouseover({
value: measurez[0],
- label: 'Current',
+ label: measureLabelz[0] || 'Current',
pos: [x1(measurez[0]), availableHeight/2]
})
})
.on('mouseout', function() {
dispatch.elementMouseout({
value: measurez[0],
- label: 'Current'
+ label: measureLabelz[0] || 'Current'
})
})
@@ -928,14 +1920,14 @@ nv.models.bullet = function() {
.on('mouseover', function() {
dispatch.elementMouseover({
value: markerz[0],
- label: 'Previous',
+ label: markerLabelz[0] || 'Previous',
pos: [x1(markerz[0]), availableHeight/2]
})
})
.on('mouseout', function() {
dispatch.elementMouseout({
value: markerz[0],
- label: 'Previous'
+ label: markerLabelz[0] || 'Previous'
})
});
} else {
@@ -945,7 +1937,7 @@ nv.models.bullet = function() {
wrap.selectAll('.nv-range')
.on('mouseover', function(d,i) {
- var label = !i ? "Maximum" : i == 1 ? "Mean" : "Minimum";
+ var label = rangeLabelz[i] || (!i ? "Maximum" : i == 1 ? "Mean" : "Minimum");
dispatch.elementMouseover({
value: d,
@@ -954,7 +1946,7 @@ nv.models.bullet = function() {
})
})
.on('mouseout', function(d,i) {
- var label = !i ? "Maximum" : i == 1 ? "Mean" : "Minimum";
+ var label = rangeLabelz[i] || (!i ? "Maximum" : i == 1 ? "Mean" : "Minimum");
dispatch.elementMouseout({
value: d,
@@ -1068,6 +2060,8 @@ nv.models.bullet = function() {
chart.dispatch = dispatch;
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
// left, right, top, bottom
chart.orient = function(_) {
if (!arguments.length) return orient;
@@ -1148,7 +2142,7 @@ nv.models.bullet = function() {
// based on the work of Clint Ivy, Jamie Love, and Jason Davies.
// http://projects.instantcognition.com/protovis/bulletchart/
nv.models.bulletChart = function() {
-
+ "use strict";
//============================================================
// Public Variables with Default Settings
//------------------------------------------------------------
@@ -1403,6 +2397,8 @@ nv.models.bulletChart = function() {
d3.rebind(chart, bullet, 'color');
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
// left, right, top, bottom
chart.orient = function(x) {
if (!arguments.length) return orient;
@@ -1486,7 +2482,7 @@ nv.models.bulletChart = function() {
nv.models.cumulativeLineChart = function() {
-
+ "use strict";
//============================================================
// Public Variables with Default Settings
//------------------------------------------------------------
@@ -1496,6 +2492,7 @@ nv.models.cumulativeLineChart = function() {
, yAxis = nv.models.axis()
, legend = nv.models.legend()
, controls = nv.models.legend()
+ , interactiveLayer = nv.interactiveGuideline()
;
var margin = {top: 30, right: 30, bottom: 50, left: 60}
@@ -1503,8 +2500,12 @@ nv.models.cumulativeLineChart = function() {
, width = null
, height = null
, showLegend = true
+ , showXAxis = true
+ , showYAxis = true
+ , rightAlignYAxis = false
, tooltips = true
, showControls = true
+ , useInteractiveGuideline = false
, rescaleY = true
, tooltip = function(key, x, y, e, graph) {
return '<h3>' + key + '</h3>' +
@@ -1518,6 +2519,8 @@ nv.models.cumulativeLineChart = function() {
, noData = 'No Data Available.'
, average = function(d) { return d.average }
, dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState')
+ , transitionDuration = 250
+ , noErrorCheck = false //if set to TRUE, will bypass an error check in the indexify function.
;
xAxis
@@ -1525,11 +2528,11 @@ nv.models.cumulativeLineChart = function() {
.tickPadding(7)
;
yAxis
- .orient('left')
+ .orient((rightAlignYAxis) ? 'right' : 'left')
;
//============================================================
-
+ controls.updateState(false);
//============================================================
// Private Variables
@@ -1549,36 +2552,8 @@ nv.models.cumulativeLineChart = function() {
nv.tooltip.show([left, top], content, null, null, offsetElement);
};
-/*
- //Moved to see if we can get better behavior to fix issue #315
- var indexDrag = d3.behavior.drag()
- .on('dragstart', dragStart)
- .on('drag', dragMove)
- .on('dragend', dragEnd);
-
- function dragStart(d,i) {
- d3.select(chart.container)
- .style('cursor', 'ew-resize');
- }
-
- function dragMove(d,i) {
- d.x += d3.event.dx;
- d.i = Math.round(dx.invert(d.x));
-
- d3.select(this).attr('transform', 'translate(' + dx(d.i) + ',0)');
- chart.update();
- }
-
- function dragEnd(d,i) {
- d3.select(chart.container)
- .style('cursor', 'auto');
- chart.update();
- }
-*/
-
//============================================================
-
function chart(selection) {
selection.each(function(data) {
var container = d3.select(this).classed('nv-chart-' + id, true),
@@ -1590,7 +2565,7 @@ nv.models.cumulativeLineChart = function() {
- margin.top - margin.bottom;
- chart.update = function() { container.transition().call(chart) };
+ chart.update = function() { container.transition().duration(transitionDuration).call(chart) };
chart.container = this;
//set state.disabled
@@ -1633,9 +2608,6 @@ nv.models.cumulativeLineChart = function() {
dispatch.stateChange(state);
}
-
-
-
//------------------------------------------------------------
// Display No Data message if there's nothing to show.
@@ -1705,21 +2677,20 @@ nv.models.cumulativeLineChart = function() {
//------------------------------------------------------------
// Setup containers and skeleton of chart
-
+ var interactivePointerEvents = (useInteractiveGuideline) ? "none" : "all";
var wrap = container.selectAll('g.nv-wrap.nv-cumulativeLine').data([data]);
var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-cumulativeLine').append('g');
var g = wrap.select('g');
- gEnter.append('g').attr('class', 'nv-x nv-axis');
+ gEnter.append('g').attr('class', 'nv-interactive');
+ gEnter.append('g').attr('class', 'nv-x nv-axis').style("pointer-events","none");
gEnter.append('g').attr('class', 'nv-y nv-axis');
gEnter.append('g').attr('class', 'nv-background');
- gEnter.append('g').attr('class', 'nv-linesWrap');
- gEnter.append('g').attr('class', 'nv-avgLinesWrap');
+ gEnter.append('g').attr('class', 'nv-linesWrap').style("pointer-events",interactivePointerEvents);
+ gEnter.append('g').attr('class', 'nv-avgLinesWrap').style("pointer-events","none");
gEnter.append('g').attr('class', 'nv-legendWrap');
gEnter.append('g').attr('class', 'nv-controlsWrap');
- //------------------------------------------------------------
-
//------------------------------------------------------------
// Legend
@@ -1732,7 +2703,7 @@ nv.models.cumulativeLineChart = function() {
.call(legend);
if ( margin.top != legend.height()) {
- margin.top = legend.height() + legend.legendBelowPadding();// added legend.legendBelowPadding to allow for more spacing
+ margin.top = legend.height();
availableHeight = (height || parseInt(container.style('height')) || 400)
- margin.top - margin.bottom;
}
@@ -1752,7 +2723,13 @@ nv.models.cumulativeLineChart = function() {
{ key: 'Re-scale y-axis', disabled: !rescaleY }
];
- controls.width(140).color(['#444', '#444', '#444']);
+ controls
+ .width(140)
+ .color(['#444', '#444', '#444'])
+ .rightAlign(false)
+ .margin({top: 5, right: 0, bottom: 5, left: 20})
+ ;
+
g.select('.nv-controlsWrap')
.datum(controlsData)
.attr('transform', 'translate(0,' + (-margin.top) +')')
@@ -1764,6 +2741,10 @@ nv.models.cumulativeLineChart = function() {
wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+ if (rightAlignYAxis) {
+ g.select(".nv-y.nv-axis")
+ .attr("transform", "translate(" + availableWidth + ",0)");
+ }
// Show error if series goes below 100%
var tempDisabled = data.filter(function(d) { return d.tempDisabled });
@@ -1780,6 +2761,18 @@ nv.models.cumulativeLineChart = function() {
//------------------------------------------------------------
// Main Chart Component(s)
+ //------------------------------------------------------------
+ //Set up interactive layer
+ if (useInteractiveGuideline) {
+ interactiveLayer
+ .width(availableWidth)
+ .height(availableHeight)
+ .margin({left:margin.left,top:margin.top})
+ .svgContainer(container)
+ .xScale(x);
+ wrap.select(".nv-interactive").call(interactiveLayer);
+ }
+
gEnter.select('.nv-background')
.append('rect');
@@ -1818,6 +2811,14 @@ nv.models.cumulativeLineChart = function() {
var avgLines = g.select(".nv-avgLinesWrap").selectAll("line")
.data(avgLineData, function(d) { return d.key; });
+ var getAvgLineY = function(d) {
+ //If average lines go off the svg element, clamp them to the svg bounds.
+ var yVal = y(average(d));
+ if (yVal < 0) return 0;
+ if (yVal > availableHeight) return availableHeight;
+ return yVal;
+ };
+
avgLines.enter()
.append('line')
.style('stroke-width',2)
@@ -1827,14 +2828,20 @@ nv.models.cumulativeLineChart = function() {
})
.attr('x1',0)
.attr('x2',availableWidth)
- .attr('y1', function(d) { return y(average(d)); })
- .attr('y2', function(d) { return y(average(d)); });
+ .attr('y1', getAvgLineY)
+ .attr('y2', getAvgLineY);
avgLines
+ .style('stroke-opacity',function(d){
+ //If average lines go offscreen, make them transparent
+ var yVal = y(average(d));
+ if (yVal < 0 || yVal > availableHeight) return 0;
+ return 1;
+ })
.attr('x1',0)
.attr('x2',availableWidth)
- .attr('y1', function(d) { return y(average(d)); })
- .attr('y2', function(d) { return y(average(d)); });
+ .attr('y1', getAvgLineY)
+ .attr('y2', getAvgLineY);
avgLines.exit().remove();
@@ -1847,6 +2854,7 @@ nv.models.cumulativeLineChart = function() {
.attr('x', -2)
.attr('fill', 'red')
.attr('fill-opacity', .5)
+ .style("pointer-events","all")
.call(indexDrag)
indexLine
@@ -1859,26 +2867,29 @@ nv.models.cumulativeLineChart = function() {
//------------------------------------------------------------
// Setup Axes
- xAxis
- .scale(x)
- //Suggest how many ticks based on the chart width and D3 should listen (70 is the optimal number for MM/DD/YY dates)
- .ticks( Math.min(data[0].values.length,availableWidth/70) )
- .tickSize(-availableHeight, 0);
-
- g.select('.nv-x.nv-axis')
- .attr('transform', 'translate(0,' + y.range()[0] + ')');
- d3.transition(g.select('.nv-x.nv-axis'))
- .call(xAxis);
+ if (showXAxis) {
+ xAxis
+ .scale(x)
+ //Suggest how many ticks based on the chart width and D3 should listen (70 is the optimal number for MM/DD/YY dates)
+ .ticks( Math.min(data[0].values.length,availableWidth/70) )
+ .tickSize(-availableHeight, 0);
+ g.select('.nv-x.nv-axis')
+ .attr('transform', 'translate(0,' + y.range()[0] + ')');
+ d3.transition(g.select('.nv-x.nv-axis'))
+ .call(xAxis);
+ }
- yAxis
- .scale(y)
- .ticks( availableHeight / 36 )
- .tickSize( -availableWidth, 0);
- d3.transition(g.select('.nv-y.nv-axis'))
- .call(yAxis);
+ if (showYAxis) {
+ yAxis
+ .scale(y)
+ .ticks( availableHeight / 36 )
+ .tickSize( -availableWidth, 0);
+ d3.transition(g.select('.nv-y.nv-axis'))
+ .call(yAxis);
+ }
//------------------------------------------------------------
@@ -1891,7 +2902,12 @@ nv.models.cumulativeLineChart = function() {
indexLine
.data([index]);
- container.call(chart);
+ //When dragging the index line, turn off line transitions.
+ // Then turn them back on when done dragging.
+ var oldDuration = chart.transitionDuration();
+ chart.transitionDuration(0);
+ chart.update();
+ chart.transitionDuration(oldDuration);
}
g.select('.nv-background rect')
@@ -1917,61 +2933,79 @@ nv.models.cumulativeLineChart = function() {
updateZero();
});
- controls.dispatch.on('legendClick', function(d,i) {
+ controls.dispatch.on('legendClick', function(d,i) {
d.disabled = !d.disabled;
rescaleY = !d.disabled;
state.rescaleY = rescaleY;
dispatch.stateChange(state);
-
- //selection.transition().call(chart);
chart.update();
});
- legend.dispatch.on('legendClick', function(d,i) {
- d.disabled = !d.disabled;
-
- if (!data.filter(function(d) { return !d.disabled }).length) {
- data.map(function(d) {
- d.disabled = false;
- wrap.selectAll('.nv-series').classed('disabled', false);
- return d;
- });
- }
-
- state.disabled = data.map(function(d) { return !!d.disabled });
+ legend.dispatch.on('stateChange', function(newState) {
+ state.disabled = newState.disabled;
dispatch.stateChange(state);
-
- //selection.transition().call(chart);
chart.update();
});
- legend.dispatch.on('legendDblclick', function(d) {
- //Double clicking should always enable current series, and disabled all others.
- data.forEach(function(d) {
- d.disabled = true;
+ interactiveLayer.dispatch.on('elementMousemove', function(e) {
+ lines.clearHighlights();
+ var singlePoint, pointIndex, pointXLocation, allData = [];
+
+
+ data
+ .filter(function(series, i) {
+ series.seriesIndex = i;
+ return !series.disabled;
+ })
+ .forEach(function(series,i) {
+ pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x());
+ lines.highlightPoint(i, pointIndex, true);
+ var point = series.values[pointIndex];
+ if (typeof point === 'undefined') return;
+ if (typeof singlePoint === 'undefined') singlePoint = point;
+ if (typeof pointXLocation === 'undefined') pointXLocation = chart.xScale()(chart.x()(point,pointIndex));
+ allData.push({
+ key: series.key,
+ value: chart.y()(point, pointIndex),
+ color: color(series,series.seriesIndex)
+ });
});
- d.disabled = false;
- state.disabled = data.map(function(d) { return !!d.disabled });
- dispatch.stateChange(state);
- chart.update();
- });
+ //Highlight the tooltip entry based on which point the mouse is closest to.
+ if (allData.length > 2) {
+ var yValue = chart.yScale().invert(e.mouseY);
+ var domainExtent = Math.abs(chart.yScale().domain()[0] - chart.yScale().domain()[1]);
+ var threshold = 0.03 * domainExtent;
+ var indexToHighlight = nv.nearestValueIndex(allData.map(function(d){return d.value}),yValue,threshold);
+ if (indexToHighlight !== null)
+ allData[indexToHighlight].highlight = true;
+ }
+ var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex), pointIndex);
+ interactiveLayer.tooltip
+ .position({left: pointXLocation + margin.left, top: e.mouseY + margin.top})
+ .chartContainer(that.parentNode)
+ .enabled(tooltips)
+ .valueFormatter(function(d,i) {
+ return yAxis.tickFormat()(d);
+ })
+ .data(
+ {
+ value: xValue,
+ series: allData
+ }
+ )();
+
+ interactiveLayer.renderGuideLine(pointXLocation);
-/*
- //
- legend.dispatch.on('legendMouseover', function(d, i) {
- d.hover = true;
- selection.transition().call(chart)
});
- legend.dispatch.on('legendMouseout', function(d, i) {
- d.hover = false;
- selection.transition().call(chart)
+ interactiveLayer.dispatch.on("elementMouseout",function(e) {
+ dispatch.tooltipHide();
+ lines.clearHighlights();
});
-*/
dispatch.on('tooltipShow', function(e) {
if (tooltips) showTooltip(e, that.parentNode);
@@ -2046,8 +3080,11 @@ nv.models.cumulativeLineChart = function() {
chart.legend = legend;
chart.xAxis = xAxis;
chart.yAxis = yAxis;
+ chart.interactiveLayer = interactiveLayer;
+
+ d3.rebind(chart, lines, 'defined', 'isArea', 'x', 'y', 'xScale','yScale', 'size', 'xDomain', 'yDomain', 'xRange', 'yRange', 'forceX', 'forceY', 'interactive', 'clipEdge', 'clipVoronoi','useVoronoi', 'id');
- d3.rebind(chart, lines, 'defined', 'isArea', 'x', 'y', 'size', 'xDomain', 'yDomain', 'forceX', 'forceY', 'interactive', 'clipEdge', 'clipVoronoi', 'id');
+ chart.options = nv.utils.optionsFunc.bind(chart);
chart.margin = function(_) {
if (!arguments.length) return margin;
@@ -2079,8 +3116,8 @@ nv.models.cumulativeLineChart = function() {
chart.rescaleY = function(_) {
if (!arguments.length) return rescaleY;
- rescaleY = _
- return rescaleY;
+ rescaleY = _;
+ return chart;
};
chart.showControls = function(_) {
@@ -2089,12 +3126,41 @@ nv.models.cumulativeLineChart = function() {
return chart;
};
+ chart.useInteractiveGuideline = function(_) {
+ if(!arguments.length) return useInteractiveGuideline;
+ useInteractiveGuideline = _;
+ if (_ === true) {
+ chart.interactive(false);
+ chart.useVoronoi(false);
+ }
+ return chart;
+ };
+
chart.showLegend = function(_) {
if (!arguments.length) return showLegend;
showLegend = _;
return chart;
};
+ chart.showXAxis = function(_) {
+ if (!arguments.length) return showXAxis;
+ showXAxis = _;
+ return chart;
+ };
+
+ chart.showYAxis = function(_) {
+ if (!arguments.length) return showYAxis;
+ showYAxis = _;
+ return chart;
+ };
+
+ chart.rightAlignYAxis = function(_) {
+ if(!arguments.length) return rightAlignYAxis;
+ rightAlignYAxis = _;
+ yAxis.orient( (_) ? 'right' : 'left');
+ return chart;
+ };
+
chart.tooltips = function(_) {
if (!arguments.length) return tooltips;
tooltips = _;
@@ -2131,6 +3197,18 @@ nv.models.cumulativeLineChart = function() {
return chart;
};
+ chart.transitionDuration = function(_) {
+ if (!arguments.length) return transitionDuration;
+ transitionDuration = _;
+ return chart;
+ };
+
+ chart.noErrorCheck = function(_) {
+ if (!arguments.length) return noErrorCheck;
+ noErrorCheck = _;
+ return chart;
+ };
+
//============================================================
@@ -2144,11 +3222,16 @@ nv.models.cumulativeLineChart = function() {
if (!line.values) {
return line;
}
- var v = lines.y()(line.values[idx], idx);
+ var indexValue = line.values[idx];
+ if (indexValue == null) {
+ return line;
+ }
+ var v = lines.y()(indexValue, idx);
//TODO: implement check below, and disable series if series loses 100% or more cause divide by 0 issue
- if (v < -.95) {
+ if (v < -.95 && !noErrorCheck) {
//if a series loses more than 100%, calculations fail.. anything close can cause major distortion (but is mathematically correct till it hits 100)
+
line.tempDisabled = true;
return line;
}
@@ -2171,7 +3254,7 @@ nv.models.cumulativeLineChart = function() {
}
//TODO: consider deprecating by adding necessary features to multiBar model
nv.models.discreteBar = function() {
-
+ "use strict";
//============================================================
// Public Variables with Default Settings
//------------------------------------------------------------
@@ -2190,6 +3273,8 @@ nv.models.discreteBar = function() {
, valueFormat = d3.format(',.2f')
, xDomain
, yDomain
+ , xRange
+ , yRange
, dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout')
, rectClass = 'discreteBar'
;
@@ -2214,12 +3299,10 @@ nv.models.discreteBar = function() {
//add series index to each data point for reference
- data = data.map(function(series, i) {
- series.values = series.values.map(function(point) {
+ data.forEach(function(series, i) {
+ series.values.forEach(function(point) {
point.series = i;
- return point;
});
- return series;
});
@@ -2235,14 +3318,14 @@ nv.models.discreteBar = function() {
});
x .domain(xDomain || d3.merge(seriesData).map(function(d) { return d.x }))
- .rangeBands([0, availableWidth], .1);
+ .rangeBands(xRange || [0, availableWidth], .1);
y .domain(yDomain || d3.extent(d3.merge(seriesData).map(function(d) { return d.y }).concat(forceY)));
// If showValues, pad the Y axis range to account for label height
- if (showValues) y.range([availableHeight - (y.domain()[0] < 0 ? 12 : 0), y.domain()[1] > 0 ? 12 : 0]);
- else y.range([availableHeight, 0]);
+ if (showValues) y.range(yRange || [availableHeight - (y.domain()[0] < 0 ? 12 : 0), y.domain()[1] > 0 ? 12 : 0]);
+ else y.range(yRange || [availableHeight, 0]);
//store old scales if they exist
x0 = x0 || x;
@@ -2273,14 +3356,16 @@ nv.models.discreteBar = function() {
groups.enter().append('g')
.style('stroke-opacity', 1e-6)
.style('fill-opacity', 1e-6);
- d3.transition(groups.exit())
+ groups.exit()
+ .transition()
.style('stroke-opacity', 1e-6)
.style('fill-opacity', 1e-6)
.remove();
groups
.attr('class', function(d,i) { return 'nv-group nv-series-' + i })
.classed('hover', function(d) { return d.hover });
- d3.transition(groups)
+ groups
+ .transition()
.style('stroke-opacity', 1)
.style('fill-opacity', .75);
@@ -2293,7 +3378,7 @@ nv.models.discreteBar = function() {
var barsEnter = bars.enter().append('g')
.attr('transform', function(d,i,j) {
- return 'translate(' + (x(getX(d,i)) + x.rangeBand() * .05 ) + ', ' + y(0) + ')'
+ return 'translate(' + (x(getX(d,i)) + x.rangeBand() * .05 ) + ', ' + y(0) + ')'
})
.on('mouseover', function(d,i) { //TODO: figure out why j works above, but not here
d3.select(this).classed('hover', true);
@@ -2350,10 +3435,15 @@ nv.models.discreteBar = function() {
if (showValues) {
barsEnter.append('text')
.attr('text-anchor', 'middle')
+ ;
+
bars.select('text')
+ .text(function(d,i) { return valueFormat(getY(d,i)) })
+ .transition()
.attr('x', x.rangeBand() * .9 / 2)
.attr('y', function(d,i) { return getY(d,i) < 0 ? y(getY(d,i)) - y(0) + 12 : -4 })
- .text(function(d,i) { return
<TRUNCATED>
[2/6] Updating d3 to v3.4.3 and nv.d3 to v1.1.15
Posted by de...@apache.org.
http://git-wip-us.apache.org/repos/asf/couchdb/blob/95d6d6b0/src/fauxton/assets/js/libs/d3.js
----------------------------------------------------------------------
diff --git a/src/fauxton/assets/js/libs/d3.js b/src/fauxton/assets/js/libs/d3.js
index 44fc0b0..b57c8d0 100644
--- a/src/fauxton/assets/js/libs/d3.js
+++ b/src/fauxton/assets/js/libs/d3.js
@@ -1,4 +1,223 @@
-(function() {
+!function() {
+ var d3 = {
+ version: "3.4.3"
+ };
+ if (!Date.now) Date.now = function() {
+ return +new Date();
+ };
+ var d3_arraySlice = [].slice, d3_array = function(list) {
+ return d3_arraySlice.call(list);
+ };
+ var d3_document = document, d3_documentElement = d3_document.documentElement, d3_window = window;
+ try {
+ d3_array(d3_documentElement.childNodes)[0].nodeType;
+ } catch (e) {
+ d3_array = function(list) {
+ var i = list.length, array = new Array(i);
+ while (i--) array[i] = list[i];
+ return array;
+ };
+ }
+ try {
+ d3_document.createElement("div").style.setProperty("opacity", 0, "");
+ } catch (error) {
+ var d3_element_prototype = d3_window.Element.prototype, d3_element_setAttribute = d3_element_prototype.setAttribute, d3_element_setAttributeNS = d3_element_prototype.setAttributeNS, d3_style_prototype = d3_window.CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty;
+ d3_element_prototype.setAttribute = function(name, value) {
+ d3_element_setAttribute.call(this, name, value + "");
+ };
+ d3_element_prototype.setAttributeNS = function(space, local, value) {
+ d3_element_setAttributeNS.call(this, space, local, value + "");
+ };
+ d3_style_prototype.setProperty = function(name, value, priority) {
+ d3_style_setProperty.call(this, name, value + "", priority);
+ };
+ }
+ d3.ascending = function(a, b) {
+ return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
+ };
+ d3.descending = function(a, b) {
+ return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
+ };
+ d3.min = function(array, f) {
+ var i = -1, n = array.length, a, b;
+ if (arguments.length === 1) {
+ while (++i < n && !((a = array[i]) != null && a <= a)) a = undefined;
+ while (++i < n) if ((b = array[i]) != null && a > b) a = b;
+ } else {
+ while (++i < n && !((a = f.call(array, array[i], i)) != null && a <= a)) a = undefined;
+ while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b;
+ }
+ return a;
+ };
+ d3.max = function(array, f) {
+ var i = -1, n = array.length, a, b;
+ if (arguments.length === 1) {
+ while (++i < n && !((a = array[i]) != null && a <= a)) a = undefined;
+ while (++i < n) if ((b = array[i]) != null && b > a) a = b;
+ } else {
+ while (++i < n && !((a = f.call(array, array[i], i)) != null && a <= a)) a = undefined;
+ while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b;
+ }
+ return a;
+ };
+ d3.extent = function(array, f) {
+ var i = -1, n = array.length, a, b, c;
+ if (arguments.length === 1) {
+ while (++i < n && !((a = c = array[i]) != null && a <= a)) a = c = undefined;
+ while (++i < n) if ((b = array[i]) != null) {
+ if (a > b) a = b;
+ if (c < b) c = b;
+ }
+ } else {
+ while (++i < n && !((a = c = f.call(array, array[i], i)) != null && a <= a)) a = undefined;
+ while (++i < n) if ((b = f.call(array, array[i], i)) != null) {
+ if (a > b) a = b;
+ if (c < b) c = b;
+ }
+ }
+ return [ a, c ];
+ };
+ d3.sum = function(array, f) {
+ var s = 0, n = array.length, a, i = -1;
+ if (arguments.length === 1) {
+ while (++i < n) if (!isNaN(a = +array[i])) s += a;
+ } else {
+ while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a;
+ }
+ return s;
+ };
+ function d3_number(x) {
+ return x != null && !isNaN(x);
+ }
+ d3.mean = function(array, f) {
+ var n = array.length, a, m = 0, i = -1, j = 0;
+ if (arguments.length === 1) {
+ while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j;
+ } else {
+ while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j;
+ }
+ return j ? m : undefined;
+ };
+ d3.quantile = function(values, p) {
+ var H = (values.length - 1) * p + 1, h = Math.floor(H), v = +values[h - 1], e = H - h;
+ return e ? v + e * (values[h] - v) : v;
+ };
+ d3.median = function(array, f) {
+ if (arguments.length > 1) array = array.map(f);
+ array = array.filter(d3_number);
+ return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined;
+ };
+ d3.bisector = function(f) {
+ return {
+ left: function(a, x, lo, hi) {
+ if (arguments.length < 3) lo = 0;
+ if (arguments.length < 4) hi = a.length;
+ while (lo < hi) {
+ var mid = lo + hi >>> 1;
+ if (f.call(a, a[mid], mid) < x) lo = mid + 1; else hi = mid;
+ }
+ return lo;
+ },
+ right: function(a, x, lo, hi) {
+ if (arguments.length < 3) lo = 0;
+ if (arguments.length < 4) hi = a.length;
+ while (lo < hi) {
+ var mid = lo + hi >>> 1;
+ if (x < f.call(a, a[mid], mid)) hi = mid; else lo = mid + 1;
+ }
+ return lo;
+ }
+ };
+ };
+ var d3_bisector = d3.bisector(function(d) {
+ return d;
+ });
+ d3.bisectLeft = d3_bisector.left;
+ d3.bisect = d3.bisectRight = d3_bisector.right;
+ d3.shuffle = function(array) {
+ var m = array.length, t, i;
+ while (m) {
+ i = Math.random() * m-- | 0;
+ t = array[m], array[m] = array[i], array[i] = t;
+ }
+ return array;
+ };
+ d3.permute = function(array, indexes) {
+ var i = indexes.length, permutes = new Array(i);
+ while (i--) permutes[i] = array[indexes[i]];
+ return permutes;
+ };
+ d3.pairs = function(array) {
+ var i = 0, n = array.length - 1, p0, p1 = array[0], pairs = new Array(n < 0 ? 0 : n);
+ while (i < n) pairs[i] = [ p0 = p1, p1 = array[++i] ];
+ return pairs;
+ };
+ d3.zip = function() {
+ if (!(n = arguments.length)) return [];
+ for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m; ) {
+ for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) {
+ zip[j] = arguments[j][i];
+ }
+ }
+ return zips;
+ };
+ function d3_zipLength(d) {
+ return d.length;
+ }
+ d3.transpose = function(matrix) {
+ return d3.zip.apply(d3, matrix);
+ };
+ d3.keys = function(map) {
+ var keys = [];
+ for (var key in map) keys.push(key);
+ return keys;
+ };
+ d3.values = function(map) {
+ var values = [];
+ for (var key in map) values.push(map[key]);
+ return values;
+ };
+ d3.entries = function(map) {
+ var entries = [];
+ for (var key in map) entries.push({
+ key: key,
+ value: map[key]
+ });
+ return entries;
+ };
+ d3.merge = function(arrays) {
+ var n = arrays.length, m, i = -1, j = 0, merged, array;
+ while (++i < n) j += arrays[i].length;
+ merged = new Array(j);
+ while (--n >= 0) {
+ array = arrays[n];
+ m = array.length;
+ while (--m >= 0) {
+ merged[--j] = array[m];
+ }
+ }
+ return merged;
+ };
+ var abs = Math.abs;
+ d3.range = function(start, stop, step) {
+ if (arguments.length < 3) {
+ step = 1;
+ if (arguments.length < 2) {
+ stop = start;
+ start = 0;
+ }
+ }
+ if ((stop - start) / step === Infinity) throw new Error("infinite range");
+ var range = [], k = d3_range_integerScale(abs(step)), i = -1, j;
+ start *= k, stop *= k, step *= k;
+ if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else while ((j = start + step * ++i) < stop) range.push(j / k);
+ return range;
+ };
+ function d3_range_integerScale(x) {
+ var k = 1;
+ while (x * k % 1) k *= 10;
+ return k;
+ }
function d3_class(ctor, properties) {
try {
for (var key in properties) {
@@ -11,60 +230,206 @@
ctor.prototype = properties;
}
}
- function d3_arrayCopy(pseudoarray) {
- var i = -1, n = pseudoarray.length, array = [];
- while (++i < n) array.push(pseudoarray[i]);
- return array;
+ d3.map = function(object) {
+ var map = new d3_Map();
+ if (object instanceof d3_Map) object.forEach(function(key, value) {
+ map.set(key, value);
+ }); else for (var key in object) map.set(key, object[key]);
+ return map;
+ };
+ function d3_Map() {}
+ d3_class(d3_Map, {
+ has: d3_map_has,
+ get: function(key) {
+ return this[d3_map_prefix + key];
+ },
+ set: function(key, value) {
+ return this[d3_map_prefix + key] = value;
+ },
+ remove: d3_map_remove,
+ keys: d3_map_keys,
+ values: function() {
+ var values = [];
+ this.forEach(function(key, value) {
+ values.push(value);
+ });
+ return values;
+ },
+ entries: function() {
+ var entries = [];
+ this.forEach(function(key, value) {
+ entries.push({
+ key: key,
+ value: value
+ });
+ });
+ return entries;
+ },
+ size: d3_map_size,
+ empty: d3_map_empty,
+ forEach: function(f) {
+ for (var key in this) if (key.charCodeAt(0) === d3_map_prefixCode) f.call(this, key.substring(1), this[key]);
+ }
+ });
+ var d3_map_prefix = "\x00", d3_map_prefixCode = d3_map_prefix.charCodeAt(0);
+ function d3_map_has(key) {
+ return d3_map_prefix + key in this;
}
- function d3_arraySlice(pseudoarray) {
- return Array.prototype.slice.call(pseudoarray);
+ function d3_map_remove(key) {
+ key = d3_map_prefix + key;
+ return key in this && delete this[key];
}
- function d3_Map() {}
- function d3_identity(d) {
- return d;
+ function d3_map_keys() {
+ var keys = [];
+ this.forEach(function(key) {
+ keys.push(key);
+ });
+ return keys;
}
- function d3_this() {
- return this;
+ function d3_map_size() {
+ var size = 0;
+ for (var key in this) if (key.charCodeAt(0) === d3_map_prefixCode) ++size;
+ return size;
}
- function d3_true() {
+ function d3_map_empty() {
+ for (var key in this) if (key.charCodeAt(0) === d3_map_prefixCode) return false;
return true;
}
- function d3_functor(v) {
- return typeof v === "function" ? v : function() {
- return v;
+ d3.nest = function() {
+ var nest = {}, keys = [], sortKeys = [], sortValues, rollup;
+ function map(mapType, array, depth) {
+ if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues ? array.sort(sortValues) : array;
+ var i = -1, n = array.length, key = keys[depth++], keyValue, object, setter, valuesByKey = new d3_Map(), values;
+ while (++i < n) {
+ if (values = valuesByKey.get(keyValue = key(object = array[i]))) {
+ values.push(object);
+ } else {
+ valuesByKey.set(keyValue, [ object ]);
+ }
+ }
+ if (mapType) {
+ object = mapType();
+ setter = function(keyValue, values) {
+ object.set(keyValue, map(mapType, values, depth));
+ };
+ } else {
+ object = {};
+ setter = function(keyValue, values) {
+ object[keyValue] = map(mapType, values, depth);
+ };
+ }
+ valuesByKey.forEach(setter);
+ return object;
+ }
+ function entries(map, depth) {
+ if (depth >= keys.length) return map;
+ var array = [], sortKey = sortKeys[depth++];
+ map.forEach(function(key, keyMap) {
+ array.push({
+ key: key,
+ values: entries(keyMap, depth)
+ });
+ });
+ return sortKey ? array.sort(function(a, b) {
+ return sortKey(a.key, b.key);
+ }) : array;
+ }
+ nest.map = function(array, mapType) {
+ return map(mapType, array, 0);
};
- }
- function d3_rebind(target, source, method) {
- return function() {
- var value = method.apply(source, arguments);
- return arguments.length ? target : value;
+ nest.entries = function(array) {
+ return entries(map(d3.map, array, 0), 0);
};
+ nest.key = function(d) {
+ keys.push(d);
+ return nest;
+ };
+ nest.sortKeys = function(order) {
+ sortKeys[keys.length - 1] = order;
+ return nest;
+ };
+ nest.sortValues = function(order) {
+ sortValues = order;
+ return nest;
+ };
+ nest.rollup = function(f) {
+ rollup = f;
+ return nest;
+ };
+ return nest;
+ };
+ d3.set = function(array) {
+ var set = new d3_Set();
+ if (array) for (var i = 0, n = array.length; i < n; ++i) set.add(array[i]);
+ return set;
+ };
+ function d3_Set() {}
+ d3_class(d3_Set, {
+ has: d3_map_has,
+ add: function(value) {
+ this[d3_map_prefix + value] = true;
+ return value;
+ },
+ remove: function(value) {
+ value = d3_map_prefix + value;
+ return value in this && delete this[value];
+ },
+ values: d3_map_keys,
+ size: d3_map_size,
+ empty: d3_map_empty,
+ forEach: function(f) {
+ for (var value in this) if (value.charCodeAt(0) === d3_map_prefixCode) f.call(this, value.substring(1));
+ }
+ });
+ d3.behavior = {};
+ d3.rebind = function(target, source) {
+ var i = 1, n = arguments.length, method;
+ while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]);
+ return target;
+ };
+ function d3_rebind(target, source, method) {
+ return function() {
+ var value = method.apply(source, arguments);
+ return value === source ? target : value;
+ };
+ }
+ function d3_vendorSymbol(object, name) {
+ if (name in object) return name;
+ name = name.charAt(0).toUpperCase() + name.substring(1);
+ for (var i = 0, n = d3_vendorPrefixes.length; i < n; ++i) {
+ var prefixName = d3_vendorPrefixes[i] + name;
+ if (prefixName in object) return prefixName;
+ }
}
- function d3_number(x) {
- return x != null && !isNaN(x);
- }
- function d3_zipLength(d) {
- return d.length;
- }
- function d3_splitter(d) {
- return d == null;
- }
- function d3_collapse(s) {
- return s.trim().replace(/\s+/g, " ");
- }
- function d3_range_integerScale(x) {
- var k = 1;
- while (x * k % 1) k *= 10;
- return k;
- }
+ var d3_vendorPrefixes = [ "webkit", "ms", "moz", "Moz", "o", "O" ];
+ function d3_noop() {}
+ d3.dispatch = function() {
+ var dispatch = new d3_dispatch(), i = -1, n = arguments.length;
+ while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
+ return dispatch;
+ };
function d3_dispatch() {}
+ d3_dispatch.prototype.on = function(type, listener) {
+ var i = type.indexOf("."), name = "";
+ if (i >= 0) {
+ name = type.substring(i + 1);
+ type = type.substring(0, i);
+ }
+ if (type) return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener);
+ if (arguments.length === 2) {
+ if (listener == null) for (type in this) {
+ if (this.hasOwnProperty(type)) this[type].on(name, null);
+ }
+ return this;
+ }
+ };
function d3_dispatch_event(dispatch) {
+ var listeners = [], listenerByName = new d3_Map();
function event() {
var z = listeners, i = -1, n = z.length, l;
while (++i < n) if (l = z[i].on) l.apply(this, arguments);
return dispatch;
}
- var listeners = [], listenerByName = new d3_Map;
event.on = function(name, listener) {
var l = listenerByName.get(name), i;
if (arguments.length < 2) return l && l.on;
@@ -80,82 +445,8 @@
};
return event;
}
- function d3_format_precision(x, p) {
- return p - (x ? 1 + Math.floor(Math.log(x + Math.pow(10, 1 + Math.floor(Math.log(x) / Math.LN10) - p)) / Math.LN10) : 1);
- }
- function d3_format_typeDefault(x) {
- return x + "";
- }
- function d3_format_group(value) {
- var i = value.lastIndexOf("."), f = i >= 0 ? value.substring(i) : (i = value.length, ""), t = [];
- while (i > 0) t.push(value.substring(i -= 3, i + 3));
- return t.reverse().join(",") + f;
- }
- function d3_formatPrefix(d, i) {
- var k = Math.pow(10, Math.abs(8 - i) * 3);
- return {
- scale: i > 8 ? function(d) {
- return d / k;
- } : function(d) {
- return d * k;
- },
- symbol: d
- };
- }
- function d3_ease_clamp(f) {
- return function(t) {
- return t <= 0 ? 0 : t >= 1 ? 1 : f(t);
- };
- }
- function d3_ease_reverse(f) {
- return function(t) {
- return 1 - f(1 - t);
- };
- }
- function d3_ease_reflect(f) {
- return function(t) {
- return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t));
- };
- }
- function d3_ease_identity(t) {
- return t;
- }
- function d3_ease_poly(e) {
- return function(t) {
- return Math.pow(t, e);
- };
- }
- function d3_ease_sin(t) {
- return 1 - Math.cos(t * Math.PI / 2);
- }
- function d3_ease_exp(t) {
- return Math.pow(2, 10 * (t - 1));
- }
- function d3_ease_circle(t) {
- return 1 - Math.sqrt(1 - t * t);
- }
- function d3_ease_elastic(a, p) {
- var s;
- if (arguments.length < 2) p = .45;
- if (arguments.length < 1) {
- a = 1;
- s = p / 4;
- } else s = p / (2 * Math.PI) * Math.asin(1 / a);
- return function(t) {
- return 1 + a * Math.pow(2, 10 * -t) * Math.sin((t - s) * 2 * Math.PI / p);
- };
- }
- function d3_ease_back(s) {
- if (!s) s = 1.70158;
- return function(t) {
- return t * t * ((s + 1) * t - s);
- };
- }
- function d3_ease_bounce(t) {
- return t < 1 / 2.75 ? 7.5625 * t * t : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375;
- }
- function d3_eventCancel() {
- d3.event.stopPropagation();
+ d3.event = null;
+ function d3_eventPreventDefault() {
d3.event.preventDefault();
}
function d3_eventSource() {
@@ -164,7 +455,7 @@
return e;
}
function d3_eventDispatch(target) {
- var dispatch = new d3_dispatch, i = 0, n = arguments.length;
+ var dispatch = new d3_dispatch(), i = 0, n = arguments.length;
while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
dispatch.of = function(thiz, argumentz) {
return function(e1) {
@@ -180,204 +471,114 @@
};
return dispatch;
}
- function d3_transform(m) {
- var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz = d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0;
- if (r0[0] * r1[1] < r1[0] * r0[1]) {
- r0[0] *= -1;
- r0[1] *= -1;
- kx *= -1;
- kz *= -1;
- }
- this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_transformDegrees;
- this.translate = [ m.e, m.f ];
- this.scale = [ kx, ky ];
- this.skew = ky ? Math.atan2(kz, ky) * d3_transformDegrees : 0;
- }
- function d3_transformDot(a, b) {
- return a[0] * b[0] + a[1] * b[1];
- }
- function d3_transformNormalize(a) {
- var k = Math.sqrt(d3_transformDot(a, a));
- if (k) {
- a[0] /= k;
- a[1] /= k;
- }
- return k;
- }
- function d3_transformCombine(a, b, k) {
- a[0] += k * b[0];
- a[1] += k * b[1];
- return a;
- }
- function d3_interpolateByName(name) {
- return name == "transform" ? d3.interpolateTransform : d3.interpolate;
+ d3.requote = function(s) {
+ return s.replace(d3_requote_re, "\\$&");
+ };
+ var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
+ var d3_subclass = {}.__proto__ ? function(object, prototype) {
+ object.__proto__ = prototype;
+ } : function(object, prototype) {
+ for (var property in prototype) object[property] = prototype[property];
+ };
+ function d3_selection(groups) {
+ d3_subclass(groups, d3_selectionPrototype);
+ return groups;
}
- function d3_uninterpolateNumber(a, b) {
- b = b - (a = +a) ? 1 / (b - a) : 0;
- return function(x) {
- return (x - a) * b;
+ var d3_select = function(s, n) {
+ return n.querySelector(s);
+ }, d3_selectAll = function(s, n) {
+ return n.querySelectorAll(s);
+ }, d3_selectMatcher = d3_documentElement[d3_vendorSymbol(d3_documentElement, "matchesSelector")], d3_selectMatches = function(n, s) {
+ return d3_selectMatcher.call(n, s);
+ };
+ if (typeof Sizzle === "function") {
+ d3_select = function(s, n) {
+ return Sizzle(s, n)[0] || null;
};
- }
- function d3_uninterpolateClamp(a, b) {
- b = b - (a = +a) ? 1 / (b - a) : 0;
- return function(x) {
- return Math.max(0, Math.min(1, (x - a) * b));
+ d3_selectAll = function(s, n) {
+ return Sizzle.uniqueSort(Sizzle(s, n));
};
+ d3_selectMatches = Sizzle.matchesSelector;
}
- function d3_Color() {}
- function d3_rgb(r, g, b) {
- return new d3_Rgb(r, g, b);
- }
- function d3_Rgb(r, g, b) {
- this.r = r;
- this.g = g;
- this.b = b;
- }
- function d3_rgb_hex(v) {
- return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16);
- }
- function d3_rgb_parse(format, rgb, hsl) {
- var r = 0, g = 0, b = 0, m1, m2, name;
- m1 = /([a-z]+)\((.*)\)/i.exec(format);
- if (m1) {
- m2 = m1[2].split(",");
- switch (m1[1]) {
- case "hsl":
- {
- return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100);
- }
- case "rgb":
- {
- return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2]));
+ d3.selection = function() {
+ return d3_selectionRoot;
+ };
+ var d3_selectionPrototype = d3.selection.prototype = [];
+ d3_selectionPrototype.select = function(selector) {
+ var subgroups = [], subgroup, subnode, group, node;
+ selector = d3_selection_selector(selector);
+ for (var j = -1, m = this.length; ++j < m; ) {
+ subgroups.push(subgroup = []);
+ subgroup.parentNode = (group = this[j]).parentNode;
+ for (var i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) {
+ subgroup.push(subnode = selector.call(node, node.__data__, i, j));
+ if (subnode && "__data__" in node) subnode.__data__ = node.__data__;
+ } else {
+ subgroup.push(null);
}
}
}
- if (name = d3_rgb_names.get(format)) return rgb(name.r, name.g, name.b);
- if (format != null && format.charAt(0) === "#") {
- if (format.length === 4) {
- r = format.charAt(1);
- r += r;
- g = format.charAt(2);
- g += g;
- b = format.charAt(3);
- b += b;
- } else if (format.length === 7) {
- r = format.substring(1, 3);
- g = format.substring(3, 5);
- b = format.substring(5, 7);
- }
- r = parseInt(r, 16);
- g = parseInt(g, 16);
- b = parseInt(b, 16);
- }
- return rgb(r, g, b);
+ return d3_selection(subgroups);
+ };
+ function d3_selection_selector(selector) {
+ return typeof selector === "function" ? selector : function() {
+ return d3_select(selector, this);
+ };
}
- function d3_rgb_hsl(r, g, b) {
- var min = Math.min(r /= 255, g /= 255, b /= 255), max = Math.max(r, g, b), d = max - min, h, s, l = (max + min) / 2;
- if (d) {
- s = l < .5 ? d / (max + min) : d / (2 - max - min);
- if (r == max) h = (g - b) / d + (g < b ? 6 : 0); else if (g == max) h = (b - r) / d + 2; else h = (r - g) / d + 4;
- h *= 60;
- } else {
- s = h = 0;
+ d3_selectionPrototype.selectAll = function(selector) {
+ var subgroups = [], subgroup, node;
+ selector = d3_selection_selectorAll(selector);
+ for (var j = -1, m = this.length; ++j < m; ) {
+ for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) {
+ subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i, j)));
+ subgroup.parentNode = node;
+ }
+ }
}
- return d3_hsl(h, s, l);
+ return d3_selection(subgroups);
+ };
+ function d3_selection_selectorAll(selector) {
+ return typeof selector === "function" ? selector : function() {
+ return d3_selectAll(selector, this);
+ };
}
- function d3_rgb_lab(r, g, b) {
- r = d3_rgb_xyz(r);
- g = d3_rgb_xyz(g);
- b = d3_rgb_xyz(b);
- var x = d3_xyz_lab((.4124564 * r + .3575761 * g + .1804375 * b) / d3_lab_X), y = d3_xyz_lab((.2126729 * r + .7151522 * g + .072175 * b) / d3_lab_Y), z = d3_xyz_lab((.0193339 * r + .119192 * g + .9503041 * b) / d3_lab_Z);
- return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z));
- }
- function d3_rgb_xyz(r) {
- return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4);
- }
- function d3_rgb_parseNumber(c) {
- var f = parseFloat(c);
- return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f;
- }
- function d3_hsl(h, s, l) {
- return new d3_Hsl(h, s, l);
- }
- function d3_Hsl(h, s, l) {
- this.h = h;
- this.s = s;
- this.l = l;
- }
- function d3_hsl_rgb(h, s, l) {
- function v(h) {
- if (h > 360) h -= 360; else if (h < 0) h += 360;
- if (h < 60) return m1 + (m2 - m1) * h / 60;
- if (h < 180) return m2;
- if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60;
- return m1;
+ var d3_nsPrefix = {
+ svg: "http://www.w3.org/2000/svg",
+ xhtml: "http://www.w3.org/1999/xhtml",
+ xlink: "http://www.w3.org/1999/xlink",
+ xml: "http://www.w3.org/XML/1998/namespace",
+ xmlns: "http://www.w3.org/2000/xmlns/"
+ };
+ d3.ns = {
+ prefix: d3_nsPrefix,
+ qualify: function(name) {
+ var i = name.indexOf(":"), prefix = name;
+ if (i >= 0) {
+ prefix = name.substring(0, i);
+ name = name.substring(i + 1);
+ }
+ return d3_nsPrefix.hasOwnProperty(prefix) ? {
+ space: d3_nsPrefix[prefix],
+ local: name
+ } : name;
}
- function vv(h) {
- return Math.round(v(h) * 255);
+ };
+ d3_selectionPrototype.attr = function(name, value) {
+ if (arguments.length < 2) {
+ if (typeof name === "string") {
+ var node = this.node();
+ name = d3.ns.qualify(name);
+ return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name);
+ }
+ for (value in name) this.each(d3_selection_attr(value, name[value]));
+ return this;
}
- var m1, m2;
- h = h % 360;
- if (h < 0) h += 360;
- s = s < 0 ? 0 : s > 1 ? 1 : s;
- l = l < 0 ? 0 : l > 1 ? 1 : l;
- m2 = l <= .5 ? l * (1 + s) : l + s - l * s;
- m1 = 2 * l - m2;
- return d3_rgb(vv(h + 120), vv(h), vv(h - 120));
- }
- function d3_hcl(h, c, l) {
- return new d3_Hcl(h, c, l);
- }
- function d3_Hcl(h, c, l) {
- this.h = h;
- this.c = c;
- this.l = l;
- }
- function d3_hcl_lab(h, c, l) {
- return d3_lab(l, Math.cos(h *= Math.PI / 180) * c, Math.sin(h) * c);
- }
- function d3_lab(l, a, b) {
- return new d3_Lab(l, a, b);
- }
- function d3_Lab(l, a, b) {
- this.l = l;
- this.a = a;
- this.b = b;
- }
- function d3_lab_rgb(l, a, b) {
- var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200;
- x = d3_lab_xyz(x) * d3_lab_X;
- y = d3_lab_xyz(y) * d3_lab_Y;
- z = d3_lab_xyz(z) * d3_lab_Z;
- return d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z), d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259 * y + 1.0572252 * z));
- }
- function d3_lab_hcl(l, a, b) {
- return d3_hcl(Math.atan2(b, a) / Math.PI * 180, Math.sqrt(a * a + b * b), l);
- }
- function d3_lab_xyz(x) {
- return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037;
- }
- function d3_xyz_lab(x) {
- return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29;
- }
- function d3_xyz_rgb(r) {
- return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055));
- }
- function d3_selection(groups) {
- d3_arraySubclass(groups, d3_selectionPrototype);
- return groups;
- }
- function d3_selection_selector(selector) {
- return function() {
- return d3_select(selector, this);
- };
- }
- function d3_selection_selectorAll(selector) {
- return function() {
- return d3_selectAll(selector, this);
- };
- }
+ return this.each(d3_selection_attr(name, value));
+ };
function d3_selection_attr(name, value) {
+ name = d3.ns.qualify(name);
function attrNull() {
this.removeAttribute(name);
}
@@ -398,13 +599,37 @@
var x = value.apply(this, arguments);
if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x);
}
- name = d3.ns.qualify(name);
return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant;
}
+ function d3_collapse(s) {
+ return s.trim().replace(/\s+/g, " ");
+ }
+ d3_selectionPrototype.classed = function(name, value) {
+ if (arguments.length < 2) {
+ if (typeof name === "string") {
+ var node = this.node(), n = (name = d3_selection_classes(name)).length, i = -1;
+ if (value = node.classList) {
+ while (++i < n) if (!value.contains(name[i])) return false;
+ } else {
+ value = node.getAttribute("class");
+ while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false;
+ }
+ return true;
+ }
+ for (value in name) this.each(d3_selection_classed(value, name[value]));
+ return this;
+ }
+ return this.each(d3_selection_classed(name, value));
+ };
function d3_selection_classedRe(name) {
return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g");
}
+ function d3_selection_classes(name) {
+ return name.trim().split(/^|\s+/);
+ }
function d3_selection_classed(name, value) {
+ name = d3_selection_classes(name).map(d3_selection_classedName);
+ var n = name.length;
function classedConstant() {
var i = -1;
while (++i < n) name[i](this, value);
@@ -413,27 +638,34 @@
var i = -1, x = value.apply(this, arguments);
while (++i < n) name[i](this, x);
}
- name = name.trim().split(/\s+/).map(d3_selection_classedName);
- var n = name.length;
return typeof value === "function" ? classedFunction : classedConstant;
}
function d3_selection_classedName(name) {
var re = d3_selection_classedRe(name);
return function(node, value) {
if (c = node.classList) return value ? c.add(name) : c.remove(name);
- var c = node.className, cb = c.baseVal != null, cv = cb ? c.baseVal : c;
+ var c = node.getAttribute("class") || "";
if (value) {
re.lastIndex = 0;
- if (!re.test(cv)) {
- cv = d3_collapse(cv + " " + name);
- if (cb) c.baseVal = cv; else node.className = cv;
- }
- } else if (cv) {
- cv = d3_collapse(cv.replace(re, " "));
- if (cb) c.baseVal = cv; else node.className = cv;
+ if (!re.test(c)) node.setAttribute("class", d3_collapse(c + " " + name));
+ } else {
+ node.setAttribute("class", d3_collapse(c.replace(re, " ")));
}
};
}
+ d3_selectionPrototype.style = function(name, value, priority) {
+ var n = arguments.length;
+ if (n < 3) {
+ if (typeof name !== "string") {
+ if (n < 2) value = "";
+ for (priority in name) this.each(d3_selection_style(priority, name[priority], value));
+ return this;
+ }
+ if (n < 2) return d3_window.getComputedStyle(this.node(), null).getPropertyValue(name);
+ priority = "";
+ }
+ return this.each(d3_selection_style(name, value, priority));
+ };
function d3_selection_style(name, value, priority) {
function styleNull() {
this.style.removeProperty(name);
@@ -447,6 +679,14 @@
}
return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant;
}
+ d3_selectionPrototype.property = function(name, value) {
+ if (arguments.length < 2) {
+ if (typeof name === "string") return this.node()[name];
+ for (value in name) this.each(d3_selection_property(value, name[value]));
+ return this;
+ }
+ return this.each(d3_selection_property(name, value));
+ };
function d3_selection_property(name, value) {
function propertyNull() {
delete this[name];
@@ -460,2648 +700,5021 @@
}
return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant;
}
- function d3_selection_dataNode(data) {
- return {
- __data__: data
- };
- }
- function d3_selection_filter(selector) {
- return function() {
- return d3_selectMatches(this, selector);
- };
- }
- function d3_selection_sortComparator(comparator) {
- if (!arguments.length) comparator = d3.ascending;
- return function(a, b) {
- return comparator(a && a.__data__, b && b.__data__);
+ d3_selectionPrototype.text = function(value) {
+ return arguments.length ? this.each(typeof value === "function" ? function() {
+ var v = value.apply(this, arguments);
+ this.textContent = v == null ? "" : v;
+ } : value == null ? function() {
+ this.textContent = "";
+ } : function() {
+ this.textContent = value;
+ }) : this.node().textContent;
+ };
+ d3_selectionPrototype.html = function(value) {
+ return arguments.length ? this.each(typeof value === "function" ? function() {
+ var v = value.apply(this, arguments);
+ this.innerHTML = v == null ? "" : v;
+ } : value == null ? function() {
+ this.innerHTML = "";
+ } : function() {
+ this.innerHTML = value;
+ }) : this.node().innerHTML;
+ };
+ d3_selectionPrototype.append = function(name) {
+ name = d3_selection_creator(name);
+ return this.select(function() {
+ return this.appendChild(name.apply(this, arguments));
+ });
+ };
+ function d3_selection_creator(name) {
+ return typeof name === "function" ? name : (name = d3.ns.qualify(name)).local ? function() {
+ return this.ownerDocument.createElementNS(name.space, name.local);
+ } : function() {
+ return this.ownerDocument.createElementNS(this.namespaceURI, name);
};
}
- function d3_selection_on(type, listener, capture) {
- function onRemove() {
- var wrapper = this[name];
- if (wrapper) {
- this.removeEventListener(type, wrapper, wrapper.$);
- delete this[name];
- }
- }
- function onAdd() {
- function wrapper(e) {
- var o = d3.event;
- d3.event = e;
- args[0] = node.__data__;
- try {
- listener.apply(node, args);
- } finally {
- d3.event = o;
+ d3_selectionPrototype.insert = function(name, before) {
+ name = d3_selection_creator(name);
+ before = d3_selection_selector(before);
+ return this.select(function() {
+ return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments) || null);
+ });
+ };
+ d3_selectionPrototype.remove = function() {
+ return this.each(function() {
+ var parent = this.parentNode;
+ if (parent) parent.removeChild(this);
+ });
+ };
+ d3_selectionPrototype.data = function(value, key) {
+ var i = -1, n = this.length, group, node;
+ if (!arguments.length) {
+ value = new Array(n = (group = this[0]).length);
+ while (++i < n) {
+ if (node = group[i]) {
+ value[i] = node.__data__;
}
}
- var node = this, args = arguments;
- onRemove.call(this);
- this.addEventListener(type, this[name] = wrapper, wrapper.$ = capture);
- wrapper._ = listener;
- }
- var name = "__on" + type, i = type.indexOf(".");
- if (i > 0) type = type.substring(0, i);
- return listener ? onAdd : onRemove;
- }
- function d3_selection_each(groups, callback) {
- for (var j = 0, m = groups.length; j < m; j++) {
- for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) {
- if (node = group[i]) callback(node, i, j);
- }
+ return value;
}
- return groups;
- }
- function d3_selection_enter(selection) {
- d3_arraySubclass(selection, d3_selection_enterPrototype);
- return selection;
- }
- function d3_transition(groups, id, time) {
- d3_arraySubclass(groups, d3_transitionPrototype);
- var tweens = new d3_Map, event = d3.dispatch("start", "end"), ease = d3_transitionEase;
- groups.id = id;
- groups.time = time;
- groups.tween = function(name, tween) {
- if (arguments.length < 2) return tweens.get(name);
- if (tween == null) tweens.remove(name); else tweens.set(name, tween);
- return groups;
- };
- groups.ease = function(value) {
- if (!arguments.length) return ease;
- ease = typeof value === "function" ? value : d3.ease.apply(d3, arguments);
- return groups;
- };
- groups.each = function(type, listener) {
- if (arguments.length < 2) return d3_transition_each.call(groups, type);
- event.on(type, listener);
- return groups;
- };
- d3.timer(function(elapsed) {
- return d3_selection_each(groups, function(node, i, j) {
- function start(elapsed) {
- if (lock.active > id) return stop();
- lock.active = id;
- tweens.forEach(function(key, value) {
- if (value = value.call(node, d, i)) {
- tweened.push(value);
- }
- });
- event.start.call(node, d, i);
- if (!tick(elapsed)) d3.timer(tick, 0, time);
- return 1;
+ function bind(group, groupData) {
+ var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), updateNodes = new Array(m), enterNodes = new Array(m), exitNodes = new Array(n), node, nodeData;
+ if (key) {
+ var nodeByKeyValue = new d3_Map(), dataByKeyValue = new d3_Map(), keyValues = [], keyValue;
+ for (i = -1; ++i < n; ) {
+ keyValue = key.call(node = group[i], node.__data__, i);
+ if (nodeByKeyValue.has(keyValue)) {
+ exitNodes[i] = node;
+ } else {
+ nodeByKeyValue.set(keyValue, node);
+ }
+ keyValues.push(keyValue);
}
- function tick(elapsed) {
- if (lock.active !== id) return stop();
- var t = (elapsed - delay) / duration, e = ease(t), n = tweened.length;
- while (n > 0) {
- tweened[--n].call(node, e);
+ for (i = -1; ++i < m; ) {
+ keyValue = key.call(groupData, nodeData = groupData[i], i);
+ if (node = nodeByKeyValue.get(keyValue)) {
+ updateNodes[i] = node;
+ node.__data__ = nodeData;
+ } else if (!dataByKeyValue.has(keyValue)) {
+ enterNodes[i] = d3_selection_dataNode(nodeData);
}
- if (t >= 1) {
- stop();
- d3_transitionId = id;
- event.end.call(node, d, i);
- d3_transitionId = 0;
- return 1;
+ dataByKeyValue.set(keyValue, nodeData);
+ nodeByKeyValue.remove(keyValue);
+ }
+ for (i = -1; ++i < n; ) {
+ if (nodeByKeyValue.has(keyValues[i])) {
+ exitNodes[i] = group[i];
}
}
- function stop() {
- if (!--lock.count) delete node.__transition__;
- return 1;
+ } else {
+ for (i = -1; ++i < n0; ) {
+ node = group[i];
+ nodeData = groupData[i];
+ if (node) {
+ node.__data__ = nodeData;
+ updateNodes[i] = node;
+ } else {
+ enterNodes[i] = d3_selection_dataNode(nodeData);
+ }
}
- var tweened = [], delay = node.delay, duration = node.duration, lock = (node = node.node).__transition__ || (node.__transition__ = {
- active: 0,
- count: 0
- }), d = node.__data__;
- ++lock.count;
- delay <= elapsed ? start(elapsed) : d3.timer(start, delay, time);
- });
- }, 0, time);
- return groups;
+ for (;i < m; ++i) {
+ enterNodes[i] = d3_selection_dataNode(groupData[i]);
+ }
+ for (;i < n; ++i) {
+ exitNodes[i] = group[i];
+ }
+ }
+ enterNodes.update = updateNodes;
+ enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode;
+ enter.push(enterNodes);
+ update.push(updateNodes);
+ exit.push(exitNodes);
+ }
+ var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]);
+ if (typeof value === "function") {
+ while (++i < n) {
+ bind(group = this[i], value.call(group, group.parentNode.__data__, i));
+ }
+ } else {
+ while (++i < n) {
+ bind(group = this[i], value);
+ }
+ }
+ update.enter = function() {
+ return enter;
+ };
+ update.exit = function() {
+ return exit;
+ };
+ return update;
+ };
+ function d3_selection_dataNode(data) {
+ return {
+ __data__: data
+ };
+ }
+ d3_selectionPrototype.datum = function(value) {
+ return arguments.length ? this.property("__data__", value) : this.property("__data__");
+ };
+ d3_selectionPrototype.filter = function(filter) {
+ var subgroups = [], subgroup, group, node;
+ if (typeof filter !== "function") filter = d3_selection_filter(filter);
+ for (var j = 0, m = this.length; j < m; j++) {
+ subgroups.push(subgroup = []);
+ subgroup.parentNode = (group = this[j]).parentNode;
+ for (var i = 0, n = group.length; i < n; i++) {
+ if ((node = group[i]) && filter.call(node, node.__data__, i, j)) {
+ subgroup.push(node);
+ }
+ }
+ }
+ return d3_selection(subgroups);
+ };
+ function d3_selection_filter(selector) {
+ return function() {
+ return d3_selectMatches(this, selector);
+ };
+ }
+ d3_selectionPrototype.order = function() {
+ for (var j = -1, m = this.length; ++j < m; ) {
+ for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) {
+ if (node = group[i]) {
+ if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next);
+ next = node;
+ }
+ }
+ }
+ return this;
+ };
+ d3_selectionPrototype.sort = function(comparator) {
+ comparator = d3_selection_sortComparator.apply(this, arguments);
+ for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator);
+ return this.order();
+ };
+ function d3_selection_sortComparator(comparator) {
+ if (!arguments.length) comparator = d3.ascending;
+ return function(a, b) {
+ return a && b ? comparator(a.__data__, b.__data__) : !a - !b;
+ };
}
- function d3_transition_each(callback) {
- var id = d3_transitionId, ease = d3_transitionEase, delay = d3_transitionDelay, duration = d3_transitionDuration;
- d3_transitionId = this.id;
- d3_transitionEase = this.ease();
- d3_selection_each(this, function(node, i, j) {
- d3_transitionDelay = node.delay;
- d3_transitionDuration = node.duration;
- callback.call(node = node.node, node.__data__, i, j);
+ d3_selectionPrototype.each = function(callback) {
+ return d3_selection_each(this, function(node, i, j) {
+ callback.call(node, node.__data__, i, j);
});
- d3_transitionId = id;
- d3_transitionEase = ease;
- d3_transitionDelay = delay;
- d3_transitionDuration = duration;
+ };
+ function d3_selection_each(groups, callback) {
+ for (var j = 0, m = groups.length; j < m; j++) {
+ for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) {
+ if (node = group[i]) callback(node, i, j);
+ }
+ }
+ return groups;
+ }
+ d3_selectionPrototype.call = function(callback) {
+ var args = d3_array(arguments);
+ callback.apply(args[0] = this, args);
return this;
+ };
+ d3_selectionPrototype.empty = function() {
+ return !this.node();
+ };
+ d3_selectionPrototype.node = function() {
+ for (var j = 0, m = this.length; j < m; j++) {
+ for (var group = this[j], i = 0, n = group.length; i < n; i++) {
+ var node = group[i];
+ if (node) return node;
+ }
+ }
+ return null;
+ };
+ d3_selectionPrototype.size = function() {
+ var n = 0;
+ this.each(function() {
+ ++n;
+ });
+ return n;
+ };
+ function d3_selection_enter(selection) {
+ d3_subclass(selection, d3_selection_enterPrototype);
+ return selection;
}
- function d3_tweenNull(d, i, a) {
- return a != "" && d3_tweenRemove;
+ var d3_selection_enterPrototype = [];
+ d3.selection.enter = d3_selection_enter;
+ d3.selection.enter.prototype = d3_selection_enterPrototype;
+ d3_selection_enterPrototype.append = d3_selectionPrototype.append;
+ d3_selection_enterPrototype.empty = d3_selectionPrototype.empty;
+ d3_selection_enterPrototype.node = d3_selectionPrototype.node;
+ d3_selection_enterPrototype.call = d3_selectionPrototype.call;
+ d3_selection_enterPrototype.size = d3_selectionPrototype.size;
+ d3_selection_enterPrototype.select = function(selector) {
+ var subgroups = [], subgroup, subnode, upgroup, group, node;
+ for (var j = -1, m = this.length; ++j < m; ) {
+ upgroup = (group = this[j]).update;
+ subgroups.push(subgroup = []);
+ subgroup.parentNode = group.parentNode;
+ for (var i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) {
+ subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i, j));
+ subnode.__data__ = node.__data__;
+ } else {
+ subgroup.push(null);
+ }
+ }
+ }
+ return d3_selection(subgroups);
+ };
+ d3_selection_enterPrototype.insert = function(name, before) {
+ if (arguments.length < 2) before = d3_selection_enterInsertBefore(this);
+ return d3_selectionPrototype.insert.call(this, name, before);
+ };
+ function d3_selection_enterInsertBefore(enter) {
+ var i0, j0;
+ return function(d, i, j) {
+ var group = enter[j].update, n = group.length, node;
+ if (j != j0) j0 = j, i0 = 0;
+ if (i >= i0) i0 = i + 1;
+ while (!(node = group[i0]) && ++i0 < n) ;
+ return node;
+ };
}
- function d3_tweenByName(b, name) {
- return d3.tween(b, d3_interpolateByName(name));
+ d3_selectionPrototype.transition = function() {
+ var id = d3_transitionInheritId || ++d3_transitionId, subgroups = [], subgroup, node, transition = d3_transitionInherit || {
+ time: Date.now(),
+ ease: d3_ease_cubicInOut,
+ delay: 0,
+ duration: 250
+ };
+ for (var j = -1, m = this.length; ++j < m; ) {
+ subgroups.push(subgroup = []);
+ for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) d3_transitionNode(node, i, id, transition);
+ subgroup.push(node);
+ }
+ }
+ return d3_transition(subgroups, id);
+ };
+ d3_selectionPrototype.interrupt = function() {
+ return this.each(d3_selection_interrupt);
+ };
+ function d3_selection_interrupt() {
+ var lock = this.__transition__;
+ if (lock) ++lock.active;
}
- function d3_timer_step() {
- var elapsed, now = Date.now(), t1 = d3_timer_queue;
- while (t1) {
- elapsed = now - t1.then;
- if (elapsed >= t1.delay) t1.flush = t1.callback(elapsed);
- t1 = t1.next;
+ d3.select = function(node) {
+ var group = [ typeof node === "string" ? d3_select(node, d3_document) : node ];
+ group.parentNode = d3_documentElement;
+ return d3_selection([ group ]);
+ };
+ d3.selectAll = function(nodes) {
+ var group = d3_array(typeof nodes === "string" ? d3_selectAll(nodes, d3_document) : nodes);
+ group.parentNode = d3_documentElement;
+ return d3_selection([ group ]);
+ };
+ var d3_selectionRoot = d3.select(d3_documentElement);
+ d3_selectionPrototype.on = function(type, listener, capture) {
+ var n = arguments.length;
+ if (n < 3) {
+ if (typeof type !== "string") {
+ if (n < 2) listener = false;
+ for (capture in type) this.each(d3_selection_on(capture, type[capture], listener));
+ return this;
+ }
+ if (n < 2) return (n = this.node()["__on" + type]) && n._;
+ capture = false;
}
- var delay = d3_timer_flush() - now;
- if (delay > 24) {
- if (isFinite(delay)) {
- clearTimeout(d3_timer_timeout);
- d3_timer_timeout = setTimeout(d3_timer_step, delay);
+ return this.each(d3_selection_on(type, listener, capture));
+ };
+ function d3_selection_on(type, listener, capture) {
+ var name = "__on" + type, i = type.indexOf("."), wrap = d3_selection_onListener;
+ if (i > 0) type = type.substring(0, i);
+ var filter = d3_selection_onFilters.get(type);
+ if (filter) type = filter, wrap = d3_selection_onFilter;
+ function onRemove() {
+ var l = this[name];
+ if (l) {
+ this.removeEventListener(type, l, l.$);
+ delete this[name];
}
- d3_timer_interval = 0;
- } else {
- d3_timer_interval = 1;
- d3_timer_frame(d3_timer_step);
}
+ function onAdd() {
+ var l = wrap(listener, d3_array(arguments));
+ onRemove.call(this);
+ this.addEventListener(type, this[name] = l, l.$ = capture);
+ l._ = listener;
+ }
+ function removeAll() {
+ var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"), match;
+ for (var name in this) {
+ if (match = name.match(re)) {
+ var l = this[name];
+ this.removeEventListener(match[1], l, l.$);
+ delete this[name];
+ }
+ }
+ }
+ return i ? listener ? onAdd : onRemove : listener ? d3_noop : removeAll;
}
- function d3_timer_flush() {
- var t0 = null, t1 = d3_timer_queue, then = Infinity;
- while (t1) {
- if (t1.flush) {
- delete d3_timer_byId[t1.callback.id];
- t1 = t0 ? t0.next = t1.next : d3_timer_queue = t1.next;
- } else {
- then = Math.min(then, t1.then + t1.delay);
- t1 = (t0 = t1).next;
+ var d3_selection_onFilters = d3.map({
+ mouseenter: "mouseover",
+ mouseleave: "mouseout"
+ });
+ d3_selection_onFilters.forEach(function(k) {
+ if ("on" + k in d3_document) d3_selection_onFilters.remove(k);
+ });
+ function d3_selection_onListener(listener, argumentz) {
+ return function(e) {
+ var o = d3.event;
+ d3.event = e;
+ argumentz[0] = this.__data__;
+ try {
+ listener.apply(this, argumentz);
+ } finally {
+ d3.event = o;
+ }
+ };
+ }
+ function d3_selection_onFilter(listener, argumentz) {
+ var l = d3_selection_onListener(listener, argumentz);
+ return function(e) {
+ var target = this, related = e.relatedTarget;
+ if (!related || related !== target && !(related.compareDocumentPosition(target) & 8)) {
+ l.call(target, e);
}
+ };
+ }
+ var d3_event_dragSelect = "onselectstart" in d3_document ? null : d3_vendorSymbol(d3_documentElement.style, "userSelect"), d3_event_dragId = 0;
+ function d3_event_dragSuppress() {
+ var name = ".dragsuppress-" + ++d3_event_dragId, click = "click" + name, w = d3.select(d3_window).on("touchmove" + name, d3_eventPreventDefault).on("dragstart" + name, d3_eventPreventDefault).on("selectstart" + name, d3_eventPreventDefault);
+ if (d3_event_dragSelect) {
+ var style = d3_documentElement.style, select = style[d3_event_dragSelect];
+ style[d3_event_dragSelect] = "none";
}
- return then;
+ return function(suppressClick) {
+ w.on(name, null);
+ if (d3_event_dragSelect) style[d3_event_dragSelect] = select;
+ if (suppressClick) {
+ function off() {
+ w.on(click, null);
+ }
+ w.on(click, function() {
+ d3_eventPreventDefault();
+ off();
+ }, true);
+ setTimeout(off, 0);
+ }
+ };
}
+ d3.mouse = function(container) {
+ return d3_mousePoint(container, d3_eventSource());
+ };
+ var d3_mouse_bug44083 = /WebKit/.test(d3_window.navigator.userAgent) ? -1 : 0;
function d3_mousePoint(container, e) {
+ if (e.changedTouches) e = e.changedTouches[0];
var svg = container.ownerSVGElement || container;
if (svg.createSVGPoint) {
var point = svg.createSVGPoint();
- if (d3_mouse_bug44083 < 0 && (window.scrollX || window.scrollY)) {
- svg = d3.select(document.body).append("svg").style("position", "absolute").style("top", 0).style("left", 0);
+ if (d3_mouse_bug44083 < 0 && (d3_window.scrollX || d3_window.scrollY)) {
+ svg = d3.select("body").append("svg").style({
+ position: "absolute",
+ top: 0,
+ left: 0,
+ margin: 0,
+ padding: 0,
+ border: "none"
+ }, "important");
var ctm = svg[0][0].getScreenCTM();
d3_mouse_bug44083 = !(ctm.f || ctm.e);
svg.remove();
}
- if (d3_mouse_bug44083) {
- point.x = e.pageX;
- point.y = e.pageY;
- } else {
- point.x = e.clientX;
- point.y = e.clientY;
- }
+ if (d3_mouse_bug44083) point.x = e.pageX, point.y = e.pageY; else point.x = e.clientX,
+ point.y = e.clientY;
point = point.matrixTransform(container.getScreenCTM().inverse());
return [ point.x, point.y ];
}
var rect = container.getBoundingClientRect();
return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ];
}
- function d3_noop() {}
- function d3_scaleExtent(domain) {
- var start = domain[0], stop = domain[domain.length - 1];
- return start < stop ? [ start, stop ] : [ stop, start ];
- }
- function d3_scaleRange(scale) {
- return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range());
- }
- function d3_scale_nice(domain, nice) {
- var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx;
- if (x1 < x0) {
- dx = i0, i0 = i1, i1 = dx;
- dx = x0, x0 = x1, x1 = dx;
- }
- if (nice = nice(x1 - x0)) {
- domain[i0] = nice.floor(x0);
- domain[i1] = nice.ceil(x1);
+ d3.touches = function(container, touches) {
+ if (arguments.length < 2) touches = d3_eventSource().touches;
+ return touches ? d3_array(touches).map(function(touch) {
+ var point = d3_mousePoint(container, touch);
+ point.identifier = touch.identifier;
+ return point;
+ }) : [];
+ };
+ d3.behavior.drag = function() {
+ var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), origin = null, mousedown = dragstart(d3_noop, d3.mouse, "mousemove", "mouseup"), touchstart = dragstart(touchid, touchposition, "touchmove", "touchend");
+ function drag() {
+ this.on("mousedown.drag", mousedown).on("touchstart.drag", touchstart);
}
- return domain;
- }
- function d3_scale_niceDefault() {
- return Math;
- }
- function d3_scale_linear(domain, range, interpolate, clamp) {
- function rescale() {
- var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber;
- output = linear(domain, range, uninterpolate, interpolate);
- input = linear(range, domain, uninterpolate, d3.interpolate);
- return scale;
+ function touchid() {
+ return d3.event.changedTouches[0].identifier;
}
- function scale(x) {
- return output(x);
+ function touchposition(parent, id) {
+ return d3.touches(parent).filter(function(p) {
+ return p.identifier === id;
+ })[0];
}
- var output, input;
- scale.invert = function(y) {
- return input(y);
- };
- scale.domain = function(x) {
- if (!arguments.length) return domain;
- domain = x.map(Number);
- return rescale();
- };
- scale.range = function(x) {
- if (!arguments.length) return range;
- range = x;
- return rescale();
- };
- scale.rangeRound = function(x) {
- return scale.range(x).interpolate(d3.interpolateRound);
- };
- scale.clamp = function(x) {
- if (!arguments.length) return clamp;
- clamp = x;
- return rescale();
- };
- scale.interpolate = function(x) {
- if (!arguments.length) return interpolate;
- interpolate = x;
- return rescale();
- };
- scale.ticks = function(m) {
- return d3_scale_linearTicks(domain, m);
- };
- scale.tickFormat = function(m) {
- return d3_scale_linearTickFormat(domain, m);
- };
- scale.nice = function() {
- d3_scale_nice(domain, d3_scale_linearNice);
- return rescale();
- };
- scale.copy = function() {
- return d3_scale_linear(domain, range, interpolate, clamp);
+ function dragstart(id, position, move, end) {
+ return function() {
+ var target = this, parent = target.parentNode, event_ = event.of(target, arguments), eventTarget = d3.event.target, eventId = id(), drag = eventId == null ? "drag" : "drag-" + eventId, origin_ = position(parent, eventId), dragged = 0, offset, w = d3.select(d3_window).on(move + "." + drag, moved).on(end + "." + drag, ended), dragRestore = d3_event_dragSuppress();
+ if (origin) {
+ offset = origin.apply(target, arguments);
+ offset = [ offset.x - origin_[0], offset.y - origin_[1] ];
+ } else {
+ offset = [ 0, 0 ];
+ }
+ event_({
+ type: "dragstart"
+ });
+ function moved() {
+ var p = position(parent, eventId), dx = p[0] - origin_[0], dy = p[1] - origin_[1];
+ dragged |= dx | dy;
+ origin_ = p;
+ event_({
+ type: "drag",
+ x: p[0] + offset[0],
+ y: p[1] + offset[1],
+ dx: dx,
+ dy: dy
+ });
+ }
+ function ended() {
+ w.on(move + "." + drag, null).on(end + "." + drag, null);
+ dragRestore(dragged && d3.event.target === eventTarget);
+ event_({
+ type: "dragend"
+ });
+ }
+ };
+ }
+ drag.origin = function(x) {
+ if (!arguments.length) return origin;
+ origin = x;
+ return drag;
};
- return rescale();
+ return d3.rebind(drag, event, "on");
+ };
+ var π = Math.PI, τ = 2 * π, halfπ = π / 2, ε = 1e-6, ε2 = ε * ε, d3_radians = π / 180, d3_degrees = 180 / π;
+ function d3_sgn(x) {
+ return x > 0 ? 1 : x < 0 ? -1 : 0;
}
- function d3_scale_linearRebind(scale, linear) {
- return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp");
+ function d3_cross2d(a, b, c) {
+ return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
}
- function d3_scale_linearNice(dx) {
- dx = Math.pow(10, Math.round(Math.log(dx) / Math.LN10) - 1);
- return dx && {
- floor: function(x) {
- return Math.floor(x / dx) * dx;
- },
- ceil: function(x) {
- return Math.ceil(x / dx) * dx;
- }
- };
+ function d3_acos(x) {
+ return x > 1 ? 0 : x < -1 ? π : Math.acos(x);
}
- function d3_scale_linearTickRange(domain, m) {
- var extent = d3_scaleExtent(domain), span = extent[1] - extent[0], step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), err = m / span * step;
- if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <= .75) step *= 2;
- extent[0] = Math.ceil(extent[0] / step) * step;
- extent[1] = Math.floor(extent[1] / step) * step + step * .5;
- extent[2] = step;
- return extent;
+ function d3_asin(x) {
+ return x > 1 ? halfπ : x < -1 ? -halfπ : Math.asin(x);
}
- function d3_scale_linearTicks(domain, m) {
- return d3.range.apply(d3, d3_scale_linearTickRange(domain, m));
+ function d3_sinh(x) {
+ return ((x = Math.exp(x)) - 1 / x) / 2;
}
- function d3_scale_linearTickFormat(domain, m) {
- return d3.format(",." + Math.max(0, -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01)) + "f");
+ function d3_cosh(x) {
+ return ((x = Math.exp(x)) + 1 / x) / 2;
}
- function d3_scale_bilinear(domain, range, uninterpolate, interpolate) {
- var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]);
- return function(x) {
- return i(u(x));
- };
+ function d3_tanh(x) {
+ return ((x = Math.exp(2 * x)) - 1) / (x + 1);
}
- function d3_scale_polylinear(domain, range, uninterpolate, interpolate) {
- var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1;
- if (domain[k] < domain[0]) {
- domain = domain.slice().reverse();
- range = range.slice().reverse();
- }
- while (++j <= k) {
- u.push(uninterpolate(domain[j - 1], domain[j]));
- i.push(interpolate(range[j - 1], range[j]));
- }
- return function(x) {
- var j = d3.bisect(domain, x, 1, k) - 1;
- return i[j](u[j](x));
- };
+ function d3_haversin(x) {
+ return (x = Math.sin(x / 2)) * x;
}
- function d3_scale_log(linear, log) {
- function scale(x) {
- return linear(log(x));
+ var ρ = Math.SQRT2, ρ2 = 2, ρ4 = 4;
+ d3.interpolateZoom = function(p0, p1) {
+ var ux0 = p0[0], uy0 = p0[1], w0 = p0[2], ux1 = p1[0], uy1 = p1[1], w1 = p1[2];
+ var dx = ux1 - ux0, dy = uy1 - uy0, d2 = dx * dx + dy * dy, d1 = Math.sqrt(d2), b0 = (w1 * w1 - w0 * w0 + ρ4 * d2) / (2 * w0 * ρ2 * d1), b1 = (w1 * w1 - w0 * w0 - ρ4 * d2) / (2 * w1 * ρ2 * d1), r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0), r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1), dr = r1 - r0, S = (dr || Math.log(w1 / w0)) / ρ;
+ function interpolate(t) {
+ var s = t * S;
+ if (dr) {
+ var coshr0 = d3_cosh(r0), u = w0 / (ρ2 * d1) * (coshr0 * d3_tanh(ρ * s + r0) - d3_sinh(r0));
+ return [ ux0 + u * dx, uy0 + u * dy, w0 * coshr0 / d3_cosh(ρ * s + r0) ];
+ }
+ return [ ux0 + t * dx, uy0 + t * dy, w0 * Math.exp(ρ * s) ];
}
- var pow = log.pow;
- scale.invert = function(x) {
- return pow(linear.invert(x));
- };
- scale.domain = function(x) {
- if (!arguments.length) return linear.domain().map(pow);
- log = x[0] < 0 ? d3_scale_logn : d3_scale_logp;
- pow = log.pow;
- linear.domain(x.map(log));
- return scale;
- };
- scale.nice = function() {
- linear.domain(d3_scale_nice(linear.domain(), d3_scale_niceDefault));
- return scale;
- };
- scale.ticks = function() {
- var extent = d3_scaleExtent(linear.domain()), ticks = [];
- if (extent.every(isFinite)) {
- var i = Math.floor(extent[0]), j = Math.ceil(extent[1]), u = pow(extent[0]), v = pow(extent[1]);
- if (log === d3_scale_logn) {
- ticks.push(pow(i));
- for (; i++ < j; ) for (var k = 9; k > 0; k--) ticks.push(pow(i) * k);
+ interpolate.duration = S * 1e3;
+ return interpolate;
+ };
+ d3.behavior.zoom = function() {
+ var view = {
+ x: 0,
+ y: 0,
+ k: 1
+ }, translate0, center, size = [ 960, 500 ], scaleExtent = d3_behavior_zoomInfinity, mousedown = "mousedown.zoom", mousemove = "mousemove.zoom", mouseup = "mouseup.zoom", mousewheelTimer, touchstart = "touchstart.zoom", touchtime, event = d3_eventDispatch(zoom, "zoomstart", "zoom", "zoomend"), x0, x1, y0, y1;
+ function zoom(g) {
+ g.on(mousedown, mousedowned).on(d3_behavior_zoomWheel + ".zoom", mousewheeled).on(mousemove, mousewheelreset).on("dblclick.zoom", dblclicked).on(touchstart, touchstarted);
+ }
+ zoom.event = function(g) {
+ g.each(function() {
+ var event_ = event.of(this, arguments), view1 = view;
+ if (d3_transitionInheritId) {
+ d3.select(this).transition().each("start.zoom", function() {
+ view = this.__chart__ || {
+ x: 0,
+ y: 0,
+ k: 1
+ };
+ zoomstarted(event_);
+ }).tween("zoom:zoom", function() {
+ var dx = size[0], dy = size[1], cx = dx / 2, cy = dy / 2, i = d3.interpolateZoom([ (cx - view.x) / view.k, (cy - view.y) / view.k, dx / view.k ], [ (cx - view1.x) / view1.k, (cy - view1.y) / view1.k, dx / view1.k ]);
+ return function(t) {
+ var l = i(t), k = dx / l[2];
+ this.__chart__ = view = {
+ x: cx - l[0] * k,
+ y: cy - l[1] * k,
+ k: k
+ };
+ zoomed(event_);
+ };
+ }).each("end.zoom", function() {
+ zoomended(event_);
+ });
} else {
- for (; i < j; i++) for (var k = 1; k < 10; k++) ticks.push(pow(i) * k);
- ticks.push(pow(i));
+ this.__chart__ = view;
+ zoomstarted(event_);
+ zoomed(event_);
+ zoomended(event_);
}
- for (i = 0; ticks[i] < u; i++) {}
- for (j = ticks.length; ticks[j - 1] > v; j--) {}
- ticks = ticks.slice(i, j);
- }
- return ticks;
- };
- scale.tickFormat = function(n, format) {
- if (arguments.length < 2) format = d3_scale_logFormat;
- if (arguments.length < 1) return format;
- var k = Math.max(.1, n / scale.ticks().length), f = log === d3_scale_logn ? (e = -1e-12, Math.floor) : (e = 1e-12, Math.ceil), e;
- return function(d) {
- return d / pow(f(log(d) + e)) <= k ? format(d) : "";
- };
- };
- scale.copy = function() {
- return d3_scale_log(linear.copy(), log);
- };
- return d3_scale_linearRebind(scale, linear);
- }
- function d3_scale_logp(x) {
- return Math.log(x < 0 ? 0 : x) / Math.LN10;
- }
- function d3_scale_logn(x) {
- return -Math.log(x > 0 ? 0 : -x) / Math.LN10;
- }
- function d3_scale_pow(linear, exponent) {
- function scale(x) {
- return linear(powp(x));
- }
- var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent);
- scale.invert = function(x) {
- return powb(linear.invert(x));
- };
- scale.domain = function(x) {
- if (!arguments.length) return linear.domain().map(powb);
- linear.domain(x.map(powp));
- return scale;
- };
- scale.ticks = function(m) {
- return d3_scale_linearTicks(scale.domain(), m);
- };
- scale.tickFormat = function(m) {
- return d3_scale_linearTickFormat(scale.domain(), m);
- };
- scale.nice = function() {
- return scale.domain(d3_scale_nice(scale.domain(), d3_scale_linearNice));
- };
- scale.exponent = function(x) {
- if (!arguments.length) return exponent;
- var domain = scale.domain();
- powp = d3_scale_powPow(exponent = x);
- powb = d3_scale_powPow(1 / exponent);
- return scale.domain(domain);
- };
- scale.copy = function() {
- return d3_scale_pow(linear.copy(), exponent);
- };
- return d3_scale_linearRebind(scale, linear);
- }
- function d3_scale_powPow(e) {
- return function(x) {
- return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e);
- };
- }
- function d3_scale_ordinal(domain, ranger) {
- function scale(x) {
- return range[((index.get(x) || index.set(x, domain.push(x))) - 1) % range.length];
- }
- function steps(start, step) {
- return d3.range(domain.length).map(function(i) {
- return start + step * i;
});
- }
- var index, range, rangeBand;
- scale.domain = function(x) {
- if (!arguments.length) return domain;
- domain = [];
- index = new d3_Map;
- var i = -1, n = x.length, xi;
- while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi));
- return scale[ranger.t].apply(scale, ranger.a);
};
- scale.range = function(x) {
- if (!arguments.length) return range;
- range = x;
- rangeBand = 0;
- ranger = {
- t: "range",
- a: arguments
+ zoom.translate = function(_) {
+ if (!arguments.length) return [ view.x, view.y ];
+ view = {
+ x: +_[0],
+ y: +_[1],
+ k: view.k
};
- return scale;
+ rescale();
+ return zoom;
};
- scale.rangePoints = function(x, padding) {
- if (arguments.length < 2) padding = 0;
- var start = x[0], stop = x[1], step = (stop - start) / (Math.max(1, domain.length - 1) + padding);
- range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step);
- rangeBand = 0;
- ranger = {
- t: "rangePoints",
- a: arguments
+ zoom.scale = function(_) {
+ if (!arguments.length) return view.k;
+ view = {
+ x: view.x,
+ y: view.y,
+ k: +_
};
- return scale;
+ rescale();
+ return zoom;
};
- scale.rangeBands = function(x, padding, outerPadding) {
- if (arguments.length < 2) padding = 0;
- if (arguments.length < 3) outerPadding = padding;
- var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = (stop - start) / (domain.length - padding + 2 * outerPadding);
- range = steps(start + step * outerPadding, step);
- if (reverse) range.reverse();
- rangeBand = step * (1 - padding);
- ranger = {
- t: "rangeBands",
- a: arguments
- };
- return scale;
+ zoom.scaleExtent = function(_) {
+ if (!arguments.length) return scaleExtent;
+ scaleExtent = _ == null ? d3_behavior_zoomInfinity : [ +_[0], +_[1] ];
+ return zoom;
};
- scale.rangeRoundBands = function(x, padding, outerPadding) {
- if (arguments.length < 2) padding = 0;
- if (arguments.length < 3) outerPadding = padding;
- var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)), error = stop - start - (domain.length - padding) * step;
- range = steps(start + Math.round(error / 2), step);
- if (reverse) range.reverse();
- rangeBand = Math.round(step * (1 - padding));
- ranger = {
- t: "rangeRoundBands",
- a: arguments
- };
- return scale;
+ zoom.center = function(_) {
+ if (!arguments.length) return center;
+ center = _ && [ +_[0], +_[1] ];
+ return zoom;
};
- scale.rangeBand = function() {
- return rangeBand;
+ zoom.size = function(_) {
+ if (!arguments.length) return size;
+ size = _ && [ +_[0], +_[1] ];
+ return zoom;
};
- scale.rangeExtent = function() {
- return d3_scaleExtent(ranger.a[0]);
+ zoom.x = function(z) {
+ if (!arguments.length) return x1;
+ x1 = z;
+ x0 = z.copy();
+ view = {
+ x: 0,
+ y: 0,
+ k: 1
+ };
+ return zoom;
};
- scale.copy = function() {
- return d3_scale_ordinal(domain, ranger);
+ zoom.y = function(z) {
+ if (!arguments.length) return y1;
+ y1 = z;
+ y0 = z.copy();
+ view = {
+ x: 0,
+ y: 0,
+ k: 1
+ };
+ return zoom;
};
- return scale.domain(domain);
- }
- function d3_scale_quantile(domain, range) {
+ function location(p) {
+ return [ (p[0] - view.x) / view.k, (p[1] - view.y) / view.k ];
+ }
+ function point(l) {
+ return [ l[0] * view.k + view.x, l[1] * view.k + view.y ];
+ }
+ function scaleTo(s) {
+ view.k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s));
+ }
+ function translateTo(p, l) {
+ l = point(l);
+ view.x += p[0] - l[0];
+ view.y += p[1] - l[1];
+ }
function rescale() {
- var k = 0, n = domain.length, q = range.length;
- thresholds = [];
- while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q);
- return scale;
+ if (x1) x1.domain(x0.range().map(function(x) {
+ return (x - view.x) / view.k;
+ }).map(x0.invert));
+ if (y1) y1.domain(y0.range().map(function(y) {
+ return (y - view.y) / view.k;
+ }).map(y0.invert));
}
- function scale(x) {
- if (isNaN(x = +x)) return NaN;
- return range[d3.bisect(thresholds, x)];
+ function zoomstarted(event) {
+ event({
+ type: "zoomstart"
+ });
}
- var thresholds;
- scale.domain = function(x) {
- if (!arguments.length) return domain;
- domain = x.filter(function(d) {
- return !isNaN(d);
- }).sort(d3.ascending);
- return rescale();
- };
- scale.range = function(x) {
- if (!arguments.length) return range;
- range = x;
- return rescale();
- };
- scale.quantiles = function() {
- return thresholds;
- };
- scale.copy = function() {
- return d3_scale_quantile(domain, range);
- };
- return rescale();
- }
- function d3_scale_quantize(x0, x1, range) {
- function scale(x) {
- return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))];
- }
- function rescale() {
- kx = range.length / (x1 - x0);
- i = range.length - 1;
- return scale;
- }
- var kx, i;
- scale.domain = function(x) {
- if (!arguments.length) return [ x0, x1 ];
- x0 = +x[0];
- x1 = +x[x.length - 1];
- return rescale();
- };
- scale.range = function(x) {
- if (!arguments.length) return range;
- range = x;
- return rescale();
- };
- scale.copy = function() {
- return d3_scale_quantize(x0, x1, range);
- };
- return rescale();
- }
- function d3_scale_threshold(domain, range) {
- function scale(x) {
- return range[d3.bisect(domain, x)];
+ function zoomed(event) {
+ rescale();
+ event({
+ type: "zoom",
+ scale: view.k,
+ translate: [ view.x, view.y ]
+ });
}
- scale.domain = function(_) {
- if (!arguments.length) return domain;
- domain = _;
- return scale;
- };
- scale.range = function(_) {
- if (!arguments.length) return range;
- range = _;
- return scale;
- };
- scale.copy = function() {
- return d3_scale_threshold(domain, range);
- };
- return scale;
- }
- function d3_scale_identity(domain) {
- function identity(x) {
- return +x;
+ function zoomended(event) {
+ event({
+ type: "zoomend"
+ });
}
- identity.invert = identity;
- identity.domain = identity.range = function(x) {
- if (!arguments.length) return domain;
- domain = x.map(identity);
- return identity;
- };
- identity.ticks = function(m) {
- return d3_scale_linearTicks(domain, m);
- };
- identity.tickFormat = function(m) {
- return d3_scale_linearTickFormat(domain, m);
- };
- identity.copy = function() {
- return d3_scale_identity(domain);
- };
- return identity;
- }
- function d3_svg_arcInnerRadius(d) {
- return d.innerRadius;
- }
- function d3_svg_arcOuterRadius(d) {
- return d.outerRadius;
- }
- function d3_svg_arcStartAngle(d) {
- return d.startAngle;
- }
- function d3_svg_arcEndAngle(d) {
- return d.endAngle;
- }
- function d3_svg_line(projection) {
- function line(data) {
- function segment() {
- segments.push("M", interpolate(projection(points), tension));
+ function mousedowned() {
+ var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, dragged = 0, w = d3.select(d3_window).on(mousemove, moved).on(mouseup, ended), l = location(d3.mouse(target)), dragRestore = d3_event_dragSuppress();
+ d3_selection_interrupt.call(target);
+ zoomstarted(event_);
+ function moved() {
+ dragged = 1;
+ translateTo(d3.mouse(target), l);
+ zoomed(event_);
+ }
+ function ended() {
+ w.on(mousemove, d3_window === target ? mousewheelreset : null).on(mouseup, null);
+ dragRestore(dragged && d3.event.target === eventTarget);
+ zoomended(event_);
+ }
+ }
+ function touchstarted() {
+ var target = this, event_ = event.of(target, arguments), locations0 = {}, distance0 = 0, scale0, eventId = d3.event.changedTouches[0].identifier, touchmove = "touchmove.zoom-" + eventId, touchend = "touchend.zoom-" + eventId, w = d3.select(d3_window).on(touchmove, moved).on(touchend, ended), t = d3.select(target).on(mousedown, null).on(touchstart, started), dragRestore = d3_event_dragSuppress();
+ d3_selection_interrupt.call(target);
+ started();
+ zoomstarted(event_);
+ function relocate() {
+ var touches = d3.touches(target);
+ scale0 = view.k;
+ touches.forEach(function(t) {
+ if (t.identifier in locations0) locations0[t.identifier] = location(t);
+ });
+ return touches;
}
- var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y);
- while (++i < n) {
- if (defined.call(this, d = data[i], i)) {
- points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]);
- } else if (points.length) {
- segment();
- points = [];
+ function started() {
+ var changed = d3.event.changedTouches;
+ for (var i = 0, n = changed.length; i < n; ++i) {
+ locations0[changed[i].identifier] = null;
+ }
+ var touches = relocate(), now = Date.now();
+ if (touches.length === 1) {
+ if (now - touchtime < 500) {
+ var p = touches[0], l = locations0[p.identifier];
+ scaleTo(view.k * 2);
+ translateTo(p, l);
+ d3_eventPreventDefault();
+ zoomed(event_);
+ }
+ touchtime = now;
+ } else if (touches.length > 1) {
+ var p = touches[0], q = touches[1], dx = p[0] - q[0], dy = p[1] - q[1];
+ distance0 = dx * dx + dy * dy;
}
}
- if (points.length) segment();
- return segments.length ? segments.join("") : null;
+ function moved() {
+ var touches = d3.touches(target), p0, l0, p1, l1;
+ for (var i = 0, n = touches.length; i < n; ++i, l1 = null) {
+ p1 = touches[i];
+ if (l1 = locations0[p1.identifier]) {
+ if (l0) break;
+ p0 = p1, l0 = l1;
+ }
+ }
+ if (l1) {
+ var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1, scale1 = distance0 && Math.sqrt(distance1 / distance0);
+ p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ];
+ l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ];
+ scaleTo(scale1 * scale0);
+ }
+ touchtime = null;
+ translateTo(p0, l0);
+ zoomed(event_);
+ }
+ function ended() {
+ if (d3.event.touches.length) {
+ var changed = d3.event.changedTouches;
+ for (var i = 0, n = changed.length; i < n; ++i) {
+ delete locations0[changed[i].identifier];
+ }
+ for (var identifier in locations0) {
+ return void relocate();
+ }
+ }
+ w.on(touchmove, null).on(touchend, null);
+ t.on(mousedown, mousedowned).on(touchstart, touchstarted);
+ dragRestore();
+ zoomended(event_);
+ }
+ }
+ function mousewheeled() {
+ var event_ = event.of(this, arguments);
+ if (mousewheelTimer) clearTimeout(mousewheelTimer); else d3_selection_interrupt.call(this),
+ zoomstarted(event_);
+ mousewheelTimer = setTimeout(function() {
+ mousewheelTimer = null;
+ zoomended(event_);
+ }, 50);
+ d3_eventPreventDefault();
+ var point = center || d3.mouse(this);
+ if (!translate0) translate0 = location(point);
+ scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * view.k);
+ translateTo(point, translate0);
+ zoomed(event_);
+ }
+ function mousewheelreset() {
+ translate0 = null;
}
- var x = d3_svg_lineX, y = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7;
- line.x = function(_) {
- if (!arguments.length) return x;
- x = _;
- return line;
- };
- line.y = function(_) {
- if (!arguments.length) return y;
- y = _;
- return line;
- };
- line.defined = function(_) {
- if (!arguments.length) return defined;
- defined = _;
- return line;
- };
- line.interpolate = function(_) {
- if (!arguments.length) return interpolateKey;
- if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key;
- return line;
- };
- line.tension = function(_) {
- if (!arguments.length) return tension;
- tension = _;
- return line;
- };
- return line;
+ function dblclicked() {
+ var event_ = event.of(this, arguments), p = d3.mouse(this), l = location(p), k = Math.log(view.k) / Math.LN2;
+ zoomstarted(event_);
+ scaleTo(Math.pow(2, d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1));
+ translateTo(p, l);
+ zoomed(event_);
+ zoomended(event_);
+ }
+ return d3.rebind(zoom, event, "on");
+ };
+ var d3_behavior_zoomInfinity = [ 0, Infinity ];
+ var d3_behavior_zoomDelta, d3_behavior_zoomWheel = "onwheel" in d3_document ? (d3_behavior_zoomDelta = function() {
+ return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1);
+ }, "wheel") : "onmousewheel" in d3_document ? (d3_behavior_zoomDelta = function() {
+ return d3.event.wheelDelta;
+ }, "mousewheel") : (d3_behavior_zoomDelta = function() {
+ return -d3.event.detail;
+ }, "MozMousePixelScroll");
+ function d3_Color() {}
+ d3_Color.prototype.toString = function() {
+ return this.rgb() + "";
+ };
+ d3.hsl = function(h, s, l) {
+ return arguments.length === 1 ? h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l) : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : d3_hsl(+h, +s, +l);
+ };
+ function d3_hsl(h, s, l) {
+ return new d3_Hsl(h, s, l);
}
- function d3_svg_lineX(d) {
- return d[0];
+ function d3_Hsl(h, s, l) {
+ this.h = h;
+ this.s = s;
+ this.l = l;
}
- function d3_svg_lineY(d) {
- return d[1];
+ var d3_hslPrototype = d3_Hsl.prototype = new d3_Color();
+ d3_hslPrototype.brighter = function(k) {
+ k = Math.pow(.7, arguments.length ? k : 1);
+ return d3_hsl(this.h, this.s, this.l / k);
+ };
+ d3_hslPrototype.darker = function(k) {
+ k = Math.pow(.7, arguments.length ? k : 1);
+ return d3_hsl(this.h, this.s, k * this.l);
+ };
+ d3_hslPrototype.rgb = function() {
+ return d3_hsl_rgb(this.h, this.s, this.l);
+ };
+ function d3_hsl_rgb(h, s, l) {
+ var m1, m2;
+ h = isNaN(h) ? 0 : (h %= 360) < 0 ? h + 360 : h;
+ s = isNaN(s) ? 0 : s < 0 ? 0 : s > 1 ? 1 : s;
+ l = l < 0 ? 0 : l > 1 ? 1 : l;
+ m2 = l <= .5 ? l * (1 + s) : l + s - l * s;
+ m1 = 2 * l - m2;
+ function v(h) {
+ if (h > 360) h -= 360; else if (h < 0) h += 360;
+ if (h < 60) return m1 + (m2 - m1) * h / 60;
+ if (h < 180) return m2;
+ if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60;
+ return m1;
+ }
+ function vv(h) {
+ return Math.round(v(h) * 255);
+ }
+ return d3_rgb(vv(h + 120), vv(h), vv(h - 120));
}
- function d3_svg_lineLinear(points) {
- return points.join("L");
+ d3.hcl = function(h, c, l) {
+ return arguments.length === 1 ? h instanceof d3_Hcl ? d3_hcl(h.h, h.c, h.l) : h instanceof d3_Lab ? d3_lab_hcl(h.l, h.a, h.b) : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b) : d3_hcl(+h, +c, +l);
+ };
+ function d3_hcl(h, c, l) {
+ return new d3_Hcl(h, c, l);
}
- function d3_svg_lineLinearClosed(points) {
- return d3_svg_lineLinear(points) + "Z";
+ function d3_Hcl(h, c, l) {
+ this.h = h;
+ this.c = c;
+ this.l = l;
}
- function d3_svg_lineStepBefore(points) {
- var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
- while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]);
- return path.join("");
+ var d3_hclPrototype = d3_Hcl.prototype = new d3_Color();
+ d3_hclPrototype.brighter = function(k) {
+ return d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)));
+ };
+ d3_hclPrototype.darker = function(k) {
+ return d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)));
+ };
+ d3_hclPrototype.rgb = function() {
+ return d3_hcl_lab(this.h, this.c, this.l).rgb();
+ };
+ function d3_hcl_lab(h, c, l) {
+ if (isNaN(h)) h = 0;
+ if (isNaN(c)) c = 0;
+ return d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c);
}
- function d3_svg_lineStepAfter(points) {
- var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
- while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]);
- return path.join("");
+ d3.lab = function(l, a, b) {
+ return arguments.length === 1 ? l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b) : l instanceof d3_Hcl ? d3_hcl_lab(l.l, l.c, l.h) : d3_rgb_lab((l = d3.rgb(l)).r, l.g, l.b) : d3_lab(+l, +a, +b);
+ };
+ function d3_lab(l, a, b) {
+ return new d3_Lab(l, a, b);
}
- function d3_svg_lineCardinalOpen(points, tension) {
- return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, points.length - 1), d3_svg_lineCardinalTangents(points, tension));
+ function d3_Lab(l, a, b) {
+ this.l = l;
+ this.a = a;
+ this.b = b;
}
- function d3_svg_lineCardinalClosed(points, tension) {
- return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite((points.push(points[0]), points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension));
+ var d3_lab_K = 18;
+ var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883;
+ var d3_labPrototype = d3_Lab.prototype = new d3_Color();
+ d3_labPrototype.brighter = function(k) {
+ return d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
+ };
+ d3_labPrototype.darker = function(k) {
+ return d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
+ };
+ d3_labPrototype.rgb = function() {
+ return d3_lab_rgb(this.l, this.a, this.b);
+ };
+ function d3_lab_rgb(l, a, b) {
+ var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200;
+ x = d3_lab_xyz(x) * d3_lab_X;
+ y = d3_lab_xyz(y) * d3_lab_Y;
+ z = d3_lab_xyz(z) * d3_lab_Z;
+ return d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z), d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259 * y + 1.0572252 * z));
}
- function d3_svg_lineCardinal(points, tension, closed) {
- return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension));
+ function d3_lab_hcl(l, a, b) {
+ return l > 0 ? d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l) : d3_hcl(NaN, NaN, l);
}
- function d3_svg_lineHermite(points, tangents) {
- if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) {
- return d3_svg_lineLinear(points);
- }
- var quad = points.length != tangents.length, path = "", p0 = points[0], p = points[1], t0 = tangents[0], t = t0, pi = 1;
- if (quad) {
- path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) + "," + p[0] + "," + p[1];
- p0 = points[1];
- pi = 2;
- }
- if (tangents.length > 1) {
- t = tangents[1];
- p = points[pi];
- pi++;
- path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) + "," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1];
- for (var i = 2; i < tangents.length; i++, pi++) {
- p = points[pi];
- t = tangents[i];
- path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1];
- }
- }
- if (quad) {
- var lp = points[pi];
- path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) + "," + lp[0] + "," + lp[1];
- }
- return path;
+ function d3_lab_xyz(x) {
+ return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037;
}
- function d3_svg_lineCardinalTangents(points, tension) {
- var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length;
- while (++i < n) {
- p0 = p1;
- p1 = p2;
- p2 = points[i];
- tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]);
- }
- return tangents;
+ function d3_xyz_lab(x) {
+ return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29;
}
- function d3_svg_lineBasis(points) {
- if (points.length < 3) return d3_svg_lineLinear(points);
- var i = 1, n = points.length, pi = points[0], x0 = pi[0], y0 = pi[1], px = [ x0, x0, x0, (pi = points[1])[0] ], py = [ y0, y0, y0, pi[1] ], path = [ x0, ",", y0 ];
- d3_svg_lineBasisBezier(path, px, py);
- while (++i < n) {
- pi = points[i];
- px.shift();
- px.push(pi[0]);
- py.shift();
- py.push(pi[1]);
- d3_svg_lineBasisBezier(path, px, py);
- }
- i = -1;
- while (++i < 2) {
- px.shift();
- px.push(pi[0]);
- py.shift();
- py.push(pi[1]);
- d3_svg_lineB
<TRUNCATED>
[4/6] couchdb commit: updated refs/heads/master to 7296e53
Posted by de...@apache.org.
Require.js config to support d3 v3 update.
Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/6301060f
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/6301060f
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/6301060f
Branch: refs/heads/master
Commit: 6301060fdbb9d5505ffd43f8b0df52b6c303b6ef
Parents: 95d6d6b
Author: Christian Hogan <gi...@infliction.org>
Authored: Fri Mar 21 15:02:28 2014 -0400
Committer: suelockwood <de...@apache.org>
Committed: Tue Mar 25 15:19:18 2014 -0400
----------------------------------------------------------------------
src/fauxton/app/config.js | 8 ++++++++
1 file changed, 8 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb/blob/6301060f/src/fauxton/app/config.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/config.js b/src/fauxton/app/config.js
index 98be9c6..d33f3b8 100644
--- a/src/fauxton/app/config.js
+++ b/src/fauxton/app/config.js
@@ -53,6 +53,8 @@ require.config({
deps: ["jquery"],
exports: "Bootstrap"
},
+
+ "nv.d3": ["d3.global"],
"plugins/prettify": [],
"plugins/beautify": [],
@@ -60,3 +62,9 @@ require.config({
"plugins/jquery.form": ["jquery"]
}
});
+
+define("d3.global", ["d3"], function(_) {
+ d3 = _;
+});
+
+require(["d3", "nv.d3"], function(d3, nvd3) {});
[6/6] couchdb commit: updated refs/heads/master to 7296e53
Posted by de...@apache.org.
Updating d3 license year to match d3's official license.
Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/b1255309
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/b1255309
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/b1255309
Branch: refs/heads/master
Commit: b1255309eca961d188d40ef509e7541a3d4ad14e
Parents: 6301060
Author: Christian Hogan <gi...@infliction.org>
Authored: Fri Mar 21 16:31:07 2014 -0400
Committer: suelockwood <de...@apache.org>
Committed: Tue Mar 25 15:19:18 2014 -0400
----------------------------------------------------------------------
LICENSE | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb/blob/b1255309/LICENSE
----------------------------------------------------------------------
diff --git a/LICENSE b/LICENSE
index 6ae7303..21cfb8c 100644
--- a/LICENSE
+++ b/LICENSE
@@ -689,7 +689,7 @@ For src/fauxton/assets/less/bootstrap
For src/fauxton/assets/js/libs/d3.js
- Copyright (c) 2012, Michael Bostock
+ Copyright (c) 2010-2014, Michael Bostock
All rights reserved.
Redistribution and use in source and binary forms, with or without
[5/6] couchdb commit: updated refs/heads/master to 7296e53
Posted by de...@apache.org.
Updating pie chart to reflect nvd3's removal of pie.values(), tweaking CSS to make pie chart fit all nice like.
Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/7296e53c
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/7296e53c
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/7296e53c
Branch: refs/heads/master
Commit: 7296e53c8dcd5d69d83bd04a4421887390c06816
Parents: b125530
Author: Christian Hogan <gi...@infliction.org>
Authored: Tue Mar 25 14:43:36 2014 -0400
Committer: suelockwood <de...@apache.org>
Committed: Tue Mar 25 15:19:18 2014 -0400
----------------------------------------------------------------------
src/fauxton/app/addons/stats/assets/less/stats.less | 5 +++++
src/fauxton/app/addons/stats/templates/pie_table.html | 6 +++++-
src/fauxton/app/addons/stats/views.js | 7 +++----
3 files changed, 13 insertions(+), 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb/blob/7296e53c/src/fauxton/app/addons/stats/assets/less/stats.less
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/stats/assets/less/stats.less b/src/fauxton/app/addons/stats/assets/less/stats.less
index 7ec88b9..43ddb3b 100644
--- a/src/fauxton/app/addons/stats/assets/less/stats.less
+++ b/src/fauxton/app/addons/stats/assets/less/stats.less
@@ -13,3 +13,8 @@
.datatypes {
padding: 0 15px;
}
+
+.span5 {
+ height:450px;
+ min-width: 450px;
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/couchdb/blob/7296e53c/src/fauxton/app/addons/stats/templates/pie_table.html
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/stats/templates/pie_table.html b/src/fauxton/app/addons/stats/templates/pie_table.html
index 1fa781a..8c4682c 100644
--- a/src/fauxton/app/addons/stats/templates/pie_table.html
+++ b/src/fauxton/app/addons/stats/templates/pie_table.html
@@ -46,5 +46,9 @@ the License.
</table>
</div>
- <svg id="<%= datatype %>_graph"></svg>
+ <div class="span5">
+ <center>
+ <svg id="<%= datatype %>_graph"></svg>
+ </center>
+ </div>
</div>
http://git-wip-us.apache.org/repos/asf/couchdb/blob/7296e53c/src/fauxton/app/addons/stats/views.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/stats/views.js b/src/fauxton/app/addons/stats/views.js
index 9dd9cbc..c8374ad 100644
--- a/src/fauxton/app/addons/stats/views.js
+++ b/src/fauxton/app/addons/stats/views.js
@@ -70,21 +70,20 @@ function(app, FauxtonAPI,Stats) {
series = _.sortBy(series, function(d){return -d.y;});
nv.addGraph(function() {
- var width = 550,
- height = 400;
+ var width = 440,
+ height = 440;
var chart = nv.models.pieChart()
.x(function(d) { return d.key; })
.y(function(d) { return d.y; })
.showLabels(true)
.showLegend(false)
- .values(function(d) { return d; })
.color(d3.scale.category10().range())
.width(width)
.height(height);
d3.select(chartelem)
- .datum([series])
+ .datum(series)
.transition().duration(300)
.attr('width', width)
.attr('height', height)
[3/6] couchdb commit: updated refs/heads/master to 7296e53
Posted by de...@apache.org.
Updating d3 to v3.4.3 and nv.d3 to v1.1.15
Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/95d6d6b0
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/95d6d6b0
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/95d6d6b0
Branch: refs/heads/master
Commit: 95d6d6b035242d9a203b2df3af342274b29f98b1
Parents: 0fb5aa9
Author: Christian Hogan <gi...@infliction.org>
Authored: Fri Mar 21 13:42:04 2014 -0400
Committer: suelockwood <de...@apache.org>
Committed: Tue Mar 25 15:19:17 2014 -0400
----------------------------------------------------------------------
src/fauxton/assets/css/nv.d3.css | 191 +-
src/fauxton/assets/js/libs/d3.js | 14721 +++++++++++++++++------------
src/fauxton/assets/js/libs/nv.d3.js | 4536 +++++----
3 files changed, 11530 insertions(+), 7918 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb/blob/95d6d6b0/src/fauxton/assets/css/nv.d3.css
----------------------------------------------------------------------
diff --git a/src/fauxton/assets/css/nv.d3.css b/src/fauxton/assets/css/nv.d3.css
index 28ccd05..cae8348 100644
--- a/src/fauxton/assets/css/nv.d3.css
+++ b/src/fauxton/assets/css/nv.d3.css
@@ -10,6 +10,18 @@
overflow: hidden;
}
+/********************
+ Box shadow and border radius styling
+*/
+.nvtooltip.with-3d-shadow, .with-3d-shadow .nvtooltip {
+ -moz-box-shadow: 0 5px 10px rgba(0,0,0,.2);
+ -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2);
+ box-shadow: 0 5px 10px rgba(0,0,0,.2);
+
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+}
/********************
* TOOLTIP CSS
@@ -17,31 +29,18 @@
.nvtooltip {
position: absolute;
- background-color: rgba(255,255,255,1);
- padding: 10px;
- border: 1px solid #ddd;
+ background-color: rgba(255,255,255,1.0);
+ padding: 1px;
+ border: 1px solid rgba(0,0,0,.2);
z-index: 10000;
font-family: Arial;
font-size: 13px;
-
- transition: opacity 500ms linear;
- -moz-transition: opacity 500ms linear;
- -webkit-transition: opacity 500ms linear;
-
- transition-delay: 500ms;
- -moz-transition-delay: 500ms;
- -webkit-transition-delay: 500ms;
-
- -moz-box-shadow: 4px 4px 8px rgba(0,0,0,.5);
- -webkit-box-shadow: 4px 4px 8px rgba(0,0,0,.5);
- box-shadow: 4px 4px 8px rgba(0,0,0,.5);
-
- -moz-border-radius: 10px;
- border-radius: 10px;
-
+ text-align: left;
pointer-events: none;
+ white-space: nowrap;
+
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
@@ -50,15 +49,42 @@
user-select: none;
}
+/*Give tooltips that old fade in transition by
+ putting a "with-transitions" class on the container div.
+*/
+.nvtooltip.with-transitions, .with-transitions .nvtooltip {
+ transition: opacity 250ms linear;
+ -moz-transition: opacity 250ms linear;
+ -webkit-transition: opacity 250ms linear;
+
+ transition-delay: 250ms;
+ -moz-transition-delay: 250ms;
+ -webkit-transition-delay: 250ms;
+}
+
+.nvtooltip.x-nvtooltip,
+.nvtooltip.y-nvtooltip {
+ padding: 8px;
+}
+
.nvtooltip h3 {
margin: 0;
- padding: 0;
+ padding: 4px 14px;
+ line-height: 18px;
+ font-weight: normal;
+ background-color: rgba(247,247,247,0.75);
text-align: center;
+
+ border-bottom: 1px solid #ebebeb;
+
+ -webkit-border-radius: 5px 5px 0 0;
+ -moz-border-radius: 5px 5px 0 0;
+ border-radius: 5px 5px 0 0;
}
.nvtooltip p {
margin: 0;
- padding: 0;
+ padding: 5px 14px;
text-align: center;
}
@@ -67,6 +93,45 @@
margin: 2px 0;
}
+.nvtooltip table {
+ margin: 6px;
+ border-spacing:0;
+}
+
+
+.nvtooltip table td {
+ padding: 2px 9px 2px 0;
+ vertical-align: middle;
+}
+
+.nvtooltip table td.key {
+ font-weight:normal;
+}
+.nvtooltip table td.value {
+ text-align: right;
+ font-weight: bold;
+}
+
+.nvtooltip table tr.highlight td {
+ padding: 1px 9px 1px 0;
+ border-bottom-style: solid;
+ border-bottom-width: 1px;
+ border-top-style: solid;
+ border-top-width: 1px;
+}
+
+.nvtooltip table td.legend-color-guide div {
+ width: 8px;
+ height: 8px;
+ vertical-align: middle;
+}
+
+.nvtooltip .footer {
+ padding: 3px;
+ text-align: center;
+}
+
+
.nvtooltip-pending-removal {
position: absolute;
pointer-events: none;
@@ -110,7 +175,7 @@ svg .title {
.nvd3.nv-noData {
font-size: 18px;
- font-weight: bolf;
+ font-weight: bold;
}
@@ -142,6 +207,9 @@ svg .title {
/**********
* Axes
*/
+.nvd3 .nv-axis {
+ pointer-events:none;
+}
.nvd3 .nv-axis path {
fill: none;
@@ -160,12 +228,12 @@ svg .title {
.nvd3 .nv-axis line {
fill: none;
- stroke: #000;
- stroke-opacity: .25;
+ stroke: #e5e5e5;
shape-rendering: crispEdges;
}
-.nvd3 .nv-axis line.zero {
+.nvd3 .nv-axis .zero line,
+/*this selector may not be necessary*/ .nvd3 .nv-axis line.zero {
stroke-opacity: .75;
}
@@ -209,7 +277,7 @@ svg .title {
-webkit-transition: fill-opacity 250ms linear;
}
-.nvd3 .nv-bars rect:hover {
+.nvd3 .nv-bars rect.hover {
fill-opacity: 1;
}
@@ -259,7 +327,6 @@ svg .title {
.nvd3.nv-pie path {
stroke-opacity: 0;
-
transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear;
-moz-transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear;
-webkit-transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear;
@@ -279,12 +346,10 @@ svg .title {
.nvd3.nv-pie .hover path {
fill-opacity: .7;
-/*
- stroke-width: 6px;
- stroke-opacity: 1;
-*/
}
-
+.nvd3.nv-pie .nv-label {
+ pointer-events: none;
+}
.nvd3.nv-pie .nv-label rect {
fill-opacity: 0;
stroke-opacity: 0;
@@ -296,7 +361,7 @@ svg .title {
.nvd3 .nv-groups path.nv-line {
fill: none;
- stroke-width: 2.5px;
+ stroke-width: 1.5px;
/*
stroke-linecap: round;
shape-rendering: geometricPrecision;
@@ -311,6 +376,11 @@ svg .title {
*/
}
+.nvd3 .nv-groups path.nv-line.nv-thin-line {
+ stroke-width: 1px;
+}
+
+
.nvd3 .nv-groups path.nv-area {
stroke: none;
/*
@@ -350,17 +420,18 @@ svg .title {
}
-.nvd3 .nv-groups .nv-point {
+.with-transitions .nvd3 .nv-groups .nv-point {
transition: stroke-width 250ms linear, stroke-opacity 250ms linear;
-moz-transition: stroke-width 250ms linear, stroke-opacity 250ms linear;
-webkit-transition: stroke-width 250ms linear, stroke-opacity 250ms linear;
+
}
.nvd3.nv-scatter .nv-groups .nv-point.hover,
.nvd3 .nv-groups .nv-point.hover {
- stroke-width: 20px;
- fill-opacity: .5 !important;
- stroke-opacity: .5 !important;
+ stroke-width: 7px;
+ fill-opacity: .95 !important;
+ stroke-opacity: .95 !important;
}
@@ -457,11 +528,12 @@ svg .title {
fill-opacity: 0;
}
+/*
.nvd3.nv-stackedarea .nv-groups .nv-point.hover {
stroke-width: 20px;
stroke-opacity: .75;
fill-opacity: 1;
-}
+}*/
@@ -496,7 +568,7 @@ svg .title {
.nvd3.nv-bullet .nv-range {
- fill: #999;
+ fill: #bababa;
fill-opacity: .4;
}
.nvd3.nv-bullet .nv-range:hover {
@@ -653,4 +725,45 @@ svg .title {
*/
}
+/**********
+* Parallel Coordinates
+*/
+
+.nvd3 .background path {
+ fill: none;
+ stroke: #ccc;
+ stroke-opacity: .4;
+ shape-rendering: crispEdges;
+}
+
+.nvd3 .foreground path {
+ fill: none;
+ stroke: steelblue;
+ stroke-opacity: .7;
+}
+
+.nvd3 .brush .extent {
+ fill-opacity: .3;
+ stroke: #fff;
+ shape-rendering: crispEdges;
+}
+.nvd3 .axis line, .axis path {
+ fill: none;
+ stroke: #000;
+ shape-rendering: crispEdges;
+}
+
+.nvd3 .axis text {
+ text-shadow: 0 1px 0 #fff;
+}
+
+/****
+Interactive Layer
+*/
+.nvd3 .nv-interactiveGuideLine {
+ pointer-events:none;
+}
+.nvd3 line.nv-guideline {
+ stroke: #ccc;
+}
\ No newline at end of file