1 |
|
/* nvd3 version 1.8.3 (https://github.com/novus/nvd3) 2016-04-26 */
|
|
1 |
/* nvd3 version 1.8.6 (https://github.com/novus/nvd3) 2017-08-23 */
|
2 |
2 |
(function(){
|
3 |
3 |
|
4 |
4 |
// set up main nv object
|
... | ... | |
161 |
161 |
* implementations in the future.
|
162 |
162 |
*/
|
163 |
163 |
nv.dom.write = function(callback) {
|
164 |
|
if (window.fastdom !== undefined) {
|
165 |
|
return fastdom.mutate(callback);
|
166 |
|
}
|
167 |
|
return callback();
|
|
164 |
if (window.fastdom !== undefined) {
|
|
165 |
return fastdom.mutate(callback);
|
|
166 |
}
|
|
167 |
return callback();
|
168 |
168 |
};
|
169 |
169 |
|
170 |
170 |
/* Facade for queueing DOM read operations
|
... | ... | |
174 |
174 |
* implementations in the future.
|
175 |
175 |
*/
|
176 |
176 |
nv.dom.read = function(callback) {
|
177 |
|
if (window.fastdom !== undefined) {
|
178 |
|
return fastdom.measure(callback);
|
179 |
|
}
|
180 |
|
return callback();
|
|
177 |
if (window.fastdom !== undefined) {
|
|
178 |
return fastdom.measure(callback);
|
|
179 |
}
|
|
180 |
return callback();
|
181 |
181 |
};
|
182 |
182 |
/* Utility class to handle creation of an interactive layer.
|
183 |
183 |
This places a rectangle on top of the chart. When you mouse move over it, it sends a dispatch
|
... | ... | |
198 |
198 |
, showGuideLine = true
|
199 |
199 |
, svgContainer = null // Must pass the chart's svg, we'll use its mousemove event.
|
200 |
200 |
, tooltip = nv.models.tooltip()
|
201 |
|
, isMSIE = "ActiveXObject" in window // Checkt if IE by looking for activeX.
|
|
201 |
, isMSIE = window.ActiveXObject// Checkt if IE by looking for activeX. (excludes IE11)
|
202 |
202 |
;
|
203 |
203 |
|
204 |
204 |
tooltip
|
... | ... | |
221 |
221 |
}
|
222 |
222 |
|
223 |
223 |
function mouseHandler() {
|
224 |
|
var d3mouse = d3.mouse(this);
|
225 |
|
var mouseX = d3mouse[0];
|
226 |
|
var mouseY = d3mouse[1];
|
|
224 |
var mouseX = d3.event.clientX - this.getBoundingClientRect().left;
|
|
225 |
var mouseY = d3.event.clientY - this.getBoundingClientRect().top;
|
|
226 |
|
227 |
227 |
var subtractMargin = true;
|
228 |
228 |
var mouseOutAnyReason = false;
|
229 |
229 |
if (isMSIE) {
|
... | ... | |
342 |
342 |
|
343 |
343 |
// if user presses mouse down the layer, fire elementMouseDown
|
344 |
344 |
if (d3.event.type === 'mousedown') {
|
345 |
|
dispatch.elementMouseDown({
|
346 |
|
mouseX: mouseX,
|
347 |
|
mouseY: mouseY,
|
348 |
|
pointXValue: pointXValue
|
349 |
|
});
|
|
345 |
dispatch.elementMouseDown({
|
|
346 |
mouseX: mouseX,
|
|
347 |
mouseY: mouseY,
|
|
348 |
pointXValue: pointXValue
|
|
349 |
});
|
350 |
350 |
}
|
351 |
351 |
|
352 |
352 |
// if user presses mouse down the layer, fire elementMouseUp
|
353 |
353 |
if (d3.event.type === 'mouseup') {
|
354 |
|
dispatch.elementMouseUp({
|
355 |
|
mouseX: mouseX,
|
356 |
|
mouseY: mouseY,
|
357 |
|
pointXValue: pointXValue
|
358 |
|
});
|
|
354 |
dispatch.elementMouseUp({
|
|
355 |
mouseX: mouseX,
|
|
356 |
mouseY: mouseY,
|
|
357 |
pointXValue: pointXValue
|
|
358 |
});
|
359 |
359 |
}
|
360 |
360 |
}
|
361 |
361 |
|
... | ... | |
545 |
545 |
, distance = 25 // Distance to offset tooltip from the mouse location.
|
546 |
546 |
, snapDistance = 0 // Tolerance allowed before tooltip is moved from its current position (creates 'snapping' effect)
|
547 |
547 |
, classes = null // Attaches additional CSS classes to the tooltip DIV that is created.
|
548 |
|
, chartContainer = null // Parent dom element of the SVG that holds the chart.
|
549 |
548 |
, hidden = true // Start off hidden, toggle with hide/show functions below.
|
550 |
549 |
, hideDelay = 200 // Delay (in ms) before the tooltip hides after calling hide().
|
551 |
550 |
, tooltip = null // d3 select of the tooltip div.
|
... | ... | |
556 |
555 |
, nvPointerEventsClass = "nv-pointer-events-none" // CSS class to specify whether element should not have mouse events.
|
557 |
556 |
;
|
558 |
557 |
|
559 |
|
/*
|
560 |
|
Function that returns the position (relative to the viewport) the tooltip should be placed in.
|
561 |
|
Should return: {
|
562 |
|
left: <leftPos>,
|
563 |
|
top: <topPos>
|
564 |
|
}
|
565 |
|
*/
|
566 |
|
var position = function() {
|
567 |
|
return {
|
568 |
|
left: d3.event !== null ? d3.event.clientX : 0,
|
569 |
|
top: d3.event !== null ? d3.event.clientY : 0
|
570 |
|
};
|
571 |
|
};
|
572 |
|
|
573 |
558 |
// Format function for the tooltip values column.
|
574 |
|
var valueFormatter = function(d, i) {
|
|
559 |
// d is value,
|
|
560 |
// i is series index
|
|
561 |
// p is point containing the value
|
|
562 |
var valueFormatter = function(d, i, p) {
|
575 |
563 |
return d;
|
576 |
564 |
};
|
577 |
565 |
|
... | ... | |
584 |
572 |
return d;
|
585 |
573 |
};
|
586 |
574 |
|
587 |
|
// By default, the tooltip model renders a beautiful table inside a DIV.
|
588 |
|
// You can override this function if a custom tooltip is desired.
|
589 |
|
var contentGenerator = function(d) {
|
|
575 |
// By default, the tooltip model renders a beautiful table inside a DIV, returned as HTML
|
|
576 |
// You can override this function if a custom tooltip is desired. For instance, you could directly manipulate
|
|
577 |
// the DOM by accessing elem and returning false.
|
|
578 |
var contentGenerator = function(d, elem) {
|
590 |
579 |
if (d === null) {
|
591 |
580 |
return '';
|
592 |
581 |
}
|
... | ... | |
627 |
616 |
|
628 |
617 |
trowEnter.append("td")
|
629 |
618 |
.classed("value",true)
|
630 |
|
.html(function(p, i) { return valueFormatter(p.value, i) });
|
|
619 |
.html(function(p, i) { return valueFormatter(p.value, i, p) });
|
|
620 |
|
|
621 |
trowEnter.filter(function (p,i) { return p.percent !== undefined }).append("td")
|
|
622 |
.classed("percent", true)
|
|
623 |
.html(function(p, i) { return "(" + d3.format('%')(p.percent) + ")" });
|
631 |
624 |
|
632 |
625 |
trowEnter.selectAll("td").each(function(p) {
|
633 |
626 |
if (p.highlight) {
|
... | ... | |
647 |
640 |
|
648 |
641 |
};
|
649 |
642 |
|
|
643 |
/*
|
|
644 |
Function that returns the position (relative to the viewport/document.body)
|
|
645 |
the tooltip should be placed in.
|
|
646 |
Should return: {
|
|
647 |
left: <leftPos>,
|
|
648 |
top: <topPos>
|
|
649 |
}
|
|
650 |
*/
|
|
651 |
var position = function() {
|
|
652 |
var pos = {
|
|
653 |
left: d3.event !== null ? d3.event.clientX : 0,
|
|
654 |
top: d3.event !== null ? d3.event.clientY : 0
|
|
655 |
};
|
|
656 |
|
|
657 |
if(getComputedStyle(document.body).transform != 'none') {
|
|
658 |
// Take the offset into account, as now the tooltip is relative
|
|
659 |
// to document.body.
|
|
660 |
var client = document.body.getBoundingClientRect();
|
|
661 |
pos.left -= client.left;
|
|
662 |
pos.top -= client.top;
|
|
663 |
}
|
|
664 |
|
|
665 |
return pos;
|
|
666 |
};
|
|
667 |
|
650 |
668 |
var dataSeriesExists = function(d) {
|
651 |
669 |
if (d && d.series) {
|
652 |
670 |
if (nv.utils.isArray(d.series)) {
|
... | ... | |
734 |
752 |
} else {
|
735 |
753 |
// using tooltip.style('transform') returns values un-usable for tween
|
736 |
754 |
var old_translate = 'translate(' + lastPosition.left + 'px, ' + lastPosition.top + 'px)';
|
737 |
|
var new_translate = 'translate(' + left + 'px, ' + top + 'px)';
|
|
755 |
var new_translate = 'translate(' + Math.round(left) + 'px, ' + Math.round(top) + 'px)';
|
738 |
756 |
var translateInterpolator = d3.interpolateString(old_translate, new_translate);
|
739 |
757 |
var is_hidden = tooltip.style('opacity') < 0.1;
|
740 |
758 |
|
... | ... | |
762 |
780 |
// Creates new tooltip container, or uses existing one on DOM.
|
763 |
781 |
function initTooltip() {
|
764 |
782 |
if (!tooltip || !tooltip.node()) {
|
765 |
|
var container = chartContainer ? chartContainer : document.body;
|
766 |
783 |
// Create new tooltip div if it doesn't exist on DOM.
|
767 |
784 |
|
768 |
785 |
var data = [1];
|
769 |
|
tooltip = d3.select(container).selectAll('.nvtooltip').data(data);
|
|
786 |
tooltip = d3.select(document.body).select('#'+id).data(data);
|
770 |
787 |
|
771 |
788 |
tooltip.enter().append('div')
|
772 |
789 |
.attr("class", "nvtooltip " + (classes ? classes : "xy-tooltip"))
|
... | ... | |
789 |
806 |
nv.dom.write(function () {
|
790 |
807 |
initTooltip();
|
791 |
808 |
// Generate data and set it into tooltip.
|
792 |
|
// Bonus - If you override contentGenerator and return falsey you can use something like
|
793 |
|
// React or Knockout to bind the data for your tooltip.
|
794 |
|
var newContent = contentGenerator(data);
|
|
809 |
// Bonus - If you override contentGenerator and return false, you can use something like
|
|
810 |
// Angular, React or Knockout to bind the data for your tooltip directly to the DOM.
|
|
811 |
var newContent = contentGenerator(data, tooltip.node());
|
795 |
812 |
if (newContent) {
|
796 |
813 |
tooltip.node().innerHTML = newContent;
|
797 |
814 |
}
|
... | ... | |
812 |
829 |
distance: {get: function(){return distance;}, set: function(_){distance=_;}},
|
813 |
830 |
snapDistance: {get: function(){return snapDistance;}, set: function(_){snapDistance=_;}},
|
814 |
831 |
classes: {get: function(){return classes;}, set: function(_){classes=_;}},
|
815 |
|
chartContainer: {get: function(){return chartContainer;}, set: function(_){chartContainer=_;}},
|
816 |
832 |
enabled: {get: function(){return enabled;}, set: function(_){enabled=_;}},
|
817 |
833 |
hideDelay: {get: function(){return hideDelay;}, set: function(_){hideDelay=_;}},
|
818 |
834 |
contentGenerator: {get: function(){return contentGenerator;}, set: function(_){contentGenerator=_;}},
|
... | ... | |
823 |
839 |
position: {get: function(){return position;}, set: function(_){position=_;}},
|
824 |
840 |
|
825 |
841 |
// Deprecated options
|
|
842 |
chartContainer: {get: function(){return document.body;}, set: function(_){
|
|
843 |
// deprecated after 1.8.3
|
|
844 |
nv.deprecated('chartContainer', 'feature removed after 1.8.3');
|
|
845 |
}},
|
826 |
846 |
fixedTop: {get: function(){return null;}, set: function(_){
|
827 |
847 |
// deprecated after 1.8.1
|
828 |
848 |
nv.deprecated('fixedTop', 'feature removed after 1.8.1');
|
... | ... | |
1552 |
1572 |
if (!array1 || !array2)
|
1553 |
1573 |
return false;
|
1554 |
1574 |
|
1555 |
|
// compare lengths - can save a lot of time
|
|
1575 |
// compare lengths - can save a lot of time
|
1556 |
1576 |
if (array1.length != array2.length)
|
1557 |
1577 |
return false;
|
1558 |
1578 |
|
... | ... | |
1569 |
1589 |
}
|
1570 |
1590 |
}
|
1571 |
1591 |
return true;
|
1572 |
|
};nv.models.axis = function() {
|
|
1592 |
};
|
|
1593 |
|
|
1594 |
/*
|
|
1595 |
Check if a point within an arc
|
|
1596 |
*/
|
|
1597 |
nv.utils.pointIsInArc = function(pt, ptData, d3Arc) {
|
|
1598 |
// Center of the arc is assumed to be 0,0
|
|
1599 |
// (pt.x, pt.y) are assumed to be relative to the center
|
|
1600 |
var r1 = d3Arc.innerRadius()(ptData), // Note: Using the innerRadius
|
|
1601 |
r2 = d3Arc.outerRadius()(ptData),
|
|
1602 |
theta1 = d3Arc.startAngle()(ptData),
|
|
1603 |
theta2 = d3Arc.endAngle()(ptData);
|
|
1604 |
|
|
1605 |
var dist = pt.x * pt.x + pt.y * pt.y,
|
|
1606 |
angle = Math.atan2(pt.x, -pt.y); // Note: different coordinate system.
|
|
1607 |
|
|
1608 |
angle = (angle < 0) ? (angle + Math.PI * 2) : angle;
|
|
1609 |
|
|
1610 |
return (r1 * r1 <= dist) && (dist <= r2 * r2) &&
|
|
1611 |
(theta1 <= angle) && (angle <= theta2);
|
|
1612 |
};
|
|
1613 |
|
|
1614 |
nv.models.axis = function() {
|
1573 |
1615 |
"use strict";
|
1574 |
1616 |
|
1575 |
1617 |
//============================================================
|
... | ... | |
1593 |
1635 |
, fontSize = undefined
|
1594 |
1636 |
, duration = 250
|
1595 |
1637 |
, dispatch = d3.dispatch('renderEnd')
|
|
1638 |
, tickFormatMaxMin
|
1596 |
1639 |
;
|
1597 |
1640 |
axis
|
1598 |
1641 |
.scale(scale)
|
... | ... | |
1677 |
1720 |
.attr('y', -axis.tickPadding())
|
1678 |
1721 |
.attr('text-anchor', 'middle')
|
1679 |
1722 |
.text(function(d,i) {
|
1680 |
|
var v = fmt(d);
|
|
1723 |
var formatter = tickFormatMaxMin || fmt;
|
|
1724 |
var v = formatter(d);
|
1681 |
1725 |
return ('' + v).match('NaN') ? '' : v;
|
1682 |
1726 |
});
|
1683 |
1727 |
axisMaxMin.watchTransition(renderWatch, 'min-max top')
|
... | ... | |
1694 |
1738 |
var rotateLabelsRule = '';
|
1695 |
1739 |
if (rotateLabels%360) {
|
1696 |
1740 |
//Reset transform on ticks so textHeight can be calculated correctly
|
1697 |
|
xTicks.attr('transform', '');
|
|
1741 |
xTicks.attr('transform', '');
|
1698 |
1742 |
//Calculate the longest xTick width
|
1699 |
1743 |
xTicks.each(function(d,i){
|
1700 |
1744 |
var box = this.getBoundingClientRect();
|
... | ... | |
1752 |
1796 |
.attr('transform', rotateLabelsRule)
|
1753 |
1797 |
.style('text-anchor', rotateLabels ? (rotateLabels%360 > 0 ? 'start' : 'end') : 'middle')
|
1754 |
1798 |
.text(function(d,i) {
|
1755 |
|
var v = fmt(d);
|
|
1799 |
var formatter = tickFormatMaxMin || fmt;
|
|
1800 |
var v = formatter(d);
|
1756 |
1801 |
return ('' + v).match('NaN') ? '' : v;
|
1757 |
1802 |
});
|
1758 |
1803 |
axisMaxMin.watchTransition(renderWatch, 'min-max bottom')
|
... | ... | |
1767 |
1812 |
axisLabel
|
1768 |
1813 |
.style('text-anchor', rotateYLabel ? 'middle' : 'begin')
|
1769 |
1814 |
.attr('transform', rotateYLabel ? 'rotate(90)' : '')
|
1770 |
|
.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
|
|
1815 |
.attr('y', rotateYLabel ? (-Math.max(margin.right, width) + 12 - (axisLabelDistance || 0)) : -10) //TODO: consider calculating this based on largest tick width... OR at least expose this on chart
|
1771 |
1816 |
.attr('x', rotateYLabel ? (d3.max(scale.range()) / 2) : axis.tickPadding());
|
1772 |
1817 |
if (showMaxMin) {
|
1773 |
1818 |
axisMaxMin = wrap.selectAll('g.nv-axisMaxMin')
|
1774 |
1819 |
.data(scale.domain());
|
1775 |
|
axisMaxMin.enter().append('g').attr('class',function(d,i){
|
|
1820 |
axisMaxMin.enter().append('g').attr('class',function(d,i){
|
1776 |
1821 |
return ['nv-axisMaxMin','nv-axisMaxMin-y',(i == 0 ? 'nv-axisMin-y':'nv-axisMax-y')].join(' ')
|
1777 |
1822 |
}).append('text')
|
1778 |
1823 |
.style('opacity', 0);
|
... | ... | |
1787 |
1832 |
.attr('x', axis.tickPadding())
|
1788 |
1833 |
.style('text-anchor', 'start')
|
1789 |
1834 |
.text(function(d, i) {
|
1790 |
|
var v = fmt(d);
|
|
1835 |
var formatter = tickFormatMaxMin || fmt;
|
|
1836 |
var v = formatter(d);
|
1791 |
1837 |
return ('' + v).match('NaN') ? '' : v;
|
1792 |
1838 |
});
|
1793 |
1839 |
axisMaxMin.watchTransition(renderWatch, 'min-max right')
|
... | ... | |
1831 |
1877 |
.attr('x', -axis.tickPadding())
|
1832 |
1878 |
.attr('text-anchor', 'end')
|
1833 |
1879 |
.text(function(d,i) {
|
1834 |
|
var v = fmt(d);
|
|
1880 |
var formatter = tickFormatMaxMin || fmt;
|
|
1881 |
var v = formatter(d);
|
1835 |
1882 |
return ('' + v).match('NaN') ? '' : v;
|
1836 |
1883 |
});
|
1837 |
1884 |
axisMaxMin.watchTransition(renderWatch, 'min-max right')
|
... | ... | |
1902 |
1949 |
and the arithmetic trick below solves that.
|
1903 |
1950 |
*/
|
1904 |
1951 |
return !parseFloat(Math.round(d * 100000) / 1000000) && (d !== undefined)
|
1905 |
|
})
|
|
1952 |
})
|
1906 |
1953 |
.classed('zero', true);
|
1907 |
|
|
|
1954 |
|
1908 |
1955 |
//store old scales for use in transitions on update
|
1909 |
1956 |
scale0 = scale.copy();
|
1910 |
1957 |
|
... | ... | |
1935 |
1982 |
ticks: {get: function(){return ticks;}, set: function(_){ticks=_;}},
|
1936 |
1983 |
width: {get: function(){return width;}, set: function(_){width=_;}},
|
1937 |
1984 |
fontSize: {get: function(){return fontSize;}, set: function(_){fontSize=_;}},
|
|
1985 |
tickFormatMaxMin: {get: function(){return tickFormatMaxMin;}, set: function(_){tickFormatMaxMin=_;}},
|
1938 |
1986 |
|
1939 |
1987 |
// options that require extra logic in the setter
|
1940 |
1988 |
margin: {get: function(){return margin;}, set: function(_){
|
... | ... | |
2070 |
2118 |
boxEnter.each(function(d,i) {
|
2071 |
2119 |
var box = d3.select(this);
|
2072 |
2120 |
[getWl, getWh].forEach(function (f) {
|
2073 |
|
if (f(d)) {
|
|
2121 |
if (f(d) !== undefined && f(d) !== null) {
|
2074 |
2122 |
var key = (f === getWl) ? 'low' : 'high';
|
2075 |
2123 |
box.append('line')
|
2076 |
2124 |
.style('stroke', getColor(d) || color(d,i))
|
... | ... | |
2535 |
2583 |
, reverse = false
|
2536 |
2584 |
, ranges = function(d) { return d.ranges }
|
2537 |
2585 |
, markers = function(d) { return d.markers ? d.markers : [] }
|
|
2586 |
, markerLines = function(d) { return d.markerLines ? d.markerLines : [0] }
|
2538 |
2587 |
, measures = function(d) { return d.measures }
|
2539 |
2588 |
, rangeLabels = function(d) { return d.rangeLabels ? d.rangeLabels : [] }
|
2540 |
2589 |
, markerLabels = function(d) { return d.markerLabels ? d.markerLabels : [] }
|
|
2590 |
, markerLineLabels = function(d) { return d.markerLineLabels ? d.markerLineLabels : [] }
|
2541 |
2591 |
, measureLabels = function(d) { return d.measureLabels ? d.measureLabels : [] }
|
2542 |
2592 |
, forceX = [0] // List of numbers to Force into the X scale (ie. 0, or a max / min, etc.)
|
2543 |
2593 |
, width = 380
|
... | ... | |
2548 |
2598 |
, dispatch = d3.dispatch('elementMouseover', 'elementMouseout', 'elementMousemove')
|
2549 |
2599 |
, defaultRangeLabels = ["Maximum", "Mean", "Minimum"]
|
2550 |
2600 |
, legacyRangeClassNames = ["Max", "Avg", "Min"]
|
|
2601 |
, duration = 1000
|
2551 |
2602 |
;
|
2552 |
2603 |
|
2553 |
2604 |
function sortLabels(labels, values){
|
... | ... | |
2569 |
2620 |
|
2570 |
2621 |
var rangez = ranges.call(this, d, i).slice(),
|
2571 |
2622 |
markerz = markers.call(this, d, i).slice(),
|
|
2623 |
markerLinez = markerLines.call(this, d, i).slice(),
|
2572 |
2624 |
measurez = measures.call(this, d, i).slice(),
|
2573 |
2625 |
rangeLabelz = rangeLabels.call(this, d, i).slice(),
|
2574 |
2626 |
markerLabelz = markerLabels.call(this, d, i).slice(),
|
|
2627 |
markerLineLabelz = markerLineLabels.call(this, d, i).slice(),
|
2575 |
2628 |
measureLabelz = measureLabels.call(this, d, i).slice();
|
2576 |
2629 |
|
2577 |
2630 |
// Sort labels according to their sorted values
|
2578 |
2631 |
sortLabels(rangeLabelz, rangez);
|
2579 |
2632 |
sortLabels(markerLabelz, markerz);
|
|
2633 |
sortLabels(markerLineLabelz, markerLinez);
|
2580 |
2634 |
sortLabels(measureLabelz, measurez);
|
2581 |
2635 |
|
2582 |
2636 |
// sort values descending
|
2583 |
2637 |
rangez.sort(d3.descending);
|
2584 |
2638 |
markerz.sort(d3.descending);
|
|
2639 |
markerLinez.sort(d3.descending);
|
2585 |
2640 |
measurez.sort(d3.descending);
|
2586 |
2641 |
|
2587 |
2642 |
// Setup Scales
|
... | ... | |
2628 |
2683 |
for(var i=0,il=rangez.length; i<il; i++){
|
2629 |
2684 |
var range = rangez[i];
|
2630 |
2685 |
g.select('rect.nv-range'+i)
|
|
2686 |
.datum(range)
|
2631 |
2687 |
.attr('height', availableHeight)
|
|
2688 |
.transition()
|
|
2689 |
.duration(duration)
|
2632 |
2690 |
.attr('width', w1(range))
|
2633 |
2691 |
.attr('x', xp1(range))
|
2634 |
|
.datum(range)
|
2635 |
2692 |
}
|
2636 |
2693 |
|
2637 |
2694 |
g.select('rect.nv-measure')
|
2638 |
2695 |
.style('fill', color)
|
2639 |
2696 |
.attr('height', availableHeight / 3)
|
2640 |
2697 |
.attr('y', availableHeight / 3)
|
2641 |
|
.attr('width', measurez < 0 ?
|
2642 |
|
x1(0) - x1(measurez[0])
|
2643 |
|
: x1(measurez[0]) - x1(0))
|
2644 |
|
.attr('x', xp1(measurez))
|
2645 |
2698 |
.on('mouseover', function() {
|
2646 |
2699 |
dispatch.elementMouseover({
|
2647 |
2700 |
value: measurez[0],
|
... | ... | |
2662 |
2715 |
label: measureLabelz[0] || 'Current',
|
2663 |
2716 |
color: d3.select(this).style("fill")
|
2664 |
2717 |
})
|
2665 |
|
});
|
|
2718 |
})
|
|
2719 |
.transition()
|
|
2720 |
.duration(duration)
|
|
2721 |
.attr('width', measurez < 0 ?
|
|
2722 |
x1(0) - x1(measurez[0])
|
|
2723 |
: x1(measurez[0]) - x1(0))
|
|
2724 |
.attr('x', xp1(measurez));
|
2666 |
2725 |
|
2667 |
2726 |
var h3 = availableHeight / 6;
|
2668 |
2727 |
|
... | ... | |
2702 |
2761 |
|
2703 |
2762 |
g.selectAll("path.nv-markerTriangle")
|
2704 |
2763 |
.data(markerData)
|
|
2764 |
.transition()
|
|
2765 |
.duration(duration)
|
2705 |
2766 |
.attr('transform', function(d) { return 'translate(' + x1(d.value) + ',' + (availableHeight / 2) + ')' });
|
2706 |
2767 |
|
|
2768 |
var markerLinesData = markerLinez.map( function(marker, index) {
|
|
2769 |
return {value: marker, label: markerLineLabelz[index]}
|
|
2770 |
});
|
|
2771 |
gEnter
|
|
2772 |
.selectAll("line.nv-markerLine")
|
|
2773 |
.data(markerLinesData)
|
|
2774 |
.enter()
|
|
2775 |
.append('line')
|
|
2776 |
.attr('cursor', '')
|
|
2777 |
.attr('class', 'nv-markerLine')
|
|
2778 |
.attr('x1', function(d) { return x1(d.value) })
|
|
2779 |
.attr('y1', '2')
|
|
2780 |
.attr('x2', function(d) { return x1(d.value) })
|
|
2781 |
.attr('y2', availableHeight - 2)
|
|
2782 |
.on('mouseover', function(d) {
|
|
2783 |
dispatch.elementMouseover({
|
|
2784 |
value: d.value,
|
|
2785 |
label: d.label || 'Previous',
|
|
2786 |
color: d3.select(this).style("fill"),
|
|
2787 |
pos: [x1(d.value), availableHeight/2]
|
|
2788 |
})
|
|
2789 |
|
|
2790 |
})
|
|
2791 |
.on('mousemove', function(d) {
|
|
2792 |
dispatch.elementMousemove({
|
|
2793 |
value: d.value,
|
|
2794 |
label: d.label || 'Previous',
|
|
2795 |
color: d3.select(this).style("fill")
|
|
2796 |
})
|
|
2797 |
})
|
|
2798 |
.on('mouseout', function(d, i) {
|
|
2799 |
dispatch.elementMouseout({
|
|
2800 |
value: d.value,
|
|
2801 |
label: d.label || 'Previous',
|
|
2802 |
color: d3.select(this).style("fill")
|
|
2803 |
})
|
|
2804 |
});
|
|
2805 |
|
|
2806 |
g.selectAll("line.nv-markerLine")
|
|
2807 |
.data(markerLinesData)
|
|
2808 |
.transition()
|
|
2809 |
.duration(duration)
|
|
2810 |
.attr('x1', function(d) { return x1(d.value) })
|
|
2811 |
.attr('x2', function(d) { return x1(d.value) });
|
|
2812 |
|
2707 |
2813 |
wrap.selectAll('.nv-range')
|
2708 |
2814 |
.on('mouseover', function(d,i) {
|
2709 |
2815 |
var label = rangeLabelz[i] || defaultRangeLabels[i];
|
... | ... | |
2749 |
2855 |
width: {get: function(){return width;}, set: function(_){width=_;}},
|
2750 |
2856 |
height: {get: function(){return height;}, set: function(_){height=_;}},
|
2751 |
2857 |
tickFormat: {get: function(){return tickFormat;}, set: function(_){tickFormat=_;}},
|
|
2858 |
duration: {get: function(){return duration;}, set: function(_){duration=_;}},
|
2752 |
2859 |
|
2753 |
2860 |
// options that require extra logic in the setter
|
2754 |
2861 |
margin: {get: function(){return margin;}, set: function(_){
|
... | ... | |
2794 |
2901 |
, width = null
|
2795 |
2902 |
, height = 55
|
2796 |
2903 |
, tickFormat = null
|
2797 |
|
, ticks = null
|
|
2904 |
, ticks = null
|
2798 |
2905 |
, noData = null
|
2799 |
2906 |
, dispatch = d3.dispatch()
|
2800 |
2907 |
;
|
... | ... | |
2868 |
2975 |
|
2869 |
2976 |
bullet
|
2870 |
2977 |
.width(availableWidth)
|
2871 |
|
.height(availableHeight)
|
|
2978 |
.height(availableHeight);
|
2872 |
2979 |
|
2873 |
2980 |
var bulletWrap = g.select('.nv-bulletWrap');
|
2874 |
2981 |
d3.transition(bulletWrap).call(bullet);
|
... | ... | |
2900 |
3007 |
|
2901 |
3008 |
// Transition the updating ticks to the new scale, x1.
|
2902 |
3009 |
var tickUpdate = d3.transition(tick)
|
|
3010 |
.transition()
|
|
3011 |
.duration(bullet.duration())
|
2903 |
3012 |
.attr('transform', function(d) { return 'translate(' + x1(d) + ',0)' })
|
2904 |
3013 |
.style('opacity', 1);
|
2905 |
3014 |
|
... | ... | |
2912 |
3021 |
|
2913 |
3022 |
// Transition the exiting ticks to the new scale, x1.
|
2914 |
3023 |
d3.transition(tick.exit())
|
|
3024 |
.transition()
|
|
3025 |
.duration(bullet.duration())
|
2915 |
3026 |
.attr('transform', function(d) { return 'translate(' + x1(d) + ',0)' })
|
2916 |
3027 |
.style('opacity', 1e-6)
|
2917 |
3028 |
.remove();
|
... | ... | |
3227 |
3338 |
;
|
3228 |
3339 |
|
3229 |
3340 |
var margin = {top: 30, right: 30, bottom: 50, left: 60}
|
|
3341 |
, marginTop = null
|
3230 |
3342 |
, color = nv.utils.defaultColor()
|
3231 |
3343 |
, width = null
|
3232 |
3344 |
, height = null
|
... | ... | |
3271 |
3383 |
var dx = d3.scale.linear()
|
3272 |
3384 |
, index = {i: 0, x: 0}
|
3273 |
3385 |
, renderWatch = nv.utils.renderWatch(dispatch, duration)
|
|
3386 |
, currentYDomain
|
3274 |
3387 |
;
|
3275 |
3388 |
|
3276 |
3389 |
var stateGetter = function(data) {
|
... | ... | |
3375 |
3488 |
x = lines.xScale();
|
3376 |
3489 |
y = lines.yScale();
|
3377 |
3490 |
|
3378 |
|
if (!rescaleY) {
|
3379 |
|
var seriesDomains = data
|
3380 |
|
.filter(function(series) { return !series.disabled })
|
3381 |
|
.map(function(series,i) {
|
3382 |
|
var initialDomain = d3.extent(series.values, lines.y());
|
3383 |
|
|
3384 |
|
//account for series being disabled when losing 95% or more
|
3385 |
|
if (initialDomain[0] < -.95) initialDomain[0] = -.95;
|
3386 |
|
|
3387 |
|
return [
|
3388 |
|
(initialDomain[0] - initialDomain[1]) / (1 + initialDomain[1]),
|
3389 |
|
(initialDomain[1] - initialDomain[0]) / (1 + initialDomain[0])
|
3390 |
|
];
|
3391 |
|
});
|
3392 |
|
|
3393 |
|
var completeDomain = [
|
3394 |
|
d3.min(seriesDomains, function(d) { return d[0] }),
|
3395 |
|
d3.max(seriesDomains, function(d) { return d[1] })
|
3396 |
|
];
|
3397 |
|
|
3398 |
|
lines.yDomain(completeDomain);
|
3399 |
|
} else {
|
3400 |
|
lines.yDomain(null);
|
3401 |
|
}
|
3402 |
3491 |
|
3403 |
3492 |
dx.domain([0, data[0].values.length - 1]) //Assumes all series have same length
|
3404 |
3493 |
.range([0, availableWidth])
|
... | ... | |
3406 |
3495 |
|
3407 |
3496 |
var data = indexify(index.i, data);
|
3408 |
3497 |
|
|
3498 |
// initialize the starting yDomain for the not-rescale case after indexify (to have calculated point.display)
|
|
3499 |
if (typeof(currentYDomain) === "undefined") {
|
|
3500 |
currentYDomain = getCurrentYDomain(data);
|
|
3501 |
}
|
|
3502 |
|
|
3503 |
if (!rescaleY) {
|
|
3504 |
lines.yDomain(currentYDomain);
|
|
3505 |
lines.clipEdge(true);
|
|
3506 |
} else {
|
|
3507 |
lines.yDomain(null);
|
|
3508 |
}
|
|
3509 |
|
3409 |
3510 |
// Setup containers and skeleton of chart
|
3410 |
3511 |
var interactivePointerEvents = (useInteractiveGuideline) ? "none" : "all";
|
3411 |
3512 |
var wrap = container.selectAll('g.nv-wrap.nv-cumulativeLine').data([data]);
|
... | ... | |
3431 |
3532 |
.datum(data)
|
3432 |
3533 |
.call(legend);
|
3433 |
3534 |
|
3434 |
|
if ( margin.top != legend.height()) {
|
|
3535 |
if (!marginTop && legend.height() !== margin.top) {
|
3435 |
3536 |
margin.top = legend.height();
|
3436 |
3537 |
availableHeight = nv.utils.availableHeight(height, container, margin);
|
3437 |
3538 |
}
|
... | ... | |
3468 |
3569 |
.attr("transform", "translate(" + availableWidth + ",0)");
|
3469 |
3570 |
}
|
3470 |
3571 |
|
3471 |
|
// Show error if series goes below 100%
|
|
3572 |
// Show error if index point value is 0 (division by zero avoided)
|
3472 |
3573 |
var tempDisabled = data.filter(function(d) { return d.tempDisabled });
|
3473 |
3574 |
|
3474 |
3575 |
wrap.select('.tempDisabled').remove(); //clean-up and prevent duplicates
|
... | ... | |
3638 |
3739 |
controls.dispatch.on('legendClick', function(d,i) {
|
3639 |
3740 |
d.disabled = !d.disabled;
|
3640 |
3741 |
rescaleY = !d.disabled;
|
3641 |
|
|
3642 |
3742 |
state.rescaleY = rescaleY;
|
|
3743 |
if (!rescaleY) {
|
|
3744 |
currentYDomain = getCurrentYDomain(data); // rescale is turned off, so set the currentYDomain
|
|
3745 |
}
|
3643 |
3746 |
dispatch.stateChange(state);
|
3644 |
3747 |
chart.update();
|
3645 |
3748 |
});
|
... | ... | |
3658 |
3761 |
data
|
3659 |
3762 |
.filter(function(series, i) {
|
3660 |
3763 |
series.seriesIndex = i;
|
3661 |
|
return !series.disabled;
|
|
3764 |
return !(series.disabled || series.tempDisabled);
|
3662 |
3765 |
})
|
3663 |
3766 |
.forEach(function(series,i) {
|
3664 |
3767 |
pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x());
|
... | ... | |
3686 |
3789 |
|
3687 |
3790 |
var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex), pointIndex);
|
3688 |
3791 |
interactiveLayer.tooltip
|
3689 |
|
.chartContainer(that.parentNode)
|
3690 |
3792 |
.valueFormatter(function(d,i) {
|
3691 |
3793 |
return yAxis.tickFormat()(d);
|
3692 |
3794 |
})
|
... | ... | |
3774 |
3876 |
}
|
3775 |
3877 |
var v = indexifyYGetter(indexValue, idx);
|
3776 |
3878 |
|
3777 |
|
//TODO: implement check below, and disable series if series loses 100% or more cause divide by 0 issue
|
3778 |
|
if (v < -.95 && !noErrorCheck) {
|
3779 |
|
//if a series loses more than 100%, calculations fail.. anything close can cause major distortion (but is mathematically correct till it hits 100)
|
3780 |
|
|
|
3879 |
// avoid divide by zero
|
|
3880 |
if (Math.abs(v) < 0.00001 && !noErrorCheck) {
|
3781 |
3881 |
line.tempDisabled = true;
|
3782 |
3882 |
return line;
|
3783 |
3883 |
}
|
... | ... | |
3785 |
3885 |
line.tempDisabled = false;
|
3786 |
3886 |
|
3787 |
3887 |
line.values = line.values.map(function(point, pointIndex) {
|
3788 |
|
point.display = {'y': (indexifyYGetter(point, pointIndex) - v) / (1 + v) };
|
|
3888 |
point.display = {'y': (indexifyYGetter(point, pointIndex) - v) / v };
|
3789 |
3889 |
return point;
|
3790 |
3890 |
});
|
3791 |
3891 |
|
... | ... | |
3793 |
3893 |
})
|
3794 |
3894 |
}
|
3795 |
3895 |
|
|
3896 |
function getCurrentYDomain(data) {
|
|
3897 |
var seriesDomains = data
|
|
3898 |
.filter(function(series) { return !(series.disabled || series.tempDisabled)})
|
|
3899 |
.map(function(series,i) {
|
|
3900 |
return d3.extent(series.values, function (d) { return d.display.y });
|
|
3901 |
});
|
|
3902 |
|
|
3903 |
return [
|
|
3904 |
d3.min(seriesDomains, function(d) { return d[0] }),
|
|
3905 |
d3.max(seriesDomains, function(d) { return d[1] })
|
|
3906 |
];
|
|
3907 |
}
|
|
3908 |
|
3796 |
3909 |
//============================================================
|
3797 |
3910 |
// Expose Public Variables
|
3798 |
3911 |
//------------------------------------------------------------
|
... | ... | |
3814 |
3927 |
// simple options, just get/set the necessary values
|
3815 |
3928 |
width: {get: function(){return width;}, set: function(_){width=_;}},
|
3816 |
3929 |
height: {get: function(){return height;}, set: function(_){height=_;}},
|
3817 |
|
rescaleY: {get: function(){return rescaleY;}, set: function(_){rescaleY=_;}},
|
3818 |
3930 |
showControls: {get: function(){return showControls;}, set: function(_){showControls=_;}},
|
3819 |
3931 |
showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
|
3820 |
3932 |
average: {get: function(){return average;}, set: function(_){average=_;}},
|
... | ... | |
3825 |
3937 |
noErrorCheck: {get: function(){return noErrorCheck;}, set: function(_){noErrorCheck=_;}},
|
3826 |
3938 |
|
3827 |
3939 |
// options that require extra logic in the setter
|
|
3940 |
rescaleY: {get: function(){return rescaleY;}, set: function(_){
|
|
3941 |
rescaleY = _;
|
|
3942 |
chart.state.rescaleY = _; // also update state
|
|
3943 |
}},
|
3828 |
3944 |
margin: {get: function(){return margin;}, set: function(_){
|
3829 |
|
margin.top = _.top !== undefined ? _.top : margin.top;
|
|
3945 |
if (_.top !== undefined) {
|
|
3946 |
margin.top = _.top;
|
|
3947 |
marginTop = _.top;
|
|
3948 |
}
|
3830 |
3949 |
margin.right = _.right !== undefined ? _.right : margin.right;
|
3831 |
3950 |
margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
|
3832 |
3951 |
margin.left = _.left !== undefined ? _.left : margin.left;
|
... | ... | |
4125 |
4244 |
var discretebar = nv.models.discreteBar()
|
4126 |
4245 |
, xAxis = nv.models.axis()
|
4127 |
4246 |
, yAxis = nv.models.axis()
|
4128 |
|
, legend = nv.models.legend()
|
|
4247 |
, legend = nv.models.legend()
|
4129 |
4248 |
, tooltip = nv.models.tooltip()
|
4130 |
4249 |
;
|
4131 |
4250 |
|
4132 |
4251 |
var margin = {top: 15, right: 10, bottom: 50, left: 60}
|
|
4252 |
, marginTop = null
|
4133 |
4253 |
, width = null
|
4134 |
4254 |
, height = null
|
4135 |
4255 |
, color = nv.utils.getColor()
|
4136 |
|
, showLegend = false
|
|
4256 |
, showLegend = false
|
4137 |
4257 |
, showXAxis = true
|
4138 |
4258 |
, showYAxis = true
|
4139 |
4259 |
, rightAlignYAxis = false
|
... | ... | |
4216 |
4336 |
.append('line');
|
4217 |
4337 |
|
4218 |
4338 |
gEnter.append('g').attr('class', 'nv-barsWrap');
|
4219 |
|
gEnter.append('g').attr('class', 'nv-legendWrap');
|
|
4339 |
gEnter.append('g').attr('class', 'nv-legendWrap');
|
4220 |
4340 |
|
4221 |
4341 |
g.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
|
4222 |
4342 |
|
... | ... | |
4230 |
4350 |
.datum(data)
|
4231 |
4351 |
.call(legend);
|
4232 |
4352 |
|
4233 |
|
if ( margin.top != legend.height()) {
|
|
4353 |
if (!marginTop && legend.height() !== margin.top) {
|
4234 |
4354 |
margin.top = legend.height();
|
4235 |
4355 |
availableHeight = nv.utils.availableHeight(height, container, margin);
|
4236 |
4356 |
}
|
... | ... | |
4238 |
4358 |
wrap.select('.nv-legendWrap')
|
4239 |
4359 |
.attr('transform', 'translate(0,' + (-margin.top) +')')
|
4240 |
4360 |
}
|
4241 |
|
|
|
4361 |
|
4242 |
4362 |
if (rightAlignYAxis) {
|
4243 |
4363 |
g.select(".nv-y.nv-axis")
|
4244 |
4364 |
.attr("transform", "translate(" + availableWidth + ",0)");
|
4245 |
|
}
|
|
4365 |
}
|
4246 |
4366 |
|
4247 |
4367 |
// Main Chart Component(s)
|
4248 |
4368 |
discretebar
|
... | ... | |
4355 |
4475 |
// simple options, just get/set the necessary values
|
4356 |
4476 |
width: {get: function(){return width;}, set: function(_){width=_;}},
|
4357 |
4477 |
height: {get: function(){return height;}, set: function(_){height=_;}},
|
4358 |
|
showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
|
|
4478 |
showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
|
4359 |
4479 |
staggerLabels: {get: function(){return staggerLabels;}, set: function(_){staggerLabels=_;}},
|
4360 |
4480 |
rotateLabels: {get: function(){return rotateLabels;}, set: function(_){rotateLabels=_;}},
|
4361 |
4481 |
wrapLabels: {get: function(){return wrapLabels;}, set: function(_){wrapLabels=!!_;}},
|
... | ... | |
4365 |
4485 |
|
4366 |
4486 |
// options that require extra logic in the setter
|
4367 |
4487 |
margin: {get: function(){return margin;}, set: function(_){
|
4368 |
|
margin.top = _.top !== undefined ? _.top : margin.top;
|
|
4488 |
if (_.top !== undefined) {
|
|
4489 |
margin.top = _.top;
|
|
4490 |
marginTop = _.top;
|
|
4491 |
}
|
4369 |
4492 |
margin.right = _.right !== undefined ? _.right : margin.right;
|
4370 |
4493 |
margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
|
4371 |
4494 |
margin.left = _.left !== undefined ? _.left : margin.left;
|
... | ... | |
4380 |
4503 |
color: {get: function(){return color;}, set: function(_){
|
4381 |
4504 |
color = nv.utils.getColor(_);
|
4382 |
4505 |
discretebar.color(color);
|
4383 |
|
legend.color(color);
|
|
4506 |
legend.color(color);
|
4384 |
4507 |
}},
|
4385 |
4508 |
rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){
|
4386 |
4509 |
rightAlignYAxis = _;
|
... | ... | |
4553 |
4676 |
|
4554 |
4677 |
return chart;
|
4555 |
4678 |
}
|
4556 |
|
nv.models.forceDirectedGraph = function() {
|
|
4679 |
nv.models.focus = function(content) {
|
4557 |
4680 |
"use strict";
|
4558 |
4681 |
|
4559 |
4682 |
//============================================================
|
4560 |
4683 |
// Public Variables with Default Settings
|
4561 |
4684 |
//------------------------------------------------------------
|
4562 |
|
var margin = {top: 2, right: 0, bottom: 2, left: 0}
|
4563 |
|
, width = 400
|
4564 |
|
, height = 32
|
4565 |
|
, container = null
|
4566 |
|
, dispatch = d3.dispatch('renderEnd')
|
4567 |
|
, color = nv.utils.getColor(['#000'])
|
4568 |
|
, tooltip = nv.models.tooltip()
|
4569 |
|
, noData = null
|
4570 |
|
// Force directed graph specific parameters [default values]
|
4571 |
|
, linkStrength = 0.1
|
4572 |
|
, friction = 0.9
|
4573 |
|
, linkDist = 30
|
4574 |
|
, charge = -120
|
4575 |
|
, gravity = 0.1
|
4576 |
|
, theta = 0.8
|
4577 |
|
, alpha = 0.1
|
4578 |
|
, radius = 5
|
4579 |
|
// These functions allow to add extra attributes to ndes and links
|
4580 |
|
,nodeExtras = function(nodes) { /* Do nothing */ }
|
4581 |
|
,linkExtras = function(links) { /* Do nothing */ }
|
|
4685 |
|
|
4686 |
var content = content || nv.models.line()
|
|
4687 |
, xAxis = nv.models.axis()
|
|
4688 |
, yAxis = nv.models.axis()
|
|
4689 |
, brush = d3.svg.brush()
|
|
4690 |
;
|
|
4691 |
|
|
4692 |
var margin = {top: 10, right: 0, bottom: 30, left: 0}
|
|
4693 |
, color = nv.utils.defaultColor()
|
|
4694 |
, width = null
|
|
4695 |
, height = 70
|
|
4696 |
, showXAxis = true
|
|
4697 |
, showYAxis = false
|
|
4698 |
, rightAlignYAxis = false
|
|
4699 |
, ticks = null
|
|
4700 |
, x
|
|
4701 |
, y
|
|
4702 |
, brushExtent = null
|
|
4703 |
, duration = 250
|
|
4704 |
, dispatch = d3.dispatch('brush', 'onBrush', 'renderEnd')
|
|
4705 |
, syncBrushing = true
|
4582 |
4706 |
;
|
4583 |
4707 |
|
|
4708 |
content.interactive(false);
|
|
4709 |
content.pointActive(function(d) { return false; });
|
4584 |
4710 |
|
4585 |
4711 |
//============================================================
|
4586 |
4712 |
// Private Variables
|
4587 |
4713 |
//------------------------------------------------------------
|
4588 |
4714 |
|
4589 |
|
var renderWatch = nv.utils.renderWatch(dispatch);
|
|
4715 |
var renderWatch = nv.utils.renderWatch(dispatch, duration);
|
4590 |
4716 |
|
4591 |
4717 |
function chart(selection) {
|
4592 |
4718 |
renderWatch.reset();
|
|
4719 |
renderWatch.models(content);
|
|
4720 |
if (showXAxis) renderWatch.models(xAxis);
|
|
4721 |
if (showYAxis) renderWatch.models(yAxis);
|
4593 |
4722 |
|
4594 |
4723 |
selection.each(function(data) {
|
4595 |
|
container = d3.select(this);
|
4596 |
|
nv.utils.initSVG(container);
|
|
4724 |
var container = d3.select(this);
|
|
4725 |
nv.utils.initSVG(container);
|
|
4726 |
var availableWidth = nv.utils.availableWidth(width, container, margin),
|
|
4727 |
availableHeight = height - margin.top - margin.bottom;
|
4597 |
4728 |
|
4598 |
|
var availableWidth = nv.utils.availableWidth(width, container, margin),
|
4599 |
|
availableHeight = nv.utils.availableHeight(height, container, margin);
|
|
4729 |
chart.update = function() {
|
|
4730 |
if( duration === 0 ) {
|
|
4731 |
container.call( chart );
|
|
4732 |
} else {
|
|
4733 |
container.transition().duration(duration).call(chart);
|
|
4734 |
}
|
|
4735 |
};
|
|
4736 |
chart.container = this;
|
4600 |
4737 |
|
4601 |
|
container
|
4602 |
|
.attr("width", availableWidth)
|
4603 |
|
.attr("height", availableHeight);
|
|
4738 |
// Setup Scales
|
|
4739 |
x = content.xScale();
|
|
4740 |
y = content.yScale();
|
4604 |
4741 |
|
4605 |
|
// Display No Data message if there's nothing to show.
|
4606 |
|
if (!data || !data.links || !data.nodes) {
|
4607 |
|
nv.utils.noData(chart, container)
|
4608 |
|
return chart;
|
4609 |
|
} else {
|
4610 |
|
container.selectAll('.nv-noData').remove();
|
4611 |
|
}
|
4612 |
|
container.selectAll('*').remove();
|
|
4742 |
// Setup containers and skeleton of chart
|
|
4743 |
var wrap = container.selectAll('g.nv-focus').data([data]);
|
|
4744 |
var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-focus').append('g');
|
|
4745 |
var g = wrap.select('g');
|
4613 |
4746 |
|
4614 |
|
// Collect names of all fields in the nodes
|
4615 |
|
var nodeFieldSet = new Set();
|
4616 |
|
data.nodes.forEach(function(node) {
|
4617 |
|
var keys = Object.keys(node);
|
4618 |
|
keys.forEach(function(key) {
|
4619 |
|
nodeFieldSet.add(key);
|
4620 |
|
});
|
4621 |
|
});
|
|
4747 |
wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
|
4622 |
4748 |
|
4623 |
|
var force = d3.layout.force()
|
4624 |
|
.nodes(data.nodes)
|
4625 |
|
.links(data.links)
|
4626 |
|
.size([availableWidth, availableHeight])
|
4627 |
|
.linkStrength(linkStrength)
|
4628 |
|
.friction(friction)
|
4629 |
|
.linkDistance(linkDist)
|
4630 |
|
.charge(charge)
|
4631 |
|
.gravity(gravity)
|
4632 |
|
.theta(theta)
|
4633 |
|
.alpha(alpha)
|
4634 |
|
.start();
|
|
4749 |
gEnter.append('g').attr('class', 'nv-background').append('rect');
|
|
4750 |
gEnter.append('g').attr('class', 'nv-x nv-axis');
|
|
4751 |
gEnter.append('g').attr('class', 'nv-y nv-axis');
|
|
4752 |
gEnter.append('g').attr('class', 'nv-contentWrap');
|
|
4753 |
gEnter.append('g').attr('class', 'nv-brushBackground');
|
|
4754 |
gEnter.append('g').attr('class', 'nv-x nv-brush');
|
4635 |
4755 |
|
4636 |
|
var link = container.selectAll(".link")
|
4637 |
|
.data(data.links)
|
4638 |
|
.enter().append("line")
|
4639 |
|
.attr("class", "nv-force-link")
|
4640 |
|
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
|
|
4756 |
if (rightAlignYAxis) {
|
|
4757 |
g.select(".nv-y.nv-axis")
|
|
4758 |
.attr("transform", "translate(" + availableWidth + ",0)");
|
|
4759 |
}
|
4641 |
4760 |
|
4642 |
|
var node = container.selectAll(".node")
|
4643 |
|
.data(data.nodes)
|
4644 |
|
.enter()
|
4645 |
|
.append("g")
|
4646 |
|
.attr("class", "nv-force-node")
|
4647 |
|
.call(force.drag);
|
|
4761 |
g.select('.nv-background rect')
|
|
4762 |
.attr('width', availableWidth)
|
|
4763 |
.attr('height', availableHeight);
|
|
4764 |
|
|
4765 |
content
|
|
4766 |
.width(availableWidth)
|
|
4767 |
.height(availableHeight)
|
|
4768 |
.color(data.map(function(d,i) {
|
|
4769 |
return d.color || color(d, i);
|
|
4770 |
}).filter(function(d,i) { return !data[i].disabled; }));
|
4648 |
4771 |
|
4649 |
|
node
|
4650 |
|
.append("circle")
|
4651 |
|
.attr("r", radius)
|
4652 |
|
.style("fill", function(d) { return color(d) } )
|
4653 |
|
.on("mouseover", function(evt) {
|
4654 |
|
container.select('.nv-series-' + evt.seriesIndex + ' .nv-distx-' + evt.pointIndex)
|
4655 |
|
.attr('y1', evt.py);
|
4656 |
|
container.select('.nv-series-' + evt.seriesIndex + ' .nv-disty-' + evt.pointIndex)
|
|
4772 |
var contentWrap = g.select('.nv-contentWrap')
|
|
4773 |
.datum(data.filter(function(d) { return !d.disabled; }));
|
|
4774 |
|
|
4775 |
d3.transition(contentWrap).call(content);
|
|
4776 |
|
|
4777 |
// Setup Brush
|
|
4778 |
brush
|
|
4779 |
.x(x)
|
|
4780 |
.on('brush', function() {
|
|
4781 |
onBrush(syncBrushing);
|
|
4782 |
});
|
|
4783 |
|
|
4784 |
brush.on('brushend', function () {
|
|
4785 |
if (!syncBrushing) {
|
|
4786 |
dispatch.onBrush(brush.empty() ? x.domain() : brush.extent());
|
|
4787 |
}
|
|
4788 |
});
|
|
4789 |
|
|
4790 |
if (brushExtent) brush.extent(brushExtent);
|
|
4791 |
|
|
4792 |
var brushBG = g.select('.nv-brushBackground').selectAll('g')
|
|
4793 |
.data([brushExtent || brush.extent()]);
|
|
4794 |
|
|
4795 |
var brushBGenter = brushBG.enter()
|
|
4796 |
.append('g');
|
|
4797 |
|
|
4798 |
brushBGenter.append('rect')
|
|
4799 |
.attr('class', 'left')
|
|
4800 |
.attr('x', 0)
|
|
4801 |
.attr('y', 0)
|
|
4802 |
.attr('height', availableHeight);
|
|
4803 |
|
|
4804 |
brushBGenter.append('rect')
|
|
4805 |
.attr('class', 'right')
|
|
4806 |
.attr('x', 0)
|
|
4807 |
.attr('y', 0)
|
|
4808 |
.attr('height', availableHeight);
|
|
4809 |
|
|
4810 |
var gBrush = g.select('.nv-x.nv-brush')
|
|
4811 |
.call(brush);
|
|
4812 |
gBrush.selectAll('rect')
|
|
4813 |
.attr('height', availableHeight);
|
|
4814 |
gBrush.selectAll('.resize').append('path').attr('d', resizePath);
|
|
4815 |
|
|
4816 |
onBrush(true);
|
|
4817 |
|
|
4818 |
g.select('.nv-background rect')
|
|
4819 |
.attr('width', availableWidth)
|
|
4820 |
.attr('height', availableHeight);
|
|
4821 |
|
|
4822 |
if (showXAxis) {
|
|
4823 |
xAxis.scale(x)
|
|
4824 |
._ticks( nv.utils.calcTicksX(availableWidth/100, data) )
|
|
4825 |
.tickSize(-availableHeight, 0);
|
|
4826 |
|
|
4827 |
g.select('.nv-x.nv-axis')
|
|
4828 |
.attr('transform', 'translate(0,' + y.range()[0] + ')');
|
|
4829 |
d3.transition(g.select('.nv-x.nv-axis'))
|
|
4830 |
.call(xAxis);
|
|
4831 |
}
|
|
4832 |
|
|
4833 |
if (showYAxis) {
|
|
4834 |
yAxis
|
|
4835 |
.scale(y)
|
|
4836 |
._ticks( nv.utils.calcTicksY(availableHeight/36, data) )
|
|
4837 |
.tickSize( -availableWidth, 0);
|
|
4838 |
|
|
4839 |
d3.transition(g.select('.nv-y.nv-axis'))
|
|
4840 |
.call(yAxis);
|
|
4841 |
}
|
|
4842 |
|
|
4843 |
g.select('.nv-x.nv-axis')
|
|
4844 |
.attr('transform', 'translate(0,' + y.range()[0] + ')');
|
|
4845 |
|
|
4846 |
//============================================================
|
|
4847 |
// Event Handling/Dispatching (in chart's scope)
|
|
4848 |
//------------------------------------------------------------
|
|
4849 |
|
|
4850 |
//============================================================
|
|
4851 |
// Functions
|
|
4852 |
//------------------------------------------------------------
|
|
4853 |
|
|
4854 |
// Taken from crossfilter (http://square.github.com/crossfilter/)
|
|
4855 |
function resizePath(d) {
|
|
4856 |
var e = +(d == 'e'),
|
|
4857 |
x = e ? 1 : -1,
|
|
4858 |
y = availableHeight / 3;
|
|
4859 |
return 'M' + (0.5 * x) + ',' + y
|
|
4860 |
+ 'A6,6 0 0 ' + e + ' ' + (6.5 * x) + ',' + (y + 6)
|
|
4861 |
+ 'V' + (2 * y - 6)
|
|
4862 |
+ 'A6,6 0 0 ' + e + ' ' + (0.5 * x) + ',' + (2 * y)
|
|
4863 |
+ 'Z'
|
|
4864 |
+ 'M' + (2.5 * x) + ',' + (y + 8)
|
|
4865 |
+ 'V' + (2 * y - 8)
|
|
4866 |
+ 'M' + (4.5 * x) + ',' + (y + 8)
|
|
4867 |
+ 'V' + (2 * y - 8);
|
|
4868 |
}
|
|
4869 |
|
|
4870 |
|
|
4871 |
function updateBrushBG() {
|
|
4872 |
if (!brush.empty()) brush.extent(brushExtent);
|
|
4873 |
brushBG
|
|
4874 |
.data([brush.empty() ? x.domain() : brushExtent])
|
|
4875 |
.each(function(d,i) {
|
|
4876 |
var leftWidth = x(d[0]) - x.range()[0],
|
|
4877 |
rightWidth = availableWidth - x(d[1]);
|
|
4878 |
d3.select(this).select('.left')
|
|
4879 |
.attr('width', leftWidth < 0 ? 0 : leftWidth);
|
|
4880 |
|
|
4881 |
d3.select(this).select('.right')
|
|
4882 |
.attr('x', x(d[1]))
|
|
4883 |
.attr('width', rightWidth < 0 ? 0 : rightWidth);
|
|
4884 |
});
|
|
4885 |
}
|
|
4886 |
|
|
4887 |
|
|
4888 |
function onBrush(shouldDispatch) {
|
|
4889 |
brushExtent = brush.empty() ? null : brush.extent();
|
|
4890 |
var extent = brush.empty() ? x.domain() : brush.extent();
|
|
4891 |
dispatch.brush({extent: extent, brush: brush});
|
|
4892 |
updateBrushBG();
|
|
4893 |
if (shouldDispatch) {
|
|
4894 |
dispatch.onBrush(extent);
|
|
4895 |
}
|
|
4896 |
}
|
|
4897 |
});
|
|
4898 |
|
|
4899 |
renderWatch.renderEnd('focus immediate');
|
|
4900 |
return chart;
|
|
4901 |
}
|
|
4902 |
|
|
4903 |
|
|
4904 |
//============================================================
|
|
4905 |
// Event Handling/Dispatching (out of chart's scope)
|
|
4906 |
//------------------------------------------------------------
|
|
4907 |
|
|
4908 |
//============================================================
|
|
4909 |
// Expose Public Variables
|
|
4910 |
//------------------------------------------------------------
|
|
4911 |
|
|
4912 |
// expose chart's sub-components
|
|
4913 |
chart.dispatch = dispatch;
|
|
4914 |
chart.content = content;
|
|
4915 |
chart.brush = brush;
|
|
4916 |
chart.xAxis = xAxis;
|
|
4917 |
chart.yAxis = yAxis;
|
|
4918 |
chart.options = nv.utils.optionsFunc.bind(chart);
|
|
4919 |
|
|
4920 |
chart._options = Object.create({}, {
|
|
4921 |
// simple options, just get/set the necessary values
|
|
4922 |
width: {get: function(){return width;}, set: function(_){width=_;}},
|
|
4923 |
height: {get: function(){return height;}, set: function(_){height=_;}},
|
|
4924 |
showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}},
|
|
4925 |
showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}},
|
|
4926 |
brushExtent: {get: function(){return brushExtent;}, set: function(_){brushExtent=_;}},
|
|
4927 |
syncBrushing: {get: function(){return syncBrushing;}, set: function(_){syncBrushing=_;}},
|
|
4928 |
|
|
4929 |
// options that require extra logic in the setter
|
|
4930 |
margin: {get: function(){return margin;}, set: function(_){
|
|
4931 |
margin.top = _.top !== undefined ? _.top : margin.top;
|
|
4932 |
margin.right = _.right !== undefined ? _.right : margin.right;
|
|
4933 |
margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
|
|
4934 |
margin.left = _.left !== undefined ? _.left : margin.left;
|
|
4935 |
}},
|
|
4936 |
duration: {get: function(){return duration;}, set: function(_){
|
|
4937 |
duration = _;
|
|
4938 |
renderWatch.reset(duration);
|
|
4939 |
content.duration(duration);
|
|
4940 |
xAxis.duration(duration);
|
|
4941 |
yAxis.duration(duration);
|
|
4942 |
}},
|
|
4943 |
color: {get: function(){return color;}, set: function(_){
|
|
4944 |
color = nv.utils.getColor(_);
|
|
4945 |
content.color(color);
|
|
4946 |
}},
|
Update nvd3. Implement #13537