7388 lines
226 KiB
JavaScript
7388 lines
226 KiB
JavaScript
(function (global, factory) {
|
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-array'), require('d3-scale'), require('d3-time'), require('d3-random'), require('d3-fetch'), require('d3-path'), require('d3-selection'), require('d3-shape'), require('d3-dispatch'), require('d3-brush')) :
|
|
typeof define === 'function' && define.amd ? define(['exports', 'd3-array', 'd3-scale', 'd3-time', 'd3-random', 'd3-fetch', 'd3-path', 'd3-selection', 'd3-shape', 'd3-dispatch', 'd3-brush'], factory) :
|
|
(factory((global.fc = global.fc || {}),global.d3,global.d3,global.d3,global.d3,global.d3,global.d3,global.d3,global.d3,global.d3,global.d3));
|
|
}(this, (function (exports,d3Array,d3Scale,d3Time,d3Random,d3Fetch,d3Path,d3Selection,d3Shape,d3Dispatch,d3Brush) { 'use strict';
|
|
|
|
var createReboundMethod = (function (target, source, name) {
|
|
var method = source[name];
|
|
if (typeof method !== 'function') {
|
|
throw new Error('Attempt to rebind ' + name + ' which isn\'t a function on the source object');
|
|
}
|
|
return function () {
|
|
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
|
args[_key] = arguments[_key];
|
|
}
|
|
|
|
var value = method.apply(source, args);
|
|
return value === source ? target : value;
|
|
};
|
|
});
|
|
|
|
var rebind = (function (target, source) {
|
|
for (var _len = arguments.length, names = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
|
|
names[_key - 2] = arguments[_key];
|
|
}
|
|
|
|
var _iteratorNormalCompletion = true;
|
|
var _didIteratorError = false;
|
|
var _iteratorError = undefined;
|
|
|
|
try {
|
|
for (var _iterator = names[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
var name = _step.value;
|
|
|
|
target[name] = createReboundMethod(target, source, name);
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError = true;
|
|
_iteratorError = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion && _iterator.return) {
|
|
_iterator.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError) {
|
|
throw _iteratorError;
|
|
}
|
|
}
|
|
}
|
|
|
|
return target;
|
|
});
|
|
|
|
var createTransform = function createTransform(transforms) {
|
|
return function (name) {
|
|
return transforms.reduce(function (name, fn) {
|
|
return name && fn(name);
|
|
}, name);
|
|
};
|
|
};
|
|
|
|
var rebindAll = (function (target, source) {
|
|
for (var _len = arguments.length, transforms = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
|
|
transforms[_key - 2] = arguments[_key];
|
|
}
|
|
|
|
var transform = createTransform(transforms);
|
|
var _iteratorNormalCompletion = true;
|
|
var _didIteratorError = false;
|
|
var _iteratorError = undefined;
|
|
|
|
try {
|
|
for (var _iterator = Object.keys(source)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
var name = _step.value;
|
|
|
|
var result = transform(name);
|
|
if (result) {
|
|
target[result] = createReboundMethod(target, source, name);
|
|
}
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError = true;
|
|
_iteratorError = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion && _iterator.return) {
|
|
_iterator.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError) {
|
|
throw _iteratorError;
|
|
}
|
|
}
|
|
}
|
|
|
|
return target;
|
|
});
|
|
|
|
var regexify = (function (strsOrRegexes) {
|
|
return strsOrRegexes.map(function (strOrRegex) {
|
|
return typeof strOrRegex === 'string' ? new RegExp('^' + strOrRegex + '$') : strOrRegex;
|
|
});
|
|
});
|
|
|
|
var exclude = (function () {
|
|
for (var _len = arguments.length, exclusions = Array(_len), _key = 0; _key < _len; _key++) {
|
|
exclusions[_key] = arguments[_key];
|
|
}
|
|
|
|
exclusions = regexify(exclusions);
|
|
return function (name) {
|
|
return exclusions.every(function (exclusion) {
|
|
return !exclusion.test(name);
|
|
}) && name;
|
|
};
|
|
});
|
|
|
|
var include = (function () {
|
|
for (var _len = arguments.length, inclusions = Array(_len), _key = 0; _key < _len; _key++) {
|
|
inclusions[_key] = arguments[_key];
|
|
}
|
|
|
|
inclusions = regexify(inclusions);
|
|
return function (name) {
|
|
return inclusions.some(function (inclusion) {
|
|
return inclusion.test(name);
|
|
}) && name;
|
|
};
|
|
});
|
|
|
|
var includeMap = (function (mappings) {
|
|
return function (name) {
|
|
return mappings[name];
|
|
};
|
|
});
|
|
|
|
var capitalizeFirstLetter = function capitalizeFirstLetter(str) {
|
|
return str[0].toUpperCase() + str.slice(1);
|
|
};
|
|
|
|
var prefix = (function (prefix) {
|
|
return function (name) {
|
|
return prefix + capitalizeFirstLetter(name);
|
|
};
|
|
});
|
|
|
|
function identity(d) {
|
|
return d;
|
|
}
|
|
function noop(d) {}
|
|
|
|
function functor(v) {
|
|
return typeof v === 'function' ? v : function () {
|
|
return v;
|
|
};
|
|
}
|
|
function convertNaN(value) {
|
|
return typeof value === 'number' && isNaN(value) ? undefined : value;
|
|
}
|
|
|
|
var _slidingWindow = function () {
|
|
|
|
var period = function period() {
|
|
return 10;
|
|
};
|
|
var accumulator = noop;
|
|
var value = identity;
|
|
var defined = function defined(d) {
|
|
return d != null;
|
|
};
|
|
|
|
var slidingWindow = function slidingWindow(data) {
|
|
var size = period.apply(this, arguments);
|
|
var windowData = data.slice(0, size).map(value);
|
|
return data.map(function (d, i) {
|
|
if (i >= size) {
|
|
// Treat windowData as FIFO rolling buffer
|
|
windowData.shift();
|
|
windowData.push(value(d, i));
|
|
}
|
|
if (i < size - 1 || windowData.some(function (d) {
|
|
return !defined(d);
|
|
})) {
|
|
return accumulator(undefined, i);
|
|
}
|
|
return accumulator(windowData, i);
|
|
});
|
|
};
|
|
|
|
slidingWindow.period = function () {
|
|
if (!arguments.length) {
|
|
return period;
|
|
}
|
|
period = functor(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return slidingWindow;
|
|
};
|
|
slidingWindow.accumulator = function () {
|
|
if (!arguments.length) {
|
|
return accumulator;
|
|
}
|
|
accumulator = arguments.length <= 0 ? undefined : arguments[0];
|
|
return slidingWindow;
|
|
};
|
|
slidingWindow.defined = function () {
|
|
if (!arguments.length) {
|
|
return defined;
|
|
}
|
|
defined = arguments.length <= 0 ? undefined : arguments[0];
|
|
return slidingWindow;
|
|
};
|
|
slidingWindow.value = function () {
|
|
if (!arguments.length) {
|
|
return value;
|
|
}
|
|
value = arguments.length <= 0 ? undefined : arguments[0];
|
|
return slidingWindow;
|
|
};
|
|
|
|
return slidingWindow;
|
|
};
|
|
|
|
var bollingerBands = function () {
|
|
|
|
var multiplier = 2;
|
|
|
|
var slidingWindow = _slidingWindow().accumulator(function (values) {
|
|
var stdDev = values && d3Array.deviation(values);
|
|
var average = values && d3Array.mean(values);
|
|
return {
|
|
average: average,
|
|
upper: convertNaN(average + multiplier * stdDev),
|
|
lower: convertNaN(average - multiplier * stdDev)
|
|
};
|
|
});
|
|
|
|
var bollingerBands = function bollingerBands(data) {
|
|
return slidingWindow(data);
|
|
};
|
|
|
|
bollingerBands.multiplier = function () {
|
|
if (!arguments.length) {
|
|
return multiplier;
|
|
}
|
|
multiplier = arguments.length <= 0 ? undefined : arguments[0];
|
|
return bollingerBands;
|
|
};
|
|
|
|
rebind(bollingerBands, slidingWindow, 'period', 'value');
|
|
|
|
return bollingerBands;
|
|
};
|
|
|
|
var exponentialMovingAverage = function () {
|
|
|
|
var value = identity;
|
|
var period = function period() {
|
|
return 9;
|
|
};
|
|
|
|
var initialMovingAverageAccumulator = function initialMovingAverageAccumulator(period) {
|
|
var values = [];
|
|
return function (value) {
|
|
var movingAverage = void 0;
|
|
if (values.length < period) {
|
|
if (value != null) {
|
|
values.push(value);
|
|
} else {
|
|
values = [];
|
|
}
|
|
}
|
|
if (values.length >= period) {
|
|
movingAverage = d3Array.mean(values);
|
|
}
|
|
return movingAverage;
|
|
};
|
|
};
|
|
var exponentialMovingAverage = function exponentialMovingAverage(data) {
|
|
var size = period.apply(this, arguments);
|
|
var alpha = 2 / (size + 1);
|
|
var initialAccumulator = initialMovingAverageAccumulator(size);
|
|
var ema = void 0;
|
|
return data.map(function (d, i) {
|
|
var v = value(d, i);
|
|
if (ema === undefined) {
|
|
ema = initialAccumulator(v);
|
|
} else {
|
|
ema = v * alpha + (1 - alpha) * ema;
|
|
}
|
|
return convertNaN(ema);
|
|
});
|
|
};
|
|
|
|
exponentialMovingAverage.period = function () {
|
|
if (!arguments.length) {
|
|
return period;
|
|
}
|
|
period = functor(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return exponentialMovingAverage;
|
|
};
|
|
|
|
exponentialMovingAverage.value = function () {
|
|
if (!arguments.length) {
|
|
return value;
|
|
}
|
|
value = arguments.length <= 0 ? undefined : arguments[0];
|
|
return exponentialMovingAverage;
|
|
};
|
|
|
|
return exponentialMovingAverage;
|
|
};
|
|
|
|
var macd = function () {
|
|
|
|
var value = identity;
|
|
|
|
var fastEMA = exponentialMovingAverage().period(12);
|
|
var slowEMA = exponentialMovingAverage().period(26);
|
|
var signalEMA = exponentialMovingAverage().period(9);
|
|
|
|
var macd = function macd(data) {
|
|
|
|
fastEMA.value(value);
|
|
slowEMA.value(value);
|
|
|
|
var diff = d3Array.zip(fastEMA(data), slowEMA(data)).map(function (d) {
|
|
return d[0] !== undefined && d[1] !== undefined ? d[0] - d[1] : undefined;
|
|
});
|
|
|
|
var averageDiff = signalEMA(diff);
|
|
|
|
return d3Array.zip(diff, averageDiff).map(function (d) {
|
|
return {
|
|
macd: d[0],
|
|
signal: d[1],
|
|
divergence: d[0] !== undefined && d[1] !== undefined ? d[0] - d[1] : undefined
|
|
};
|
|
});
|
|
};
|
|
|
|
macd.value = function () {
|
|
if (!arguments.length) {
|
|
return value;
|
|
}
|
|
value = arguments.length <= 0 ? undefined : arguments[0];
|
|
return macd;
|
|
};
|
|
|
|
rebindAll(macd, fastEMA, includeMap({ 'period': 'fastPeriod' }));
|
|
rebindAll(macd, slowEMA, includeMap({ 'period': 'slowPeriod' }));
|
|
rebindAll(macd, signalEMA, includeMap({ 'period': 'signalPeriod' }));
|
|
|
|
return macd;
|
|
};
|
|
|
|
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
|
|
return typeof obj;
|
|
} : function (obj) {
|
|
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var classCallCheck = function (instance, Constructor) {
|
|
if (!(instance instanceof Constructor)) {
|
|
throw new TypeError("Cannot call a class as a function");
|
|
}
|
|
};
|
|
|
|
var createClass = function () {
|
|
function defineProperties(target, props) {
|
|
for (var i = 0; i < props.length; i++) {
|
|
var descriptor = props[i];
|
|
descriptor.enumerable = descriptor.enumerable || false;
|
|
descriptor.configurable = true;
|
|
if ("value" in descriptor) descriptor.writable = true;
|
|
Object.defineProperty(target, descriptor.key, descriptor);
|
|
}
|
|
}
|
|
|
|
return function (Constructor, protoProps, staticProps) {
|
|
if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
|
if (staticProps) defineProperties(Constructor, staticProps);
|
|
return Constructor;
|
|
};
|
|
}();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var inherits = function (subClass, superClass) {
|
|
if (typeof superClass !== "function" && superClass !== null) {
|
|
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
|
|
}
|
|
|
|
subClass.prototype = Object.create(superClass && superClass.prototype, {
|
|
constructor: {
|
|
value: subClass,
|
|
enumerable: false,
|
|
writable: true,
|
|
configurable: true
|
|
}
|
|
});
|
|
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var possibleConstructorReturn = function (self, call) {
|
|
if (!self) {
|
|
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
|
|
}
|
|
|
|
return call && (typeof call === "object" || typeof call === "function") ? call : self;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var slicedToArray = function () {
|
|
function sliceIterator(arr, i) {
|
|
var _arr = [];
|
|
var _n = true;
|
|
var _d = false;
|
|
var _e = undefined;
|
|
|
|
try {
|
|
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
|
|
_arr.push(_s.value);
|
|
|
|
if (i && _arr.length === i) break;
|
|
}
|
|
} catch (err) {
|
|
_d = true;
|
|
_e = err;
|
|
} finally {
|
|
try {
|
|
if (!_n && _i["return"]) _i["return"]();
|
|
} finally {
|
|
if (_d) throw _e;
|
|
}
|
|
}
|
|
|
|
return _arr;
|
|
}
|
|
|
|
return function (arr, i) {
|
|
if (Array.isArray(arr)) {
|
|
return arr;
|
|
} else if (Symbol.iterator in Object(arr)) {
|
|
return sliceIterator(arr, i);
|
|
} else {
|
|
throw new TypeError("Invalid attempt to destructure non-iterable instance");
|
|
}
|
|
};
|
|
}();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var toArray = function (arr) {
|
|
return Array.isArray(arr) ? arr : Array.from(arr);
|
|
};
|
|
|
|
var toConsumableArray = function (arr) {
|
|
if (Array.isArray(arr)) {
|
|
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
|
|
|
|
return arr2;
|
|
} else {
|
|
return Array.from(arr);
|
|
}
|
|
};
|
|
|
|
var relativeStrengthIndex = function () {
|
|
|
|
var slidingWindow = _slidingWindow().period(14);
|
|
var wildersSmoothing = function wildersSmoothing(values, prevAvg) {
|
|
return prevAvg + (values[values.length - 1] - prevAvg) / values.length;
|
|
};
|
|
var downChange = function downChange(_ref) {
|
|
var _ref2 = slicedToArray(_ref, 2),
|
|
prevClose = _ref2[0],
|
|
close = _ref2[1];
|
|
|
|
return prevClose < close ? 0 : prevClose - close;
|
|
};
|
|
var upChange = function upChange(_ref3) {
|
|
var _ref4 = slicedToArray(_ref3, 2),
|
|
prevClose = _ref4[0],
|
|
close = _ref4[1];
|
|
|
|
return prevClose > close ? 0 : close - prevClose;
|
|
};
|
|
|
|
var updateAverage = function updateAverage(changes, prevAverage) {
|
|
return prevAverage !== undefined ? wildersSmoothing(changes, prevAverage) : d3Array.mean(changes);
|
|
};
|
|
|
|
var makeAccumulator = function makeAccumulator() {
|
|
var prevClose = void 0;
|
|
var downChangesAvg = void 0;
|
|
var upChangesAvg = void 0;
|
|
return function (closes) {
|
|
if (!closes) {
|
|
if (prevClose !== undefined) {
|
|
prevClose = NaN;
|
|
}
|
|
return undefined;
|
|
}
|
|
if (prevClose === undefined) {
|
|
prevClose = closes[0];
|
|
return undefined;
|
|
}
|
|
|
|
var closePairs = d3Array.pairs([prevClose].concat(toConsumableArray(closes)));
|
|
downChangesAvg = updateAverage(closePairs.map(downChange), downChangesAvg);
|
|
upChangesAvg = updateAverage(closePairs.map(upChange), upChangesAvg);
|
|
var rs = !isNaN(prevClose) ? upChangesAvg / downChangesAvg : NaN;
|
|
return convertNaN(100 - 100 / (1 + rs));
|
|
};
|
|
};
|
|
|
|
var rsi = function rsi(data) {
|
|
var rsiAccumulator = makeAccumulator();
|
|
slidingWindow.accumulator(rsiAccumulator);
|
|
return slidingWindow(data);
|
|
};
|
|
|
|
rebind(rsi, slidingWindow, 'period', 'value');
|
|
return rsi;
|
|
};
|
|
|
|
var movingAverage = function () {
|
|
|
|
var slidingWindow = _slidingWindow().accumulator(function (values) {
|
|
return values && d3Array.mean(values);
|
|
});
|
|
|
|
var movingAverage = function movingAverage(data) {
|
|
return slidingWindow(data);
|
|
};
|
|
|
|
rebind(movingAverage, slidingWindow, 'period', 'value');
|
|
|
|
return movingAverage;
|
|
};
|
|
|
|
var stochasticOscillator = function () {
|
|
|
|
var closeValue = function closeValue(d, i) {
|
|
return d.close;
|
|
};
|
|
var highValue = function highValue(d, i) {
|
|
return d.high;
|
|
};
|
|
var lowValue = function lowValue(d, i) {
|
|
return d.low;
|
|
};
|
|
|
|
var kWindow = _slidingWindow().period(5).defined(function (d) {
|
|
return closeValue(d) != null && highValue(d) != null && lowValue(d) != null;
|
|
}).accumulator(function (values) {
|
|
var maxHigh = values && d3Array.max(values, highValue);
|
|
var minLow = values && d3Array.min(values, lowValue);
|
|
var kValue = values && 100 * (closeValue(values[values.length - 1]) - minLow) / (maxHigh - minLow);
|
|
return convertNaN(kValue);
|
|
});
|
|
|
|
var dWindow = movingAverage().period(3);
|
|
|
|
var stochastic = function stochastic(data) {
|
|
var kValues = kWindow(data);
|
|
var dValues = dWindow(kValues);
|
|
return kValues.map(function (k, i) {
|
|
return { k: k, d: dValues[i] };
|
|
});
|
|
};
|
|
|
|
stochastic.closeValue = function () {
|
|
if (!arguments.length) {
|
|
return closeValue;
|
|
}
|
|
closeValue = arguments.length <= 0 ? undefined : arguments[0];
|
|
return stochastic;
|
|
};
|
|
stochastic.highValue = function () {
|
|
if (!arguments.length) {
|
|
return highValue;
|
|
}
|
|
highValue = arguments.length <= 0 ? undefined : arguments[0];
|
|
return stochastic;
|
|
};
|
|
stochastic.lowValue = function () {
|
|
if (!arguments.length) {
|
|
return lowValue;
|
|
}
|
|
lowValue = arguments.length <= 0 ? undefined : arguments[0];
|
|
return stochastic;
|
|
};
|
|
|
|
rebindAll(stochastic, kWindow, includeMap({ 'period': 'kPeriod' }));
|
|
rebindAll(stochastic, dWindow, includeMap({ 'period': 'dPeriod' }));
|
|
|
|
return stochastic;
|
|
};
|
|
|
|
var forceIndex = function () {
|
|
|
|
var volumeValue = function volumeValue(d, i) {
|
|
return d.volume;
|
|
};
|
|
var closeValue = function closeValue(d, i) {
|
|
return d.close;
|
|
};
|
|
|
|
var emaComputer = exponentialMovingAverage().period(13);
|
|
|
|
var slidingWindow = _slidingWindow().period(2).defined(function (d) {
|
|
return closeValue(d) != null && volumeValue(d) != null;
|
|
}).accumulator(function (values) {
|
|
return values && convertNaN((closeValue(values[1]) - closeValue(values[0])) * volumeValue(values[1]));
|
|
});
|
|
|
|
var force = function force(data) {
|
|
var forceIndex = slidingWindow(data);
|
|
return emaComputer(forceIndex);
|
|
};
|
|
|
|
force.volumeValue = function () {
|
|
if (!arguments.length) {
|
|
return volumeValue;
|
|
}
|
|
volumeValue = arguments.length <= 0 ? undefined : arguments[0];
|
|
return force;
|
|
};
|
|
force.closeValue = function () {
|
|
if (!arguments.length) {
|
|
return closeValue;
|
|
}
|
|
closeValue = arguments.length <= 0 ? undefined : arguments[0];
|
|
return force;
|
|
};
|
|
|
|
rebind(force, emaComputer, 'period');
|
|
|
|
return force;
|
|
};
|
|
|
|
var envelope = function () {
|
|
|
|
var factor = 0.1;
|
|
var value = identity;
|
|
|
|
var envelope = function envelope(data) {
|
|
return data.map(function (d) {
|
|
var lower = convertNaN(value(d) * (1.0 - factor));
|
|
var upper = convertNaN(value(d) * (1.0 + factor));
|
|
return { lower: lower, upper: upper };
|
|
});
|
|
};
|
|
|
|
envelope.factor = function () {
|
|
if (!arguments.length) {
|
|
return factor;
|
|
}
|
|
factor = arguments.length <= 0 ? undefined : arguments[0];
|
|
return envelope;
|
|
};
|
|
|
|
envelope.value = function () {
|
|
if (!arguments.length) {
|
|
return value;
|
|
}
|
|
value = arguments.length <= 0 ? undefined : arguments[0];
|
|
return envelope;
|
|
};
|
|
|
|
return envelope;
|
|
};
|
|
|
|
var elderRay = function () {
|
|
|
|
var closeValue = function closeValue(d, i) {
|
|
return d.close;
|
|
};
|
|
var highValue = function highValue(d, i) {
|
|
return d.high;
|
|
};
|
|
var lowValue = function lowValue(d, i) {
|
|
return d.low;
|
|
};
|
|
|
|
var emaComputer = exponentialMovingAverage().period(13);
|
|
|
|
var elderRay = function elderRay(data) {
|
|
emaComputer.value(closeValue);
|
|
return d3Array.zip(data, emaComputer(data)).map(function (d) {
|
|
var bullPower = convertNaN(highValue(d[0]) - d[1]);
|
|
var bearPower = convertNaN(lowValue(d[0]) - d[1]);
|
|
return { bullPower: bullPower, bearPower: bearPower };
|
|
});
|
|
};
|
|
|
|
elderRay.closeValue = function () {
|
|
if (!arguments.length) {
|
|
return closeValue;
|
|
}
|
|
closeValue = arguments.length <= 0 ? undefined : arguments[0];
|
|
return elderRay;
|
|
};
|
|
|
|
elderRay.highValue = function () {
|
|
if (!arguments.length) {
|
|
return highValue;
|
|
}
|
|
highValue = arguments.length <= 0 ? undefined : arguments[0];
|
|
return elderRay;
|
|
};
|
|
elderRay.lowValue = function () {
|
|
if (!arguments.length) {
|
|
return lowValue;
|
|
}
|
|
lowValue = arguments.length <= 0 ? undefined : arguments[0];
|
|
return elderRay;
|
|
};
|
|
|
|
rebind(elderRay, emaComputer, 'period');
|
|
|
|
return elderRay;
|
|
};
|
|
|
|
var identity$1 = function () {
|
|
|
|
var identity = {};
|
|
|
|
identity.distance = function (start, end) {
|
|
return end - start;
|
|
};
|
|
|
|
identity.offset = function (start, offset) {
|
|
return start instanceof Date ? new Date(start.getTime() + offset) : start + offset;
|
|
};
|
|
|
|
identity.clampUp = function (d) {
|
|
return d;
|
|
};
|
|
|
|
identity.clampDown = function (d) {
|
|
return d;
|
|
};
|
|
|
|
identity.copy = function () {
|
|
return identity;
|
|
};
|
|
|
|
return identity;
|
|
};
|
|
|
|
function tickFilter(ticks, discontinuityProvider) {
|
|
var discontinuousTicks = [];
|
|
var _iteratorNormalCompletion = true;
|
|
var _didIteratorError = false;
|
|
var _iteratorError = undefined;
|
|
|
|
try {
|
|
for (var _iterator = ticks[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
var tick = _step.value;
|
|
|
|
var up = discontinuityProvider.clampUp(tick);
|
|
var down = discontinuityProvider.clampDown(tick);
|
|
if (up === down) {
|
|
discontinuousTicks.push(up);
|
|
}
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError = true;
|
|
_iteratorError = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion && _iterator.return) {
|
|
_iterator.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError) {
|
|
throw _iteratorError;
|
|
}
|
|
}
|
|
}
|
|
|
|
return discontinuousTicks;
|
|
}
|
|
|
|
function discontinuous(adaptedScale) {
|
|
var _this = this;
|
|
|
|
if (!arguments.length) {
|
|
adaptedScale = d3Scale.scaleIdentity();
|
|
}
|
|
|
|
var discontinuityProvider = identity$1();
|
|
|
|
var scale = function scale(value) {
|
|
var domain = adaptedScale.domain();
|
|
var range$$1 = adaptedScale.range();
|
|
|
|
// The discontinuityProvider is responsible for determine the distance between two points
|
|
// along a scale that has discontinuities (i.e. sections that have been removed).
|
|
// the scale for the given point 'x' is calculated as the ratio of the discontinuous distance
|
|
// over the domain of this axis, versus the discontinuous distance to 'x'
|
|
var totalDomainDistance = discontinuityProvider.distance(domain[0], domain[1]);
|
|
var distanceToX = discontinuityProvider.distance(domain[0], value);
|
|
var ratioToX = distanceToX / totalDomainDistance;
|
|
var scaledByRange = ratioToX * (range$$1[1] - range$$1[0]) + range$$1[0];
|
|
return scaledByRange;
|
|
};
|
|
|
|
scale.invert = function (x) {
|
|
var domain = adaptedScale.domain();
|
|
var range$$1 = adaptedScale.range();
|
|
|
|
var ratioToX = (x - range$$1[0]) / (range$$1[1] - range$$1[0]);
|
|
var totalDomainDistance = discontinuityProvider.distance(domain[0], domain[1]);
|
|
var distanceToX = ratioToX * totalDomainDistance;
|
|
return discontinuityProvider.offset(domain[0], distanceToX);
|
|
};
|
|
|
|
scale.domain = function () {
|
|
if (!arguments.length) {
|
|
return adaptedScale.domain();
|
|
}
|
|
var newDomain = arguments.length <= 0 ? undefined : arguments[0];
|
|
|
|
// clamp the upper and lower domain values to ensure they
|
|
// do not fall within a discontinuity
|
|
var domainLower = discontinuityProvider.clampUp(newDomain[0]);
|
|
var domainUpper = discontinuityProvider.clampDown(newDomain[1]);
|
|
adaptedScale.domain([domainLower, domainUpper]);
|
|
return scale;
|
|
};
|
|
|
|
scale.nice = function () {
|
|
adaptedScale.nice();
|
|
var domain = adaptedScale.domain();
|
|
var domainLower = discontinuityProvider.clampUp(domain[0]);
|
|
var domainUpper = discontinuityProvider.clampDown(domain[1]);
|
|
adaptedScale.domain([domainLower, domainUpper]);
|
|
return scale;
|
|
};
|
|
|
|
scale.ticks = function () {
|
|
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
|
args[_key] = arguments[_key];
|
|
}
|
|
|
|
var ticks = adaptedScale.ticks.apply(_this, args);
|
|
return tickFilter(ticks, discontinuityProvider);
|
|
};
|
|
|
|
scale.copy = function () {
|
|
return discontinuous(adaptedScale.copy()).discontinuityProvider(discontinuityProvider.copy());
|
|
};
|
|
|
|
scale.discontinuityProvider = function () {
|
|
if (!arguments.length) {
|
|
return discontinuityProvider;
|
|
}
|
|
discontinuityProvider = arguments.length <= 0 ? undefined : arguments[0];
|
|
return scale;
|
|
};
|
|
|
|
rebindAll(scale, adaptedScale, include('range', 'rangeRound', 'interpolate', 'clamp', 'tickFormat'));
|
|
|
|
return scale;
|
|
}
|
|
|
|
var skipWeekends = function () {
|
|
|
|
// the indices returned by date.getDay()
|
|
var day = {
|
|
sunday: 0,
|
|
monday: 1,
|
|
saturday: 6
|
|
};
|
|
|
|
var millisPerDay = 24 * 3600 * 1000;
|
|
var millisPerWorkWeek = millisPerDay * 5;
|
|
var millisPerWeek = millisPerDay * 7;
|
|
|
|
var skipWeekends = {};
|
|
|
|
var isWeekend = function isWeekend(date) {
|
|
return date.getDay() === 0 || date.getDay() === 6;
|
|
};
|
|
|
|
skipWeekends.clampDown = function (date) {
|
|
if (date && isWeekend(date)) {
|
|
// round the date up to midnight
|
|
var newDate = d3Time.timeDay.ceil(date);
|
|
// then subtract the required number of days
|
|
if (newDate.getDay() === day.sunday) {
|
|
return d3Time.timeDay.offset(newDate, -1);
|
|
} else if (newDate.getDay() === day.monday) {
|
|
return d3Time.timeDay.offset(newDate, -2);
|
|
} else {
|
|
return newDate;
|
|
}
|
|
} else {
|
|
return date;
|
|
}
|
|
};
|
|
|
|
skipWeekends.clampUp = function (date) {
|
|
if (date && isWeekend(date)) {
|
|
// round the date down to midnight
|
|
var newDate = d3Time.timeDay.floor(date);
|
|
// then add the required number of days
|
|
if (newDate.getDay() === day.saturday) {
|
|
return d3Time.timeDay.offset(newDate, 2);
|
|
} else if (newDate.getDay() === day.sunday) {
|
|
return d3Time.timeDay.offset(newDate, 1);
|
|
} else {
|
|
return newDate;
|
|
}
|
|
} else {
|
|
return date;
|
|
}
|
|
};
|
|
|
|
// returns the number of included milliseconds (i.e. those which do not fall)
|
|
// within discontinuities, along this scale
|
|
skipWeekends.distance = function (startDate, endDate) {
|
|
startDate = skipWeekends.clampUp(startDate);
|
|
endDate = skipWeekends.clampDown(endDate);
|
|
|
|
// move the start date to the end of week boundary
|
|
var offsetStart = d3Time.timeSaturday.ceil(startDate);
|
|
if (endDate < offsetStart) {
|
|
return endDate.getTime() - startDate.getTime();
|
|
}
|
|
|
|
var msAdded = offsetStart.getTime() - startDate.getTime();
|
|
|
|
// move the end date to the end of week boundary
|
|
var offsetEnd = d3Time.timeSaturday.ceil(endDate);
|
|
var msRemoved = offsetEnd.getTime() - endDate.getTime();
|
|
|
|
// determine how many weeks there are between these two dates
|
|
// round to account for DST transitions
|
|
var weeks = Math.round((offsetEnd.getTime() - offsetStart.getTime()) / millisPerWeek);
|
|
|
|
return weeks * millisPerWorkWeek + msAdded - msRemoved;
|
|
};
|
|
|
|
skipWeekends.offset = function (startDate, ms) {
|
|
var date = isWeekend(startDate) ? skipWeekends.clampUp(startDate) : startDate;
|
|
|
|
if (ms === 0) {
|
|
return date;
|
|
}
|
|
|
|
var isNegativeOffset = ms < 0;
|
|
var isPositiveOffset = ms > 0;
|
|
var remainingms = ms;
|
|
|
|
// move to the end of week boundary for a postive offset or to the start of a week for a negative offset
|
|
var weekBoundary = isNegativeOffset ? d3Time.timeMonday.floor(date) : d3Time.timeSaturday.ceil(date);
|
|
remainingms -= weekBoundary.getTime() - date.getTime();
|
|
|
|
// if the distance to the boundary is greater than the number of ms
|
|
// simply add the ms to the current date
|
|
if (isNegativeOffset && remainingms > 0 || isPositiveOffset && remainingms < 0) {
|
|
return new Date(date.getTime() + ms);
|
|
}
|
|
|
|
// skip the weekend for a positive offset
|
|
date = isNegativeOffset ? weekBoundary : d3Time.timeDay.offset(weekBoundary, 2);
|
|
|
|
// add all of the complete weeks to the date
|
|
var completeWeeks = Math.floor(remainingms / millisPerWorkWeek);
|
|
date = d3Time.timeDay.offset(date, completeWeeks * 7);
|
|
remainingms -= completeWeeks * millisPerWorkWeek;
|
|
|
|
// add the remaining time
|
|
date = new Date(date.getTime() + remainingms);
|
|
return date;
|
|
};
|
|
|
|
skipWeekends.copy = function () {
|
|
return skipWeekends;
|
|
};
|
|
|
|
return skipWeekends;
|
|
};
|
|
|
|
var provider = function provider() {
|
|
for (var _len = arguments.length, ranges = Array(_len), _key = 0; _key < _len; _key++) {
|
|
ranges[_key] = arguments[_key];
|
|
}
|
|
|
|
var inRange = function inRange(number, range$$1) {
|
|
return number > range$$1[0] && number < range$$1[1];
|
|
};
|
|
|
|
var surroundsRange = function surroundsRange(inner, outer) {
|
|
return inner[0] >= outer[0] && inner[1] <= outer[1];
|
|
};
|
|
|
|
var identity = {};
|
|
|
|
identity.distance = function (start, end) {
|
|
start = identity.clampUp(start);
|
|
end = identity.clampDown(end);
|
|
|
|
var surroundedRanges = ranges.filter(function (r) {
|
|
return surroundsRange(r, [start, end]);
|
|
});
|
|
var rangeSizes = surroundedRanges.map(function (r) {
|
|
return r[1] - r[0];
|
|
});
|
|
|
|
return end - start - rangeSizes.reduce(function (total, current) {
|
|
return total + current;
|
|
}, 0);
|
|
};
|
|
|
|
var add = function add(value, offset) {
|
|
return value instanceof Date ? new Date(value.getTime() + offset) : value + offset;
|
|
};
|
|
|
|
identity.offset = function (location, offset) {
|
|
if (offset > 0) {
|
|
var _ret = function () {
|
|
var currentLocation = identity.clampUp(location);
|
|
var offsetRemaining = offset;
|
|
while (offsetRemaining > 0) {
|
|
var futureRanges = ranges.filter(function (r) {
|
|
return r[0] > currentLocation;
|
|
}).sort(function (a, b) {
|
|
return a[0] - b[0];
|
|
});
|
|
if (futureRanges.length) {
|
|
var nextRange = futureRanges[0];
|
|
var delta = nextRange[0] - currentLocation;
|
|
if (delta > offsetRemaining) {
|
|
currentLocation = add(currentLocation, offsetRemaining);
|
|
offsetRemaining = 0;
|
|
} else {
|
|
currentLocation = nextRange[1];
|
|
offsetRemaining -= delta;
|
|
}
|
|
} else {
|
|
currentLocation = add(currentLocation, offsetRemaining);
|
|
offsetRemaining = 0;
|
|
}
|
|
}
|
|
return {
|
|
v: currentLocation
|
|
};
|
|
}();
|
|
|
|
if ((typeof _ret === "undefined" ? "undefined" : _typeof(_ret)) === "object") return _ret.v;
|
|
} else {
|
|
var _ret2 = function () {
|
|
var currentLocation = identity.clampDown(location);
|
|
var offsetRemaining = offset;
|
|
while (offsetRemaining < 0) {
|
|
var futureRanges = ranges.filter(function (r) {
|
|
return r[1] < currentLocation;
|
|
}).sort(function (a, b) {
|
|
return b[0] - a[0];
|
|
});
|
|
if (futureRanges.length) {
|
|
var nextRange = futureRanges[0];
|
|
var delta = nextRange[1] - currentLocation;
|
|
if (delta < offsetRemaining) {
|
|
currentLocation = add(currentLocation, offsetRemaining);
|
|
offsetRemaining = 0;
|
|
} else {
|
|
currentLocation = nextRange[0];
|
|
offsetRemaining -= delta;
|
|
}
|
|
} else {
|
|
currentLocation = add(currentLocation, offsetRemaining);
|
|
offsetRemaining = 0;
|
|
}
|
|
}
|
|
return {
|
|
v: currentLocation
|
|
};
|
|
}();
|
|
|
|
if ((typeof _ret2 === "undefined" ? "undefined" : _typeof(_ret2)) === "object") return _ret2.v;
|
|
}
|
|
};
|
|
|
|
identity.clampUp = function (d) {
|
|
return ranges.reduce(function (value, range$$1) {
|
|
return inRange(value, range$$1) ? range$$1[1] : value;
|
|
}, d);
|
|
};
|
|
|
|
identity.clampDown = function (d) {
|
|
return ranges.reduce(function (value, range$$1) {
|
|
return inRange(value, range$$1) ? range$$1[0] : value;
|
|
}, d);
|
|
};
|
|
|
|
identity.copy = function () {
|
|
return identity;
|
|
};
|
|
|
|
return identity;
|
|
};
|
|
|
|
var linearExtent = function () {
|
|
|
|
var accessors = [function (d) {
|
|
return d;
|
|
}];
|
|
var pad = [0, 0];
|
|
var padUnit = 'percent';
|
|
var symmetricalAbout = null;
|
|
var include = [];
|
|
|
|
var instance = function instance(data) {
|
|
var values = new Array(data.length);
|
|
var _iteratorNormalCompletion = true;
|
|
var _didIteratorError = false;
|
|
var _iteratorError = undefined;
|
|
|
|
try {
|
|
for (var _iterator = accessors[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
var accessor = _step.value;
|
|
|
|
for (var i = 0; i < data.length; i++) {
|
|
var value = accessor(data[i], i);
|
|
if (Array.isArray(value)) {
|
|
values.push.apply(values, toConsumableArray(value));
|
|
} else {
|
|
values.push(value);
|
|
}
|
|
}
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError = true;
|
|
_iteratorError = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion && _iterator.return) {
|
|
_iterator.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError) {
|
|
throw _iteratorError;
|
|
}
|
|
}
|
|
}
|
|
|
|
var extent$$1 = [d3Array.min(values), d3Array.max(values)];
|
|
|
|
extent$$1[0] = extent$$1[0] == null ? d3Array.min(include) : d3Array.min([extent$$1[0]].concat(toConsumableArray(include)));
|
|
extent$$1[1] = extent$$1[1] == null ? d3Array.max(include) : d3Array.max([extent$$1[1]].concat(toConsumableArray(include)));
|
|
|
|
if (symmetricalAbout != null) {
|
|
var halfRange = Math.max(Math.abs(extent$$1[1] - symmetricalAbout), Math.abs(extent$$1[0] - symmetricalAbout));
|
|
extent$$1[0] = symmetricalAbout - halfRange;
|
|
extent$$1[1] = symmetricalAbout + halfRange;
|
|
}
|
|
|
|
switch (padUnit) {
|
|
case 'domain':
|
|
{
|
|
extent$$1[0] -= pad[0];
|
|
extent$$1[1] += pad[1];
|
|
break;
|
|
}
|
|
case 'percent':
|
|
{
|
|
var delta = extent$$1[1] - extent$$1[0];
|
|
extent$$1[0] -= pad[0] * delta;
|
|
extent$$1[1] += pad[1] * delta;
|
|
break;
|
|
}
|
|
default:
|
|
throw new Error('Unknown padUnit: ' + padUnit);
|
|
}
|
|
|
|
return extent$$1;
|
|
};
|
|
|
|
instance.accessors = function () {
|
|
if (!arguments.length) {
|
|
return accessors;
|
|
}
|
|
accessors = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
|
|
instance.pad = function () {
|
|
if (!arguments.length) {
|
|
return pad;
|
|
}
|
|
pad = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
|
|
instance.padUnit = function () {
|
|
if (!arguments.length) {
|
|
return padUnit;
|
|
}
|
|
padUnit = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
|
|
instance.include = function () {
|
|
if (!arguments.length) {
|
|
return include;
|
|
}
|
|
include = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
|
|
instance.symmetricalAbout = function () {
|
|
if (!arguments.length) {
|
|
return symmetricalAbout;
|
|
}
|
|
symmetricalAbout = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
|
|
return instance;
|
|
};
|
|
|
|
var time = function () {
|
|
|
|
var accessors = [];
|
|
var pad = [0, 0];
|
|
var padUnit = 'percent';
|
|
var symmetricalAbout = null;
|
|
var include = [];
|
|
|
|
var extent$$1 = linearExtent();
|
|
|
|
var valueOf = function valueOf(date) {
|
|
return date != null ? date.valueOf() : null;
|
|
};
|
|
|
|
var instance = function instance(data) {
|
|
var adaptedAccessors = accessors.map(function (accessor) {
|
|
return function () {
|
|
var value = accessor.apply(undefined, arguments);
|
|
return Array.isArray(value) ? value.map(valueOf) : valueOf(value);
|
|
};
|
|
});
|
|
|
|
extent$$1.accessors(adaptedAccessors).pad(pad).padUnit(padUnit).symmetricalAbout(symmetricalAbout != null ? symmetricalAbout.valueOf() : null).include(include.map(function (date) {
|
|
return date.valueOf();
|
|
}));
|
|
|
|
return extent$$1(data).map(function (value) {
|
|
return new Date(value);
|
|
});
|
|
};
|
|
|
|
instance.accessors = function () {
|
|
if (!arguments.length) {
|
|
return accessors;
|
|
}
|
|
accessors = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
|
|
instance.pad = function () {
|
|
if (!arguments.length) {
|
|
return pad;
|
|
}
|
|
pad = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
|
|
instance.padUnit = function () {
|
|
if (!arguments.length) {
|
|
return padUnit;
|
|
}
|
|
padUnit = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
|
|
instance.include = function () {
|
|
if (!arguments.length) {
|
|
return include;
|
|
}
|
|
include = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
|
|
instance.symmetricalAbout = function () {
|
|
if (!arguments.length) {
|
|
return symmetricalAbout;
|
|
}
|
|
symmetricalAbout = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
|
|
return instance;
|
|
};
|
|
|
|
var geometricBrownianMotion = function () {
|
|
var period = 1;
|
|
var steps = 20;
|
|
var mu = 0.1;
|
|
var sigma = 0.1;
|
|
var random = d3Random.randomNormal();
|
|
|
|
var geometricBrownianMotion = function geometricBrownianMotion() {
|
|
var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
|
|
var timeStep = period / steps;
|
|
var pathData = [];
|
|
|
|
for (var i = 0; i < steps + 1; i++) {
|
|
pathData.push(value);
|
|
var increment = random() * Math.sqrt(timeStep) * sigma + (mu - sigma * sigma / 2) * timeStep;
|
|
value = value * Math.exp(increment);
|
|
}
|
|
|
|
return pathData;
|
|
};
|
|
|
|
geometricBrownianMotion.period = function () {
|
|
if (!arguments.length) {
|
|
return period;
|
|
}
|
|
period = arguments.length <= 0 ? undefined : arguments[0];
|
|
return geometricBrownianMotion;
|
|
};
|
|
|
|
geometricBrownianMotion.steps = function () {
|
|
if (!arguments.length) {
|
|
return steps;
|
|
}
|
|
steps = arguments.length <= 0 ? undefined : arguments[0];
|
|
return geometricBrownianMotion;
|
|
};
|
|
|
|
geometricBrownianMotion.mu = function () {
|
|
if (!arguments.length) {
|
|
return mu;
|
|
}
|
|
mu = arguments.length <= 0 ? undefined : arguments[0];
|
|
return geometricBrownianMotion;
|
|
};
|
|
|
|
geometricBrownianMotion.sigma = function () {
|
|
if (!arguments.length) {
|
|
return sigma;
|
|
}
|
|
sigma = arguments.length <= 0 ? undefined : arguments[0];
|
|
return geometricBrownianMotion;
|
|
};
|
|
|
|
geometricBrownianMotion.random = function () {
|
|
if (!arguments.length) {
|
|
return random;
|
|
}
|
|
random = arguments.length <= 0 ? undefined : arguments[0];
|
|
return geometricBrownianMotion;
|
|
};
|
|
|
|
return geometricBrownianMotion;
|
|
};
|
|
|
|
function functor$1(v) {
|
|
return typeof v === 'function' ? v : function () {
|
|
return v;
|
|
};
|
|
}
|
|
|
|
var financial = function () {
|
|
var startDate = new Date();
|
|
var startPrice = 100;
|
|
var interval = d3Time.timeDay;
|
|
var intervalStep = 1;
|
|
var unitInterval = d3Time.timeYear;
|
|
var unitIntervalStep = 1;
|
|
var filter = null;
|
|
var volume = function volume() {
|
|
var normal = d3Random.randomNormal(1, 0.1);
|
|
return Math.ceil(normal() * 1000);
|
|
};
|
|
var gbm = geometricBrownianMotion();
|
|
|
|
var getOffsetPeriod = function getOffsetPeriod(date) {
|
|
var unitMilliseconds = unitInterval.offset(date, unitIntervalStep) - date;
|
|
return (interval.offset(date, intervalStep) - date) / unitMilliseconds;
|
|
};
|
|
|
|
var calculateOHLC = function calculateOHLC(start, price) {
|
|
var period = getOffsetPeriod(start);
|
|
var prices = gbm.period(period)(price);
|
|
var ohlc = {
|
|
date: start,
|
|
open: prices[0],
|
|
high: Math.max.apply(Math, prices),
|
|
low: Math.min.apply(Math, prices),
|
|
close: prices[gbm.steps()]
|
|
};
|
|
ohlc.volume = volume(ohlc);
|
|
return ohlc;
|
|
};
|
|
|
|
var getNextDatum = function getNextDatum(ohlc) {
|
|
var date = void 0,
|
|
price = void 0,
|
|
filtered = void 0;
|
|
do {
|
|
date = ohlc ? interval.offset(ohlc.date, intervalStep) : new Date(startDate.getTime());
|
|
price = ohlc ? ohlc.close : startPrice;
|
|
ohlc = calculateOHLC(date, price);
|
|
filtered = filter && !filter(ohlc);
|
|
} while (filtered);
|
|
return ohlc;
|
|
};
|
|
|
|
var makeStream = function makeStream() {
|
|
var latest = void 0;
|
|
var stream = {};
|
|
stream.next = function () {
|
|
var ohlc = getNextDatum(latest);
|
|
latest = ohlc;
|
|
return ohlc;
|
|
};
|
|
stream.take = function (numPoints) {
|
|
return stream.until(function (d, i) {
|
|
return !numPoints || numPoints < 0 || i === numPoints;
|
|
});
|
|
};
|
|
stream.until = function (comparison) {
|
|
var data = [];
|
|
var index = 0;
|
|
var ohlc = getNextDatum(latest);
|
|
var compared = comparison && !comparison(ohlc, index);
|
|
while (compared) {
|
|
data.push(ohlc);
|
|
latest = ohlc;
|
|
ohlc = getNextDatum(latest);
|
|
index += 1;
|
|
compared = comparison && !comparison(ohlc, index);
|
|
}
|
|
return data;
|
|
};
|
|
return stream;
|
|
};
|
|
|
|
var financial = function financial(numPoints) {
|
|
return makeStream().take(numPoints);
|
|
};
|
|
financial.stream = makeStream;
|
|
|
|
if (typeof Symbol !== 'function' || _typeof(Symbol.iterator) !== 'symbol') {
|
|
throw new Error('d3fc-random-data depends on Symbol. Make sure that you load a polyfill in older browsers. See README.');
|
|
}
|
|
|
|
financial[Symbol.iterator] = function () {
|
|
var stream = makeStream();
|
|
return {
|
|
next: function next() {
|
|
return {
|
|
value: stream.next(),
|
|
done: false
|
|
};
|
|
}
|
|
};
|
|
};
|
|
|
|
financial.startDate = function () {
|
|
if (!arguments.length) {
|
|
return startDate;
|
|
}
|
|
startDate = arguments.length <= 0 ? undefined : arguments[0];
|
|
return financial;
|
|
};
|
|
financial.startPrice = function () {
|
|
if (!arguments.length) {
|
|
return startPrice;
|
|
}
|
|
startPrice = arguments.length <= 0 ? undefined : arguments[0];
|
|
return financial;
|
|
};
|
|
financial.interval = function () {
|
|
if (!arguments.length) {
|
|
return interval;
|
|
}
|
|
interval = arguments.length <= 0 ? undefined : arguments[0];
|
|
return financial;
|
|
};
|
|
financial.intervalStep = function () {
|
|
if (!arguments.length) {
|
|
return intervalStep;
|
|
}
|
|
intervalStep = arguments.length <= 0 ? undefined : arguments[0];
|
|
return financial;
|
|
};
|
|
financial.unitInterval = function () {
|
|
if (!arguments.length) {
|
|
return unitInterval;
|
|
}
|
|
unitInterval = arguments.length <= 0 ? undefined : arguments[0];
|
|
return financial;
|
|
};
|
|
financial.unitIntervalStep = function () {
|
|
if (!arguments.length) {
|
|
return unitIntervalStep;
|
|
}
|
|
unitIntervalStep = arguments.length <= 0 ? undefined : arguments[0];
|
|
return financial;
|
|
};
|
|
financial.filter = function () {
|
|
if (!arguments.length) {
|
|
return filter;
|
|
}
|
|
filter = arguments.length <= 0 ? undefined : arguments[0];
|
|
return financial;
|
|
};
|
|
financial.volume = function () {
|
|
if (!arguments.length) {
|
|
return volume;
|
|
}
|
|
volume = functor$1(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return financial;
|
|
};
|
|
|
|
rebindAll(financial, gbm);
|
|
|
|
return financial;
|
|
};
|
|
|
|
var skipWeekends$1 = function (datum) {
|
|
var day = datum.date.getDay();
|
|
return !(day === 0 || day === 6);
|
|
};
|
|
|
|
// https://docs.gdax.com/#market-data
|
|
var gdax = function () {
|
|
|
|
var product = 'BTC-USD';
|
|
var start = null;
|
|
var end = null;
|
|
var granularity = null;
|
|
|
|
var gdax = function gdax() {
|
|
var params = [];
|
|
if (start != null) {
|
|
params.push('start=' + start.toISOString());
|
|
}
|
|
if (end != null) {
|
|
params.push('end=' + end.toISOString());
|
|
}
|
|
if (granularity != null) {
|
|
params.push('granularity=' + granularity);
|
|
}
|
|
var url = 'https://api.gdax.com/products/' + product + '/candles?' + params.join('&');
|
|
return d3Fetch.json(url).then(function (data) {
|
|
return data.map(function (d) {
|
|
return {
|
|
date: new Date(d[0] * 1000),
|
|
open: d[3],
|
|
high: d[2],
|
|
low: d[1],
|
|
close: d[4],
|
|
volume: d[5]
|
|
};
|
|
});
|
|
});
|
|
};
|
|
|
|
gdax.product = function (x) {
|
|
if (!arguments.length) {
|
|
return product;
|
|
}
|
|
product = x;
|
|
return gdax;
|
|
};
|
|
gdax.start = function (x) {
|
|
if (!arguments.length) {
|
|
return start;
|
|
}
|
|
start = x;
|
|
return gdax;
|
|
};
|
|
gdax.end = function (x) {
|
|
if (!arguments.length) {
|
|
return end;
|
|
}
|
|
end = x;
|
|
return gdax;
|
|
};
|
|
gdax.granularity = function (x) {
|
|
if (!arguments.length) {
|
|
return granularity;
|
|
}
|
|
granularity = x;
|
|
return gdax;
|
|
};
|
|
|
|
return gdax;
|
|
};
|
|
|
|
var bucket = function () {
|
|
|
|
var bucketSize = 10;
|
|
|
|
var bucket = function bucket(data) {
|
|
return bucketSize <= 1 ? data.map(function (d) {
|
|
return [d];
|
|
}) : d3Array.range(0, Math.ceil(data.length / bucketSize)).map(function (i) {
|
|
return data.slice(i * bucketSize, (i + 1) * bucketSize);
|
|
});
|
|
};
|
|
|
|
bucket.bucketSize = function (x) {
|
|
if (!arguments.length) {
|
|
return bucketSize;
|
|
}
|
|
|
|
bucketSize = x;
|
|
return bucket;
|
|
};
|
|
|
|
return bucket;
|
|
};
|
|
|
|
var largestTriangleOneBucket = function () {
|
|
|
|
var dataBucketer = bucket();
|
|
var x = function x(d) {
|
|
return d;
|
|
};
|
|
var y = function y(d) {
|
|
return d;
|
|
};
|
|
|
|
var largestTriangleOneBucket = function largestTriangleOneBucket(data) {
|
|
|
|
if (dataBucketer.bucketSize() >= data.length) {
|
|
return data;
|
|
}
|
|
|
|
var pointAreas = calculateAreaOfPoints(data);
|
|
var pointAreaBuckets = dataBucketer(pointAreas);
|
|
|
|
var buckets = dataBucketer(data.slice(1, data.length - 1));
|
|
|
|
var subsampledData = buckets.map(function (thisBucket, i) {
|
|
|
|
var pointAreaBucket = pointAreaBuckets[i];
|
|
var maxArea = d3Array.max(pointAreaBucket);
|
|
var currentMaxIndex = pointAreaBucket.indexOf(maxArea);
|
|
|
|
return thisBucket[currentMaxIndex];
|
|
});
|
|
|
|
// First and last data points are their own buckets.
|
|
return [].concat([data[0]], subsampledData, [data[data.length - 1]]);
|
|
};
|
|
|
|
function calculateAreaOfPoints(data) {
|
|
|
|
var xyData = data.map(function (point) {
|
|
return [x(point), y(point)];
|
|
});
|
|
|
|
var pointAreas = d3Array.range(1, xyData.length - 1).map(function (i) {
|
|
var lastPoint = xyData[i - 1];
|
|
var thisPoint = xyData[i];
|
|
var nextPoint = xyData[i + 1];
|
|
|
|
return 0.5 * Math.abs((lastPoint[0] - nextPoint[0]) * (thisPoint[1] - lastPoint[1]) - (lastPoint[0] - thisPoint[0]) * (nextPoint[1] - lastPoint[1]));
|
|
});
|
|
|
|
return pointAreas;
|
|
}
|
|
|
|
rebind(largestTriangleOneBucket, dataBucketer, 'bucketSize');
|
|
|
|
largestTriangleOneBucket.x = function (d) {
|
|
if (!arguments.length) {
|
|
return x;
|
|
}
|
|
|
|
x = d;
|
|
|
|
return largestTriangleOneBucket;
|
|
};
|
|
|
|
largestTriangleOneBucket.y = function (d) {
|
|
if (!arguments.length) {
|
|
return y;
|
|
}
|
|
|
|
y = d;
|
|
|
|
return largestTriangleOneBucket;
|
|
};
|
|
|
|
return largestTriangleOneBucket;
|
|
};
|
|
|
|
var largestTriangleThreeBucket = function () {
|
|
|
|
var x = function x(d) {
|
|
return d;
|
|
};
|
|
var y = function y(d) {
|
|
return d;
|
|
};
|
|
var dataBucketer = bucket();
|
|
|
|
var largestTriangleThreeBucket = function largestTriangleThreeBucket(data) {
|
|
|
|
if (dataBucketer.bucketSize() >= data.length) {
|
|
return data;
|
|
}
|
|
|
|
var buckets = dataBucketer(data.slice(1, data.length - 1));
|
|
var firstBucket = data[0];
|
|
var lastBucket = data[data.length - 1];
|
|
|
|
// Keep track of the last selected bucket info and all buckets
|
|
// (for the next bucket average)
|
|
var allBuckets = [].concat([firstBucket], buckets, [lastBucket]);
|
|
|
|
var lastSelectedX = x(firstBucket);
|
|
var lastSelectedY = y(firstBucket);
|
|
|
|
var subsampledData = buckets.map(function (thisBucket, i) {
|
|
|
|
var nextAvgX = d3Array.mean(allBuckets[i + 1], x);
|
|
var nextAvgY = d3Array.mean(allBuckets[i + 1], y);
|
|
|
|
var xyData = thisBucket.map(function (item) {
|
|
return [x(item), y(item)];
|
|
});
|
|
|
|
var areas = xyData.map(function (item) {
|
|
return 0.5 * Math.abs((lastSelectedX - nextAvgX) * (item[1] - lastSelectedY) - (lastSelectedX - item[0]) * (nextAvgY - lastSelectedY));
|
|
});
|
|
|
|
var highestIndex = areas.indexOf(d3Array.max(areas));
|
|
var highestXY = xyData[highestIndex];
|
|
|
|
lastSelectedX = highestXY[0];
|
|
lastSelectedY = highestXY[1];
|
|
|
|
return thisBucket[highestIndex];
|
|
});
|
|
|
|
// First and last data points are their own buckets.
|
|
return [].concat([data[0]], subsampledData, [data[data.length - 1]]);
|
|
};
|
|
|
|
rebind(largestTriangleThreeBucket, dataBucketer, 'bucketSize');
|
|
|
|
largestTriangleThreeBucket.x = function (d) {
|
|
if (!arguments.length) {
|
|
return x;
|
|
}
|
|
|
|
x = d;
|
|
|
|
return largestTriangleThreeBucket;
|
|
};
|
|
|
|
largestTriangleThreeBucket.y = function (d) {
|
|
if (!arguments.length) {
|
|
return y;
|
|
}
|
|
|
|
y = d;
|
|
|
|
return largestTriangleThreeBucket;
|
|
};
|
|
|
|
return largestTriangleThreeBucket;
|
|
};
|
|
|
|
var modeMedian = function () {
|
|
|
|
var dataBucketer = bucket();
|
|
var value = function value(d) {
|
|
return d;
|
|
};
|
|
|
|
var modeMedian = function modeMedian(data) {
|
|
|
|
if (dataBucketer.bucketSize() > data.length) {
|
|
return data;
|
|
}
|
|
|
|
var minMax = d3Array.extent(data, value);
|
|
var buckets = dataBucketer(data.slice(1, data.length - 1));
|
|
|
|
var subsampledData = buckets.map(function (thisBucket, i) {
|
|
|
|
var frequencies = {};
|
|
var mostFrequent;
|
|
var mostFrequentIndex;
|
|
var singleMostFrequent = true;
|
|
|
|
var values = thisBucket.map(value);
|
|
|
|
var globalMinMax = values.filter(function (value) {
|
|
return value === minMax[0] || value === minMax[1];
|
|
}).map(function (value) {
|
|
return values.indexOf(value);
|
|
})[0];
|
|
|
|
if (globalMinMax !== undefined) {
|
|
return thisBucket[globalMinMax];
|
|
}
|
|
|
|
values.forEach(function (item, i) {
|
|
if (frequencies[item] === undefined) {
|
|
frequencies[item] = 0;
|
|
}
|
|
frequencies[item]++;
|
|
|
|
if (frequencies[item] > frequencies[mostFrequent] || mostFrequent === undefined) {
|
|
mostFrequent = item;
|
|
mostFrequentIndex = i;
|
|
singleMostFrequent = true;
|
|
} else if (frequencies[item] === frequencies[mostFrequent]) {
|
|
singleMostFrequent = false;
|
|
}
|
|
});
|
|
|
|
if (singleMostFrequent) {
|
|
return thisBucket[mostFrequentIndex];
|
|
} else {
|
|
return thisBucket[Math.floor(thisBucket.length / 2)];
|
|
}
|
|
});
|
|
|
|
// First and last data points are their own buckets.
|
|
return [].concat([data[0]], subsampledData, [data[data.length - 1]]);
|
|
};
|
|
|
|
rebind(modeMedian, dataBucketer, 'bucketSize');
|
|
|
|
modeMedian.value = function (x) {
|
|
if (!arguments.length) {
|
|
return value;
|
|
}
|
|
|
|
value = x;
|
|
|
|
return modeMedian;
|
|
};
|
|
|
|
return modeMedian;
|
|
};
|
|
|
|
var functor$2 = (function (v) {
|
|
return typeof v === 'function' ? v : function () {
|
|
return v;
|
|
};
|
|
});
|
|
|
|
// Renders an OHLC as an SVG path based on the given array of datapoints. Each
|
|
// OHLC has a fixed width, whilst the x, open, high, low and close positions are
|
|
// obtained from each point via the supplied accessor functions.
|
|
var shapeOhlc = (function () {
|
|
|
|
var context = null;
|
|
var x = function x(d) {
|
|
return d.date;
|
|
};
|
|
var open = function open(d) {
|
|
return d.open;
|
|
};
|
|
var high = function high(d) {
|
|
return d.high;
|
|
};
|
|
var low = function low(d) {
|
|
return d.low;
|
|
};
|
|
var close = function close(d) {
|
|
return d.close;
|
|
};
|
|
var orient = 'vertical';
|
|
var width = functor$2(3);
|
|
|
|
var ohlc = function ohlc(data) {
|
|
|
|
var drawingContext = context || d3Path.path();
|
|
|
|
data.forEach(function (d, i) {
|
|
var xValue = x(d, i);
|
|
var yOpen = open(d, i);
|
|
var yHigh = high(d, i);
|
|
var yLow = low(d, i);
|
|
var yClose = close(d, i);
|
|
var halfWidth = width(d, i) / 2;
|
|
|
|
if (orient === 'vertical') {
|
|
drawingContext.moveTo(xValue, yLow);
|
|
drawingContext.lineTo(xValue, yHigh);
|
|
|
|
drawingContext.moveTo(xValue, yOpen);
|
|
drawingContext.lineTo(xValue - halfWidth, yOpen);
|
|
drawingContext.moveTo(xValue, yClose);
|
|
drawingContext.lineTo(xValue + halfWidth, yClose);
|
|
} else {
|
|
drawingContext.moveTo(yLow, xValue);
|
|
drawingContext.lineTo(yHigh, xValue);
|
|
|
|
drawingContext.moveTo(yOpen, xValue);
|
|
drawingContext.lineTo(yOpen, xValue + halfWidth);
|
|
drawingContext.moveTo(yClose, xValue);
|
|
drawingContext.lineTo(yClose, xValue - halfWidth);
|
|
}
|
|
});
|
|
|
|
return context ? null : drawingContext.toString();
|
|
};
|
|
|
|
ohlc.context = function () {
|
|
if (!arguments.length) {
|
|
return context;
|
|
}
|
|
context = arguments.length <= 0 ? undefined : arguments[0];
|
|
return ohlc;
|
|
};
|
|
ohlc.x = function () {
|
|
if (!arguments.length) {
|
|
return x;
|
|
}
|
|
x = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return ohlc;
|
|
};
|
|
ohlc.open = function () {
|
|
if (!arguments.length) {
|
|
return open;
|
|
}
|
|
open = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return ohlc;
|
|
};
|
|
ohlc.high = function () {
|
|
if (!arguments.length) {
|
|
return high;
|
|
}
|
|
high = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return ohlc;
|
|
};
|
|
ohlc.low = function () {
|
|
if (!arguments.length) {
|
|
return low;
|
|
}
|
|
low = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return ohlc;
|
|
};
|
|
ohlc.close = function () {
|
|
if (!arguments.length) {
|
|
return close;
|
|
}
|
|
close = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return ohlc;
|
|
};
|
|
ohlc.width = function () {
|
|
if (!arguments.length) {
|
|
return width;
|
|
}
|
|
width = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return ohlc;
|
|
};
|
|
ohlc.orient = function () {
|
|
if (!arguments.length) {
|
|
return orient;
|
|
}
|
|
orient = arguments.length <= 0 ? undefined : arguments[0];
|
|
return ohlc;
|
|
};
|
|
|
|
return ohlc;
|
|
});
|
|
|
|
// Renders a bar series as an SVG path based on the given array of datapoints. Each
|
|
// bar has a fixed width, whilst the x, y and height are obtained from each data
|
|
// point via the supplied accessor functions.
|
|
var shapeBar = (function () {
|
|
|
|
var context = null;
|
|
var x = function x(d) {
|
|
return d.x;
|
|
};
|
|
var y = function y(d) {
|
|
return d.y;
|
|
};
|
|
var horizontalAlign = 'center';
|
|
var verticalAlign = 'center';
|
|
var height = function height(d) {
|
|
return d.height;
|
|
};
|
|
var width = functor$2(3);
|
|
|
|
var bar = function bar(data, index) {
|
|
|
|
var drawingContext = context || d3Path.path();
|
|
|
|
data.forEach(function (d, i) {
|
|
var xValue = x.call(this, d, index || i);
|
|
var yValue = y.call(this, d, index || i);
|
|
var barHeight = height.call(this, d, index || i);
|
|
var barWidth = width.call(this, d, index || i);
|
|
|
|
var horizontalOffset = void 0;
|
|
switch (horizontalAlign) {
|
|
case 'left':
|
|
horizontalOffset = barWidth;
|
|
break;
|
|
case 'right':
|
|
horizontalOffset = 0;
|
|
break;
|
|
case 'center':
|
|
horizontalOffset = barWidth / 2;
|
|
break;
|
|
default:
|
|
throw new Error('Invalid horizontal alignment ' + horizontalAlign);
|
|
}
|
|
|
|
var verticalOffset = void 0;
|
|
switch (verticalAlign) {
|
|
case 'bottom':
|
|
verticalOffset = -barHeight;
|
|
break;
|
|
case 'top':
|
|
verticalOffset = 0;
|
|
break;
|
|
case 'center':
|
|
verticalOffset = barHeight / 2;
|
|
break;
|
|
default:
|
|
throw new Error('Invalid vertical alignment ' + verticalAlign);
|
|
}
|
|
|
|
drawingContext.rect(xValue - horizontalOffset, yValue - verticalOffset, barWidth, barHeight);
|
|
}, this);
|
|
|
|
return context ? null : drawingContext.toString();
|
|
};
|
|
|
|
bar.context = function () {
|
|
if (!arguments.length) {
|
|
return context;
|
|
}
|
|
context = arguments.length <= 0 ? undefined : arguments[0];
|
|
return bar;
|
|
};
|
|
bar.x = function () {
|
|
if (!arguments.length) {
|
|
return x;
|
|
}
|
|
x = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return bar;
|
|
};
|
|
bar.y = function () {
|
|
if (!arguments.length) {
|
|
return y;
|
|
}
|
|
y = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return bar;
|
|
};
|
|
bar.width = function () {
|
|
if (!arguments.length) {
|
|
return width;
|
|
}
|
|
width = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return bar;
|
|
};
|
|
bar.horizontalAlign = function () {
|
|
if (!arguments.length) {
|
|
return horizontalAlign;
|
|
}
|
|
horizontalAlign = arguments.length <= 0 ? undefined : arguments[0];
|
|
return bar;
|
|
};
|
|
bar.height = function () {
|
|
if (!arguments.length) {
|
|
return height;
|
|
}
|
|
height = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return bar;
|
|
};
|
|
bar.verticalAlign = function () {
|
|
if (!arguments.length) {
|
|
return verticalAlign;
|
|
}
|
|
verticalAlign = arguments.length <= 0 ? undefined : arguments[0];
|
|
return bar;
|
|
};
|
|
|
|
return bar;
|
|
});
|
|
|
|
// Renders a candlestick as an SVG path based on the given array of datapoints. Each
|
|
// candlestick has a fixed width, whilst the x, open, high, low and close positions are
|
|
// obtained from each point via the supplied accessor functions.
|
|
var shapeCandlestick = (function () {
|
|
|
|
var context = null;
|
|
var x = function x(d) {
|
|
return d.date;
|
|
};
|
|
var open = function open(d) {
|
|
return d.open;
|
|
};
|
|
var high = function high(d) {
|
|
return d.high;
|
|
};
|
|
var low = function low(d) {
|
|
return d.low;
|
|
};
|
|
var close = function close(d) {
|
|
return d.close;
|
|
};
|
|
var width = functor$2(3);
|
|
|
|
var candlestick = function candlestick(data) {
|
|
|
|
var drawingContext = context || d3Path.path();
|
|
|
|
data.forEach(function (d, i) {
|
|
var xValue = x(d, i);
|
|
var yOpen = open(d, i);
|
|
var yHigh = high(d, i);
|
|
var yLow = low(d, i);
|
|
var yClose = close(d, i);
|
|
var barWidth = width(d, i);
|
|
var halfBarWidth = barWidth / 2;
|
|
|
|
// Body
|
|
drawingContext.rect(xValue - halfBarWidth, yOpen, barWidth, yClose - yOpen);
|
|
// High wick
|
|
// // Move to the max price of close or open; draw the high wick
|
|
// N.B. Math.min() is used as we're dealing with pixel values,
|
|
// the lower the pixel value, the higher the price!
|
|
drawingContext.moveTo(xValue, Math.min(yClose, yOpen));
|
|
drawingContext.lineTo(xValue, yHigh);
|
|
// Low wick
|
|
// // Move to the min price of close or open; draw the low wick
|
|
// N.B. Math.max() is used as we're dealing with pixel values,
|
|
// the higher the pixel value, the lower the price!
|
|
drawingContext.moveTo(xValue, Math.max(yClose, yOpen));
|
|
drawingContext.lineTo(xValue, yLow);
|
|
});
|
|
|
|
return context ? null : drawingContext.toString();
|
|
};
|
|
|
|
candlestick.context = function () {
|
|
if (!arguments.length) {
|
|
return context;
|
|
}
|
|
context = arguments.length <= 0 ? undefined : arguments[0];
|
|
return candlestick;
|
|
};
|
|
candlestick.x = function () {
|
|
if (!arguments.length) {
|
|
return x;
|
|
}
|
|
x = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return candlestick;
|
|
};
|
|
candlestick.open = function () {
|
|
if (!arguments.length) {
|
|
return open;
|
|
}
|
|
open = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return candlestick;
|
|
};
|
|
candlestick.high = function () {
|
|
if (!arguments.length) {
|
|
return high;
|
|
}
|
|
high = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return candlestick;
|
|
};
|
|
candlestick.low = function () {
|
|
if (!arguments.length) {
|
|
return low;
|
|
}
|
|
low = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return candlestick;
|
|
};
|
|
candlestick.close = function () {
|
|
if (!arguments.length) {
|
|
return close;
|
|
}
|
|
close = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return candlestick;
|
|
};
|
|
candlestick.width = function () {
|
|
if (!arguments.length) {
|
|
return width;
|
|
}
|
|
width = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return candlestick;
|
|
};
|
|
|
|
return candlestick;
|
|
});
|
|
|
|
// Renders a box plot series as an SVG path based on the given array of datapoints.
|
|
var shapeBoxPlot = (function () {
|
|
|
|
var context = null;
|
|
var value = function value(d) {
|
|
return d.value;
|
|
};
|
|
var median = function median(d) {
|
|
return d.median;
|
|
};
|
|
var upperQuartile = function upperQuartile(d) {
|
|
return d.upperQuartile;
|
|
};
|
|
var lowerQuartile = function lowerQuartile(d) {
|
|
return d.lowerQuartile;
|
|
};
|
|
var high = function high(d) {
|
|
return d.high;
|
|
};
|
|
var low = function low(d) {
|
|
return d.low;
|
|
};
|
|
var orient = 'vertical';
|
|
var width = functor$2(5);
|
|
var cap = functor$2(0.5);
|
|
|
|
var boxPlot = function boxPlot(data) {
|
|
|
|
var drawingContext = context || d3Path.path();
|
|
|
|
data.forEach(function (d, i) {
|
|
// naming convention is for vertical orientation
|
|
var _value = value(d, i);
|
|
var _width = width(d, i);
|
|
var halfWidth = _width / 2;
|
|
var capWidth = _width * cap(d, i);
|
|
var halfCapWidth = capWidth / 2;
|
|
var _high = high(d, i);
|
|
var _upperQuartile = upperQuartile(d, i);
|
|
var _median = median(d, i);
|
|
var _lowerQuartile = lowerQuartile(d, i);
|
|
var _low = low(d, i);
|
|
var upperQuartileToLowerQuartile = _lowerQuartile - _upperQuartile;
|
|
|
|
if (orient === 'vertical') {
|
|
// Upper whisker
|
|
drawingContext.moveTo(_value - halfCapWidth, _high);
|
|
drawingContext.lineTo(_value + halfCapWidth, _high);
|
|
drawingContext.moveTo(_value, _high);
|
|
drawingContext.lineTo(_value, _upperQuartile);
|
|
|
|
// Box
|
|
drawingContext.rect(_value - halfWidth, _upperQuartile, _width, upperQuartileToLowerQuartile);
|
|
drawingContext.moveTo(_value - halfWidth, _median);
|
|
// Median line
|
|
drawingContext.lineTo(_value + halfWidth, _median);
|
|
|
|
// Lower whisker
|
|
drawingContext.moveTo(_value, _lowerQuartile);
|
|
drawingContext.lineTo(_value, _low);
|
|
drawingContext.moveTo(_value - halfCapWidth, _low);
|
|
drawingContext.lineTo(_value + halfCapWidth, _low);
|
|
} else {
|
|
// Lower whisker
|
|
drawingContext.moveTo(_low, _value - halfCapWidth);
|
|
drawingContext.lineTo(_low, _value + halfCapWidth);
|
|
drawingContext.moveTo(_low, _value);
|
|
drawingContext.lineTo(_lowerQuartile, _value);
|
|
|
|
// Box
|
|
drawingContext.rect(_lowerQuartile, _value - halfWidth, -upperQuartileToLowerQuartile, _width);
|
|
drawingContext.moveTo(_median, _value - halfWidth);
|
|
drawingContext.lineTo(_median, _value + halfWidth);
|
|
|
|
// Upper whisker
|
|
drawingContext.moveTo(_upperQuartile, _value);
|
|
drawingContext.lineTo(_high, _value);
|
|
drawingContext.moveTo(_high, _value - halfCapWidth);
|
|
drawingContext.lineTo(_high, _value + halfCapWidth);
|
|
}
|
|
});
|
|
|
|
return context ? null : drawingContext.toString();
|
|
};
|
|
|
|
boxPlot.context = function () {
|
|
if (!arguments.length) {
|
|
return context;
|
|
}
|
|
context = arguments.length <= 0 ? undefined : arguments[0];
|
|
return boxPlot;
|
|
};
|
|
boxPlot.value = function () {
|
|
if (!arguments.length) {
|
|
return value;
|
|
}
|
|
value = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return boxPlot;
|
|
};
|
|
boxPlot.median = function () {
|
|
if (!arguments.length) {
|
|
return median;
|
|
}
|
|
median = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return boxPlot;
|
|
};
|
|
boxPlot.upperQuartile = function () {
|
|
if (!arguments.length) {
|
|
return upperQuartile;
|
|
}
|
|
upperQuartile = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return boxPlot;
|
|
};
|
|
boxPlot.lowerQuartile = function () {
|
|
if (!arguments.length) {
|
|
return lowerQuartile;
|
|
}
|
|
lowerQuartile = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return boxPlot;
|
|
};
|
|
boxPlot.high = function () {
|
|
if (!arguments.length) {
|
|
return high;
|
|
}
|
|
high = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return boxPlot;
|
|
};
|
|
boxPlot.low = function () {
|
|
if (!arguments.length) {
|
|
return low;
|
|
}
|
|
low = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return boxPlot;
|
|
};
|
|
boxPlot.width = function () {
|
|
if (!arguments.length) {
|
|
return width;
|
|
}
|
|
width = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return boxPlot;
|
|
};
|
|
boxPlot.orient = function () {
|
|
if (!arguments.length) {
|
|
return orient;
|
|
}
|
|
orient = arguments.length <= 0 ? undefined : arguments[0];
|
|
return boxPlot;
|
|
};
|
|
boxPlot.cap = function () {
|
|
if (!arguments.length) {
|
|
return cap;
|
|
}
|
|
cap = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return boxPlot;
|
|
};
|
|
|
|
return boxPlot;
|
|
});
|
|
|
|
// Renders an error bar series as an SVG path based on the given array of datapoints.
|
|
var shapeErrorBar = (function () {
|
|
|
|
var context = null;
|
|
var value = function value(d) {
|
|
return d.x;
|
|
};
|
|
var high = function high(d) {
|
|
return d.high;
|
|
};
|
|
var low = function low(d) {
|
|
return d.low;
|
|
};
|
|
var orient = 'vertical';
|
|
var width = functor$2(5);
|
|
|
|
var errorBar = function errorBar(data) {
|
|
|
|
var drawingContext = context || d3Path.path();
|
|
|
|
data.forEach(function (d, i) {
|
|
// naming convention is for vertical orientation
|
|
var _value = value(d, i);
|
|
var _width = width(d, i);
|
|
var halfWidth = _width / 2;
|
|
var _high = high(d, i);
|
|
var _low = low(d, i);
|
|
|
|
if (orient === 'vertical') {
|
|
drawingContext.moveTo(_value - halfWidth, _high);
|
|
drawingContext.lineTo(_value + halfWidth, _high);
|
|
drawingContext.moveTo(_value, _high);
|
|
drawingContext.lineTo(_value, _low);
|
|
drawingContext.moveTo(_value - halfWidth, _low);
|
|
drawingContext.lineTo(_value + halfWidth, _low);
|
|
} else {
|
|
drawingContext.moveTo(_low, _value - halfWidth);
|
|
drawingContext.lineTo(_low, _value + halfWidth);
|
|
drawingContext.moveTo(_low, _value);
|
|
drawingContext.lineTo(_high, _value);
|
|
drawingContext.moveTo(_high, _value - halfWidth);
|
|
drawingContext.lineTo(_high, _value + halfWidth);
|
|
}
|
|
});
|
|
|
|
return context ? null : drawingContext.toString();
|
|
};
|
|
|
|
errorBar.context = function () {
|
|
if (!arguments.length) {
|
|
return context;
|
|
}
|
|
context = arguments.length <= 0 ? undefined : arguments[0];
|
|
return errorBar;
|
|
};
|
|
errorBar.value = function () {
|
|
if (!arguments.length) {
|
|
return value;
|
|
}
|
|
value = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return errorBar;
|
|
};
|
|
errorBar.high = function () {
|
|
if (!arguments.length) {
|
|
return high;
|
|
}
|
|
high = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return errorBar;
|
|
};
|
|
errorBar.low = function () {
|
|
if (!arguments.length) {
|
|
return low;
|
|
}
|
|
low = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return errorBar;
|
|
};
|
|
errorBar.width = function () {
|
|
if (!arguments.length) {
|
|
return width;
|
|
}
|
|
width = functor$2(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return errorBar;
|
|
};
|
|
errorBar.orient = function () {
|
|
if (!arguments.length) {
|
|
return orient;
|
|
}
|
|
orient = arguments.length <= 0 ? undefined : arguments[0];
|
|
return errorBar;
|
|
};
|
|
|
|
return errorBar;
|
|
});
|
|
|
|
var functor$3 = (function (d) {
|
|
return typeof d === 'function' ? d : function () {
|
|
return d;
|
|
};
|
|
});
|
|
|
|
// "Caution: avoid interpolating to or from the number zero when the interpolator is used to generate
|
|
// a string (such as with attr).
|
|
// Very small values, when stringified, may be converted to scientific notation and
|
|
// cause a temporarily invalid attribute or style property value.
|
|
// For example, the number 0.0000001 is converted to the string "1e-7".
|
|
// This is particularly noticeable when interpolating opacity values.
|
|
// To avoid scientific notation, start or end the transition at 1e-6,
|
|
// which is the smallest value that is not stringified in exponential notation."
|
|
// - https://github.com/mbostock/d3/wiki/Transitions#d3_interpolateNumber
|
|
var effectivelyZero = 1e-6;
|
|
|
|
// Wrapper around d3's selectAll/data data-join, which allows decoration of the result.
|
|
// This is achieved by appending the element to the enter selection before exposing it.
|
|
// A default transition of fade in/out is also implicitly added but can be modified.
|
|
var dataJoin = (function (element, className) {
|
|
element = element || 'g';
|
|
|
|
var key = function key(_, i) {
|
|
return i;
|
|
};
|
|
var explicitTransition = null;
|
|
|
|
var dataJoin = function dataJoin(container, data) {
|
|
data = data || function (d) {
|
|
return d;
|
|
};
|
|
|
|
var implicitTransition = container.selection ? container : null;
|
|
if (implicitTransition) {
|
|
container = container.selection();
|
|
}
|
|
|
|
var selected = container.selectAll(function (d, i, nodes) {
|
|
return Array.from(nodes[i].childNodes).filter(function (node) {
|
|
return node.nodeType === 1;
|
|
});
|
|
}).filter(className == null ? element : element + '.' + className);
|
|
var update = selected.data(data, key);
|
|
|
|
var enter = update.enter().append(element).attr('class', className);
|
|
|
|
var exit = update.exit();
|
|
|
|
// automatically merge in the enter selection
|
|
update = update.merge(enter);
|
|
|
|
// if transitions are enabled apply a default fade in/out transition
|
|
var transition = implicitTransition || explicitTransition;
|
|
if (transition) {
|
|
update = update.transition(transition).style('opacity', 1);
|
|
enter.style('opacity', effectivelyZero);
|
|
exit = exit.transition(transition).style('opacity', effectivelyZero);
|
|
}
|
|
|
|
exit.remove();
|
|
|
|
update.enter = function () {
|
|
return enter;
|
|
};
|
|
update.exit = function () {
|
|
return exit;
|
|
};
|
|
|
|
return update;
|
|
};
|
|
|
|
dataJoin.element = function () {
|
|
if (!arguments.length) {
|
|
return element;
|
|
}
|
|
element = arguments.length <= 0 ? undefined : arguments[0];
|
|
return dataJoin;
|
|
};
|
|
dataJoin.className = function () {
|
|
if (!arguments.length) {
|
|
return className;
|
|
}
|
|
className = arguments.length <= 0 ? undefined : arguments[0];
|
|
return dataJoin;
|
|
};
|
|
dataJoin.key = function () {
|
|
if (!arguments.length) {
|
|
return key;
|
|
}
|
|
key = arguments.length <= 0 ? undefined : arguments[0];
|
|
return dataJoin;
|
|
};
|
|
dataJoin.transition = function () {
|
|
if (!arguments.length) {
|
|
return explicitTransition;
|
|
}
|
|
explicitTransition = arguments.length <= 0 ? undefined : arguments[0];
|
|
return dataJoin;
|
|
};
|
|
|
|
return dataJoin;
|
|
});
|
|
|
|
var label = (function (layoutStrategy) {
|
|
|
|
var decorate = function decorate() {};
|
|
var size = function size() {
|
|
return [0, 0];
|
|
};
|
|
var position = function position(d, i) {
|
|
return [d.x, d.y];
|
|
};
|
|
var strategy = layoutStrategy || function (x) {
|
|
return x;
|
|
};
|
|
var component = function component() {};
|
|
var xScale = d3Scale.scaleIdentity();
|
|
var yScale = d3Scale.scaleIdentity();
|
|
|
|
var dataJoin$$1 = dataJoin('g', 'label');
|
|
|
|
var label = function label(selection$$1) {
|
|
|
|
selection$$1.each(function (data, index, group) {
|
|
|
|
var g = dataJoin$$1(d3Selection.select(group[index]), data).call(component);
|
|
|
|
// obtain the rectangular bounding boxes for each child
|
|
var nodes = g.nodes();
|
|
var childRects = nodes.map(function (node, i) {
|
|
var d = d3Selection.select(node).datum();
|
|
var pos = position(d, i, nodes);
|
|
var childPos = [xScale(pos[0]), yScale(pos[1])];
|
|
var childSize = size(d, i, nodes);
|
|
return {
|
|
hidden: false,
|
|
x: childPos[0],
|
|
y: childPos[1],
|
|
width: childSize[0],
|
|
height: childSize[1]
|
|
};
|
|
});
|
|
|
|
// apply the strategy to derive the layout. The strategy does not change the order
|
|
// or number of label.
|
|
var layout = strategy(childRects);
|
|
|
|
g.attr('style', function (_, i) {
|
|
return 'display:' + (layout[i].hidden ? 'none' : 'inherit');
|
|
}).attr('transform', function (_, i) {
|
|
return 'translate(' + layout[i].x + ', ' + layout[i].y + ')';
|
|
})
|
|
// set the layout width / height so that children can use SVG layout if required
|
|
.attr('layout-width', function (_, i) {
|
|
return layout[i].width;
|
|
}).attr('layout-height', function (_, i) {
|
|
return layout[i].height;
|
|
}).attr('anchor-x', function (d, i, g) {
|
|
return childRects[i].x - layout[i].x;
|
|
}).attr('anchor-y', function (d, i, g) {
|
|
return childRects[i].y - layout[i].y;
|
|
});
|
|
|
|
g.call(component);
|
|
|
|
decorate(g, data, index);
|
|
});
|
|
};
|
|
|
|
rebindAll(label, dataJoin$$1, include('key'));
|
|
rebindAll(label, strategy);
|
|
|
|
label.size = function () {
|
|
if (!arguments.length) {
|
|
return size;
|
|
}
|
|
size = functor$3(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return label;
|
|
};
|
|
|
|
label.position = function () {
|
|
if (!arguments.length) {
|
|
return position;
|
|
}
|
|
position = functor$3(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return label;
|
|
};
|
|
|
|
label.component = function () {
|
|
if (!arguments.length) {
|
|
return component;
|
|
}
|
|
component = arguments.length <= 0 ? undefined : arguments[0];
|
|
return label;
|
|
};
|
|
|
|
label.decorate = function () {
|
|
if (!arguments.length) {
|
|
return decorate;
|
|
}
|
|
decorate = arguments.length <= 0 ? undefined : arguments[0];
|
|
return label;
|
|
};
|
|
|
|
label.xScale = function () {
|
|
if (!arguments.length) {
|
|
return xScale;
|
|
}
|
|
xScale = arguments.length <= 0 ? undefined : arguments[0];
|
|
return label;
|
|
};
|
|
|
|
label.yScale = function () {
|
|
if (!arguments.length) {
|
|
return yScale;
|
|
}
|
|
yScale = arguments.length <= 0 ? undefined : arguments[0];
|
|
return label;
|
|
};
|
|
|
|
return label;
|
|
});
|
|
|
|
var textLabel = (function (layoutStrategy) {
|
|
|
|
var padding = 2;
|
|
var value = function value(x) {
|
|
return x;
|
|
};
|
|
|
|
var textJoin = dataJoin('text');
|
|
var rectJoin = dataJoin('rect');
|
|
var pointJoin = dataJoin('circle');
|
|
|
|
var textLabel = function textLabel(selection$$1) {
|
|
selection$$1.each(function (data, index, group) {
|
|
|
|
var node = group[index];
|
|
var nodeSelection = d3Selection.select(node);
|
|
|
|
var width = Number(node.getAttribute('layout-width'));
|
|
var height = Number(node.getAttribute('layout-height'));
|
|
var rect = rectJoin(nodeSelection, [data]);
|
|
rect.attr('width', width).attr('height', height);
|
|
|
|
var anchorX = Number(node.getAttribute('anchor-x'));
|
|
var anchorY = Number(node.getAttribute('anchor-y'));
|
|
var circle = pointJoin(nodeSelection, [data]);
|
|
circle.attr('r', 2).attr('cx', anchorX).attr('cy', anchorY);
|
|
|
|
var text = textJoin(nodeSelection, [data]);
|
|
text.enter().attr('dy', '0.9em').attr('transform', 'translate(' + padding + ', ' + padding + ')');
|
|
text.text(value);
|
|
});
|
|
};
|
|
|
|
textLabel.padding = function () {
|
|
if (!arguments.length) {
|
|
return padding;
|
|
}
|
|
padding = arguments.length <= 0 ? undefined : arguments[0];
|
|
return textLabel;
|
|
};
|
|
|
|
textLabel.value = function () {
|
|
if (!arguments.length) {
|
|
return value;
|
|
}
|
|
value = functor$3(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return textLabel;
|
|
};
|
|
|
|
return textLabel;
|
|
});
|
|
|
|
var isIntersecting = function isIntersecting(a, b) {
|
|
return !(a.x >= b.x + b.width || a.x + a.width <= b.x || a.y >= b.y + b.height || a.y + a.height <= b.y);
|
|
};
|
|
|
|
var intersect = (function (a, b) {
|
|
if (isIntersecting(a, b)) {
|
|
var left = Math.max(a.x, b.x);
|
|
var right = Math.min(a.x + a.width, b.x + b.width);
|
|
var top = Math.max(a.y, b.y);
|
|
var bottom = Math.min(a.y + a.height, b.y + b.height);
|
|
return (right - left) * (bottom - top);
|
|
} else {
|
|
return 0;
|
|
}
|
|
});
|
|
|
|
// computes the area of overlap between the rectangle with the given index with the
|
|
// rectangles in the array
|
|
var collisionArea = function collisionArea(rectangles, index) {
|
|
return d3Array.sum(rectangles.map(function (d, i) {
|
|
return index === i ? 0 : intersect(rectangles[index], d);
|
|
}));
|
|
};
|
|
|
|
// computes the total overlapping area of all of the rectangles in the given array
|
|
|
|
var getPlacement = function getPlacement(x, y, width, height, location) {
|
|
return {
|
|
x: x,
|
|
y: y,
|
|
width: width,
|
|
height: height,
|
|
location: location
|
|
};
|
|
};
|
|
|
|
// returns all the potential placements of the given label
|
|
var placements = (function (label) {
|
|
var x = label.x;
|
|
var y = label.y;
|
|
var width = label.width;
|
|
var height = label.height;
|
|
return [getPlacement(x, y, width, height, 'bottom-right'), getPlacement(x - width, y, width, height, 'bottom-left'), getPlacement(x - width, y - height, width, height, 'top-left'), getPlacement(x, y - height, width, height, 'top-right'), getPlacement(x, y - height / 2, width, height, 'middle-right'), getPlacement(x - width / 2, y, width, height, 'bottom-center'), getPlacement(x - width, y - height / 2, width, height, 'middle-left'), getPlacement(x - width / 2, y - height, width, height, 'top-center')];
|
|
});
|
|
|
|
var substitute = function substitute(array, index, substitution) {
|
|
return [].concat(toConsumableArray(array.slice(0, index)), [substitution], toConsumableArray(array.slice(index + 1)));
|
|
};
|
|
|
|
var lessThan = function lessThan(a, b) {
|
|
return a < b;
|
|
};
|
|
|
|
// a layout takes an array of rectangles and allows their locations to be optimised.
|
|
// it is constructed using two functions, locationScore, which score the placement of and
|
|
// individual rectangle, and winningScore which takes the scores for a rectangle
|
|
// at two different locations and assigns a winningScore.
|
|
var layoutComponent = function layoutComponent() {
|
|
var score = null;
|
|
|
|
var winningScore = lessThan;
|
|
|
|
var locationScore = function locationScore() {
|
|
return 0;
|
|
};
|
|
|
|
var rectangles = void 0;
|
|
|
|
var evaluatePlacement = function evaluatePlacement(placement, index) {
|
|
return score - locationScore(rectangles[index], index, rectangles) + locationScore(placement, index, substitute(rectangles, index, placement));
|
|
};
|
|
|
|
var layout = function layout(placement, index) {
|
|
if (!score) {
|
|
score = d3Array.sum(rectangles.map(function (r, i) {
|
|
return locationScore(r, i, rectangles);
|
|
}));
|
|
}
|
|
|
|
var newScore = evaluatePlacement(placement, index);
|
|
|
|
if (winningScore(newScore, score)) {
|
|
return layoutComponent().locationScore(locationScore).winningScore(winningScore).score(newScore).rectangles(substitute(rectangles, index, placement));
|
|
} else {
|
|
return layout;
|
|
}
|
|
};
|
|
|
|
layout.rectangles = function () {
|
|
if (!arguments.length) {
|
|
return rectangles;
|
|
}
|
|
rectangles = arguments.length <= 0 ? undefined : arguments[0];
|
|
return layout;
|
|
};
|
|
layout.score = function () {
|
|
if (!arguments.length) {
|
|
return score;
|
|
}
|
|
score = arguments.length <= 0 ? undefined : arguments[0];
|
|
return layout;
|
|
};
|
|
layout.winningScore = function () {
|
|
if (!arguments.length) {
|
|
return winningScore;
|
|
}
|
|
winningScore = arguments.length <= 0 ? undefined : arguments[0];
|
|
return layout;
|
|
};
|
|
layout.locationScore = function () {
|
|
if (!arguments.length) {
|
|
return locationScore;
|
|
}
|
|
locationScore = arguments.length <= 0 ? undefined : arguments[0];
|
|
return layout;
|
|
};
|
|
|
|
return layout;
|
|
};
|
|
|
|
var greedy = (function () {
|
|
|
|
var bounds = void 0;
|
|
|
|
var containerPenalty = function containerPenalty(rectangle) {
|
|
return bounds ? rectangle.width * rectangle.height - intersect(rectangle, bounds) : 0;
|
|
};
|
|
|
|
var penaltyForRectangle = function penaltyForRectangle(rectangle, index, rectangles) {
|
|
return collisionArea(rectangles, index) + containerPenalty(rectangle);
|
|
};
|
|
|
|
var strategy = function strategy(data) {
|
|
var rectangles = layoutComponent().locationScore(penaltyForRectangle).rectangles(data);
|
|
|
|
data.forEach(function (rectangle, index) {
|
|
placements(rectangle).forEach(function (placement, placementIndex) {
|
|
rectangles = rectangles(placement, index);
|
|
});
|
|
});
|
|
return rectangles.rectangles();
|
|
};
|
|
|
|
strategy.bounds = function () {
|
|
if (!arguments.length) {
|
|
return bounds;
|
|
}
|
|
bounds = arguments.length <= 0 ? undefined : arguments[0];
|
|
return strategy;
|
|
};
|
|
|
|
return strategy;
|
|
});
|
|
|
|
var randomItem = function randomItem(array) {
|
|
return array[randomIndex(array)];
|
|
};
|
|
|
|
var randomIndex = function randomIndex(array) {
|
|
return Math.floor(Math.random() * array.length);
|
|
};
|
|
|
|
var annealing = (function () {
|
|
|
|
var temperature = 1000;
|
|
var cooling = 1;
|
|
var bounds = void 0;
|
|
|
|
var orientationPenalty = function orientationPenalty(rectangle) {
|
|
switch (rectangle.location) {
|
|
case 'bottom-right':
|
|
return 0;
|
|
case 'middle-right':
|
|
case 'bottom-center':
|
|
return rectangle.width * rectangle.height / 8;
|
|
}
|
|
return rectangle.width * rectangle.height / 4;
|
|
};
|
|
|
|
var containerPenalty = function containerPenalty(rectangle) {
|
|
return bounds ? rectangle.width * rectangle.height - intersect(rectangle, bounds) : 0;
|
|
};
|
|
|
|
var penaltyForRectangle = function penaltyForRectangle(rectangle, index, rectangles) {
|
|
return collisionArea(rectangles, index) + containerPenalty(rectangle) + orientationPenalty(rectangle);
|
|
};
|
|
|
|
var strategy = function strategy(data) {
|
|
var currentTemperature = temperature;
|
|
|
|
// use annealing to allow a new score to be picked even if it is worse than the old
|
|
var winningScore = function winningScore(newScore, oldScore) {
|
|
return Math.exp((oldScore - newScore) / currentTemperature) > Math.random();
|
|
};
|
|
|
|
var rectangles = layoutComponent().locationScore(penaltyForRectangle).winningScore(winningScore).rectangles(data);
|
|
|
|
while (currentTemperature > 0) {
|
|
var index = randomIndex(data);
|
|
var randomNewPlacement = randomItem(placements(data[index]));
|
|
rectangles = rectangles(randomNewPlacement, index);
|
|
currentTemperature -= cooling;
|
|
}
|
|
return rectangles.rectangles();
|
|
};
|
|
|
|
strategy.temperature = function () {
|
|
if (!arguments.length) {
|
|
return temperature;
|
|
}
|
|
temperature = arguments.length <= 0 ? undefined : arguments[0];
|
|
return strategy;
|
|
};
|
|
|
|
strategy.cooling = function () {
|
|
if (!arguments.length) {
|
|
return cooling;
|
|
}
|
|
cooling = arguments.length <= 0 ? undefined : arguments[0];
|
|
return strategy;
|
|
};
|
|
|
|
strategy.bounds = function () {
|
|
if (!arguments.length) {
|
|
return bounds;
|
|
}
|
|
bounds = arguments.length <= 0 ? undefined : arguments[0];
|
|
return strategy;
|
|
};
|
|
|
|
return strategy;
|
|
});
|
|
|
|
var scanForObject = function scanForObject(array, comparator) {
|
|
return array[d3Array.scan(array, comparator)];
|
|
};
|
|
|
|
var removeOverlaps = (function (adaptedStrategy) {
|
|
|
|
adaptedStrategy = adaptedStrategy || function (x) {
|
|
return x;
|
|
};
|
|
|
|
var removeOverlaps = function removeOverlaps(layout) {
|
|
layout = adaptedStrategy(layout);
|
|
|
|
var _loop = function _loop() {
|
|
// find the collision area for all overlapping rectangles, hiding the one
|
|
// with the greatest overlap
|
|
var visible = layout.filter(function (d) {
|
|
return !d.hidden;
|
|
});
|
|
var collisions = visible.map(function (d, i) {
|
|
return [d, collisionArea(visible, i)];
|
|
});
|
|
var maximumCollision = scanForObject(collisions, function (a, b) {
|
|
return b[1] - a[1];
|
|
});
|
|
if (maximumCollision[1] > 0) {
|
|
maximumCollision[0].hidden = true;
|
|
} else {
|
|
return 'break';
|
|
}
|
|
};
|
|
|
|
while (true) {
|
|
var _ret = _loop();
|
|
|
|
if (_ret === 'break') break;
|
|
}
|
|
return layout;
|
|
};
|
|
|
|
rebindAll(removeOverlaps, adaptedStrategy);
|
|
|
|
return removeOverlaps;
|
|
});
|
|
|
|
var boundingBox = (function () {
|
|
|
|
var bounds = [0, 0];
|
|
|
|
var strategy = function strategy(data) {
|
|
return data.map(function (d, i) {
|
|
var tx = d.x;
|
|
var ty = d.y;
|
|
if (tx + d.width > bounds[0]) {
|
|
tx -= d.width;
|
|
}
|
|
|
|
if (ty + d.height > bounds[1]) {
|
|
ty -= d.height;
|
|
}
|
|
return { height: d.height, width: d.width, x: tx, y: ty };
|
|
});
|
|
};
|
|
|
|
strategy.bounds = function () {
|
|
if (!arguments.length) {
|
|
return bounds;
|
|
}
|
|
bounds = arguments.length <= 0 ? undefined : arguments[0];
|
|
return strategy;
|
|
};
|
|
|
|
return strategy;
|
|
});
|
|
|
|
var functor$4 = (function (d) {
|
|
return typeof d === 'function' ? d : function () {
|
|
return d;
|
|
};
|
|
});
|
|
|
|
// Checks that passes properties are 'defined', meaning that calling them with (d, i) returns non null values
|
|
function defined$1() {
|
|
var outerArguments = arguments;
|
|
return function (d, i) {
|
|
for (var c = 0, j = outerArguments.length; c < j; c++) {
|
|
if (outerArguments[c](d, i) == null) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
}
|
|
|
|
// determines the offset required along the cross scale based
|
|
// on the series alignment
|
|
var alignOffset = (function (align, width) {
|
|
switch (align) {
|
|
case 'left':
|
|
return width / 2;
|
|
case 'right':
|
|
return -width / 2;
|
|
default:
|
|
return 0;
|
|
}
|
|
});
|
|
|
|
var createBase = (function (initialValues) {
|
|
|
|
var env = Object.assign({}, initialValues);
|
|
var base = function base() {};
|
|
|
|
Object.keys(env).forEach(function (key) {
|
|
base[key] = function () {
|
|
if (!arguments.length) {
|
|
return env[key];
|
|
}
|
|
env[key] = arguments.length <= 0 ? undefined : arguments[0];
|
|
return base;
|
|
};
|
|
});
|
|
|
|
return base;
|
|
});
|
|
|
|
var xyBase = (function () {
|
|
|
|
var baseValue = function baseValue() {
|
|
return 0;
|
|
};
|
|
var crossValue = function crossValue(d) {
|
|
return d.x;
|
|
};
|
|
var mainValue = function mainValue(d) {
|
|
return d.y;
|
|
};
|
|
var align = 'center';
|
|
var bandwidth = function bandwidth() {
|
|
return 5;
|
|
};
|
|
var orient = 'vertical';
|
|
|
|
var base = createBase({
|
|
decorate: function decorate() {},
|
|
defined: function defined(d, i) {
|
|
return defined$1(baseValue, crossValue, mainValue)(d, i);
|
|
},
|
|
xScale: d3Scale.scaleIdentity(),
|
|
yScale: d3Scale.scaleIdentity()
|
|
});
|
|
|
|
base.values = function (d, i) {
|
|
var width = bandwidth(d, i);
|
|
var offset = alignOffset(align, width);
|
|
var xScale = base.xScale();
|
|
var yScale = base.yScale();
|
|
|
|
if (orient === 'vertical') {
|
|
var y = yScale(mainValue(d, i), i);
|
|
var y0 = yScale(baseValue(d, i), i);
|
|
var x = xScale(crossValue(d, i), i) + offset;
|
|
return {
|
|
d: d,
|
|
x: x,
|
|
y: y,
|
|
y0: y0,
|
|
width: width,
|
|
height: y - y0,
|
|
origin: [x, y],
|
|
baseOrigin: [x, y0],
|
|
transposedX: x,
|
|
transposedY: y
|
|
};
|
|
} else {
|
|
var _y = xScale(mainValue(d, i), i);
|
|
var _y2 = xScale(baseValue(d, i), i);
|
|
var _x = yScale(crossValue(d, i), i) + offset;
|
|
return {
|
|
d: d,
|
|
x: _x,
|
|
y: _y,
|
|
y0: _y2,
|
|
width: width,
|
|
height: _y - _y2,
|
|
origin: [_y, _x],
|
|
baseOrigin: [_y2, _x],
|
|
transposedX: _y,
|
|
transposedY: _x
|
|
};
|
|
}
|
|
};
|
|
|
|
base.baseValue = function () {
|
|
if (!arguments.length) {
|
|
return baseValue;
|
|
}
|
|
baseValue = functor$4(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return base;
|
|
};
|
|
base.crossValue = function () {
|
|
if (!arguments.length) {
|
|
return crossValue;
|
|
}
|
|
crossValue = functor$4(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return base;
|
|
};
|
|
base.mainValue = function () {
|
|
if (!arguments.length) {
|
|
return mainValue;
|
|
}
|
|
mainValue = functor$4(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return base;
|
|
};
|
|
base.bandwidth = function () {
|
|
if (!arguments.length) {
|
|
return bandwidth;
|
|
}
|
|
bandwidth = functor$4(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return base;
|
|
};
|
|
base.align = function () {
|
|
if (!arguments.length) {
|
|
return align;
|
|
}
|
|
align = arguments.length <= 0 ? undefined : arguments[0];
|
|
return base;
|
|
};
|
|
base.orient = function () {
|
|
if (!arguments.length) {
|
|
return orient;
|
|
}
|
|
orient = arguments.length <= 0 ? undefined : arguments[0];
|
|
return base;
|
|
};
|
|
|
|
return base;
|
|
});
|
|
|
|
var red = '#c60';
|
|
var green = '#6c0';
|
|
var black = '#000';
|
|
var gray = '#ddd';
|
|
var darkGray = '#999';
|
|
|
|
var colors = {
|
|
red: red,
|
|
green: green,
|
|
black: black,
|
|
gray: gray,
|
|
darkGray: darkGray
|
|
};
|
|
|
|
var seriesSvgLine = (function () {
|
|
var base = xyBase();
|
|
|
|
var lineData = d3Shape.line().x(function (d, i) {
|
|
return base.values(d, i).transposedX;
|
|
}).y(function (d, i) {
|
|
return base.values(d, i).transposedY;
|
|
});
|
|
|
|
var join = dataJoin('path', 'line');
|
|
|
|
var line$$1 = function line$$1(selection$$1) {
|
|
|
|
if (selection$$1.selection) {
|
|
join.transition(selection$$1);
|
|
}
|
|
|
|
lineData.defined(base.defined());
|
|
|
|
selection$$1.each(function (data, index, group) {
|
|
var path$$1 = join(d3Selection.select(group[index]), [data]);
|
|
|
|
path$$1.enter().attr('fill', 'none').attr('stroke', colors.black);
|
|
|
|
path$$1.attr('d', lineData);
|
|
|
|
base.decorate()(path$$1, data, index);
|
|
});
|
|
};
|
|
|
|
rebindAll(line$$1, base, exclude('baseValue', 'bandwidth', 'align'));
|
|
rebind(line$$1, join, 'key');
|
|
rebind(line$$1, lineData, 'curve');
|
|
|
|
return line$$1;
|
|
});
|
|
|
|
var seriesCanvasLine = (function () {
|
|
var base = xyBase();
|
|
|
|
var lineData = d3Shape.line().x(function (d, i) {
|
|
return base.values(d, i).transposedX;
|
|
}).y(function (d, i) {
|
|
return base.values(d, i).transposedY;
|
|
});
|
|
|
|
var line$$1 = function line$$1(data) {
|
|
var context = lineData.context();
|
|
|
|
context.beginPath();
|
|
lineData.defined(base.defined())(data);
|
|
context.strokeStyle = colors.black;
|
|
context.fillStyle = 'transparent';
|
|
|
|
base.decorate()(context, data);
|
|
|
|
context.fill();
|
|
context.stroke();
|
|
context.closePath();
|
|
};
|
|
|
|
rebindAll(line$$1, base, exclude('baseValue', 'bandwidth', 'align'));
|
|
rebind(line$$1, lineData, 'curve', 'context');
|
|
|
|
return line$$1;
|
|
});
|
|
|
|
var seriesSvgPoint = (function () {
|
|
var symbol$$1 = d3Shape.symbol();
|
|
|
|
var base = xyBase();
|
|
|
|
var join = dataJoin('g', 'point');
|
|
|
|
var containerTransform = function containerTransform(origin) {
|
|
return 'translate(' + origin[0] + ', ' + origin[1] + ')';
|
|
};
|
|
|
|
var point = function point(selection$$1) {
|
|
|
|
if (selection$$1.selection) {
|
|
join.transition(selection$$1);
|
|
}
|
|
|
|
selection$$1.each(function (data, index, group) {
|
|
|
|
var filteredData = data.filter(base.defined());
|
|
|
|
var g = join(d3Selection.select(group[index]), filteredData);
|
|
g.enter().attr('transform', function (d, i) {
|
|
return containerTransform(base.values(d, i).origin);
|
|
}).attr('fill', colors.gray).attr('stroke', colors.black).append('path');
|
|
|
|
g.attr('transform', function (d, i) {
|
|
return containerTransform(base.values(d, i).origin);
|
|
}).select('path').attr('d', symbol$$1);
|
|
|
|
base.decorate()(g, data, index);
|
|
});
|
|
};
|
|
|
|
rebindAll(point, base, exclude('baseValue', 'bandwidth', 'align'));
|
|
rebind(point, join, 'key');
|
|
rebind(point, symbol$$1, 'type', 'size');
|
|
|
|
return point;
|
|
});
|
|
|
|
var seriesCanvasPoint = (function () {
|
|
|
|
var symbol$$1 = d3Shape.symbol();
|
|
|
|
var base = xyBase();
|
|
|
|
var point = function point(data) {
|
|
var filteredData = data.filter(base.defined());
|
|
var context = symbol$$1.context();
|
|
|
|
filteredData.forEach(function (d, i) {
|
|
context.save();
|
|
|
|
var values = base.values(d, i);
|
|
context.translate(values.origin[0], values.origin[1]);
|
|
context.beginPath();
|
|
|
|
symbol$$1(d, i);
|
|
|
|
context.strokeStyle = colors.black;
|
|
context.fillStyle = colors.gray;
|
|
|
|
base.decorate()(context, d, i);
|
|
|
|
context.fill();
|
|
context.stroke();
|
|
context.closePath();
|
|
|
|
context.restore();
|
|
});
|
|
};
|
|
|
|
rebindAll(point, base, exclude('baseValue', 'bandwidth', 'align'));
|
|
rebind(point, symbol$$1, 'size', 'type', 'context');
|
|
|
|
return point;
|
|
});
|
|
|
|
var bar = (function () {
|
|
|
|
var pathGenerator = shapeBar().x(0).y(0);
|
|
|
|
var base = xyBase();
|
|
|
|
var join = dataJoin('g', 'bar');
|
|
|
|
var valueAxisDimension = function valueAxisDimension(generator) {
|
|
return base.orient() === 'vertical' ? generator.height : generator.width;
|
|
};
|
|
|
|
var crossAxisDimension = function crossAxisDimension(generator) {
|
|
return base.orient() === 'vertical' ? generator.width : generator.height;
|
|
};
|
|
|
|
var translation = function translation(origin) {
|
|
return 'translate(' + origin[0] + ', ' + origin[1] + ')';
|
|
};
|
|
|
|
var bar = function bar(selection$$1) {
|
|
|
|
if (selection$$1.selection) {
|
|
join.transition(selection$$1);
|
|
}
|
|
|
|
selection$$1.each(function (data, index, group) {
|
|
|
|
var orient = base.orient();
|
|
if (orient !== 'vertical' && orient !== 'horizontal') {
|
|
throw new Error('The bar series does not support an orientation of ' + orient);
|
|
}
|
|
|
|
var filteredData = data.filter(base.defined());
|
|
var projectedData = filteredData.map(base.values);
|
|
|
|
pathGenerator.width(0).height(0);
|
|
|
|
if (base.orient() === 'vertical') {
|
|
pathGenerator.verticalAlign('top');
|
|
pathGenerator.horizontalAlign('center');
|
|
} else {
|
|
pathGenerator.horizontalAlign('right');
|
|
pathGenerator.verticalAlign('center');
|
|
}
|
|
|
|
var g = join(d3Selection.select(group[index]), filteredData);
|
|
|
|
// within the enter selection the pathGenerator creates a zero
|
|
// height bar on the baseline. As a result, when used with a transition the bar grows
|
|
// from y0 to y1 (y)
|
|
g.enter().attr('transform', function (_, i) {
|
|
return translation(projectedData[i].baseOrigin);
|
|
}).attr('class', 'bar ' + base.orient()).attr('fill', colors.darkGray).append('path').attr('d', function (d, i) {
|
|
crossAxisDimension(pathGenerator)(projectedData[i].width);
|
|
return pathGenerator([d]);
|
|
});
|
|
|
|
// the container translation sets the origin to the 'tip'
|
|
// of each bar as per the decorate pattern
|
|
g.attr('transform', function (_, i) {
|
|
return translation(projectedData[i].origin);
|
|
}).select('path').attr('d', function (d, i) {
|
|
crossAxisDimension(pathGenerator)(projectedData[i].width);
|
|
valueAxisDimension(pathGenerator)(-projectedData[i].height);
|
|
return pathGenerator([d]);
|
|
});
|
|
|
|
base.decorate()(g, filteredData, index);
|
|
});
|
|
};
|
|
|
|
rebindAll(bar, base);
|
|
rebind(bar, join, 'key');
|
|
|
|
return bar;
|
|
});
|
|
|
|
var bar$1 = (function () {
|
|
var base = xyBase();
|
|
|
|
var pathGenerator = shapeBar().x(0).y(0);
|
|
|
|
var valueAxisDimension = function valueAxisDimension(generator) {
|
|
return base.orient() === 'vertical' ? generator.height : generator.width;
|
|
};
|
|
|
|
var crossAxisDimension = function crossAxisDimension(generator) {
|
|
return base.orient() === 'vertical' ? generator.width : generator.height;
|
|
};
|
|
|
|
var bar = function bar(data) {
|
|
var context = pathGenerator.context();
|
|
|
|
var filteredData = data.filter(base.defined());
|
|
var projectedData = filteredData.map(base.values);
|
|
|
|
if (base.orient() === 'vertical') {
|
|
pathGenerator.verticalAlign('top');
|
|
pathGenerator.horizontalAlign('center');
|
|
} else {
|
|
pathGenerator.horizontalAlign('right');
|
|
pathGenerator.verticalAlign('center');
|
|
}
|
|
|
|
projectedData.forEach(function (datum, i) {
|
|
context.save();
|
|
context.beginPath();
|
|
context.translate(datum.origin[0], datum.origin[1]);
|
|
|
|
valueAxisDimension(pathGenerator)(-datum.height);
|
|
crossAxisDimension(pathGenerator)(datum.width);
|
|
pathGenerator([datum]);
|
|
|
|
context.fillStyle = colors.darkGray;
|
|
context.strokeStyle = 'transparent';
|
|
base.decorate()(context, datum.d, i);
|
|
context.fill();
|
|
context.stroke();
|
|
|
|
context.closePath();
|
|
context.restore();
|
|
});
|
|
};
|
|
|
|
rebindAll(bar, base);
|
|
rebind(bar, pathGenerator, 'context');
|
|
|
|
return bar;
|
|
});
|
|
|
|
var errorBarBase = (function () {
|
|
|
|
var highValue = function highValue(d) {
|
|
return d.high;
|
|
};
|
|
var lowValue = function lowValue(d) {
|
|
return d.low;
|
|
};
|
|
var crossValue = function crossValue(d) {
|
|
return d.cross;
|
|
};
|
|
var orient = 'vertical';
|
|
var align = 'center';
|
|
var bandwidth = function bandwidth() {
|
|
return 5;
|
|
};
|
|
|
|
var base = createBase({
|
|
decorate: function decorate() {},
|
|
defined: function defined(d, i) {
|
|
return defined$1(lowValue, highValue, crossValue)(d, i);
|
|
},
|
|
xScale: d3Scale.scaleIdentity(),
|
|
yScale: d3Scale.scaleIdentity()
|
|
});
|
|
|
|
base.values = function (d, i) {
|
|
var width = bandwidth(d, i);
|
|
var offset = alignOffset(align, width);
|
|
var xScale = base.xScale();
|
|
var yScale = base.yScale();
|
|
|
|
if (orient === 'vertical') {
|
|
var y = yScale(highValue(d, i));
|
|
return {
|
|
origin: [xScale(crossValue(d, i)) + offset, y],
|
|
high: 0,
|
|
low: yScale(lowValue(d, i)) - y,
|
|
width: width
|
|
};
|
|
} else {
|
|
var x = xScale(lowValue(d, i));
|
|
return {
|
|
origin: [x, yScale(crossValue(d, i)) + offset],
|
|
high: xScale(highValue(d, i)) - x,
|
|
low: 0,
|
|
width: width
|
|
};
|
|
}
|
|
};
|
|
|
|
base.orient = function () {
|
|
if (!arguments.length) {
|
|
return orient;
|
|
}
|
|
orient = arguments.length <= 0 ? undefined : arguments[0];
|
|
return base;
|
|
};
|
|
base.lowValue = function () {
|
|
if (!arguments.length) {
|
|
return lowValue;
|
|
}
|
|
lowValue = functor$4(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return base;
|
|
};
|
|
base.highValue = function () {
|
|
if (!arguments.length) {
|
|
return highValue;
|
|
}
|
|
highValue = functor$4(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return base;
|
|
};
|
|
base.crossValue = function () {
|
|
if (!arguments.length) {
|
|
return crossValue;
|
|
}
|
|
crossValue = functor$4(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return base;
|
|
};
|
|
base.bandwidth = function () {
|
|
if (!arguments.length) {
|
|
return bandwidth;
|
|
}
|
|
bandwidth = functor$4(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return base;
|
|
};
|
|
base.align = function () {
|
|
if (!arguments.length) {
|
|
return align;
|
|
}
|
|
align = arguments.length <= 0 ? undefined : arguments[0];
|
|
return base;
|
|
};
|
|
|
|
return base;
|
|
});
|
|
|
|
var errorBar = (function () {
|
|
|
|
var base = errorBarBase();
|
|
|
|
var join = dataJoin('g', 'error-bar');
|
|
|
|
var pathGenerator = shapeErrorBar().value(0);
|
|
|
|
var propagateTransition = function propagateTransition(maybeTransition) {
|
|
return function (selection$$1) {
|
|
return maybeTransition.selection ? selection$$1.transition(maybeTransition) : selection$$1;
|
|
};
|
|
};
|
|
|
|
var containerTranslation = function containerTranslation(values) {
|
|
return 'translate(' + values.origin[0] + ', ' + values.origin[1] + ')';
|
|
};
|
|
|
|
var errorBar = function errorBar(selection$$1) {
|
|
|
|
if (selection$$1.selection) {
|
|
join.transition(selection$$1);
|
|
}
|
|
|
|
var transitionPropagator = propagateTransition(selection$$1);
|
|
|
|
selection$$1.each(function (data, index, group) {
|
|
|
|
var filteredData = data.filter(base.defined());
|
|
var projectedData = filteredData.map(base.values);
|
|
var g = join(d3Selection.select(group[index]), filteredData);
|
|
|
|
g.enter().attr('stroke', colors.black).attr('fill', colors.gray).attr('transform', function (d, i) {
|
|
return containerTranslation(base.values(d, i)) + ' scale(1e-6, 1)';
|
|
}).append('path');
|
|
|
|
pathGenerator.orient(base.orient());
|
|
|
|
g.each(function (d, i, g) {
|
|
var values = projectedData[i];
|
|
pathGenerator.high(values.high).low(values.low).width(values.width);
|
|
|
|
transitionPropagator(d3Selection.select(g[i])).attr('transform', containerTranslation(values) + ' scale(1)').select('path').attr('d', pathGenerator([d]));
|
|
});
|
|
|
|
base.decorate()(g, data, index);
|
|
});
|
|
};
|
|
|
|
rebindAll(errorBar, base);
|
|
rebind(errorBar, join, 'key');
|
|
|
|
return errorBar;
|
|
});
|
|
|
|
var errorBar$1 = (function () {
|
|
|
|
var base = errorBarBase();
|
|
|
|
var pathGenerator = shapeErrorBar().value(0);
|
|
|
|
var errorBar = function errorBar(data) {
|
|
var filteredData = data.filter(base.defined());
|
|
var context = pathGenerator.context();
|
|
|
|
pathGenerator.orient(base.orient());
|
|
|
|
filteredData.forEach(function (d, i) {
|
|
context.save();
|
|
|
|
var values = base.values(d, i);
|
|
context.translate(values.origin[0], values.origin[1]);
|
|
context.beginPath();
|
|
|
|
pathGenerator.high(values.high).width(values.width).low(values.low)([d]);
|
|
|
|
context.strokeStyle = colors.black;
|
|
context.fillStyle = colors.gray;
|
|
|
|
base.decorate()(context, d, i);
|
|
|
|
context.fill();
|
|
context.stroke();
|
|
context.closePath();
|
|
|
|
context.restore();
|
|
});
|
|
};
|
|
|
|
rebindAll(errorBar, base);
|
|
rebind(errorBar, pathGenerator, 'context');
|
|
|
|
return errorBar;
|
|
});
|
|
|
|
var area$1 = (function () {
|
|
var base = xyBase();
|
|
|
|
var areaData = d3Shape.area();
|
|
|
|
var join = dataJoin('path', 'area');
|
|
|
|
var area$$1 = function area$$1(selection$$1) {
|
|
|
|
if (selection$$1.selection) {
|
|
join.transition(selection$$1);
|
|
}
|
|
|
|
areaData.defined(base.defined());
|
|
|
|
selection$$1.each(function (data, index, group) {
|
|
|
|
var projectedData = data.map(base.values);
|
|
areaData.x(function (_, i) {
|
|
return projectedData[i].transposedX;
|
|
}).y(function (_, i) {
|
|
return projectedData[i].transposedY;
|
|
});
|
|
|
|
var valueComponent = base.orient() === 'vertical' ? 'y' : 'x';
|
|
areaData[valueComponent + '0'](function (_, i) {
|
|
return projectedData[i].y0;
|
|
});
|
|
areaData[valueComponent + '1'](function (_, i) {
|
|
return projectedData[i].y;
|
|
});
|
|
|
|
var path$$1 = join(d3Selection.select(group[index]), [data]);
|
|
|
|
path$$1.enter().attr('fill', colors.gray);
|
|
|
|
path$$1.attr('d', areaData);
|
|
|
|
base.decorate()(path$$1, data, index);
|
|
});
|
|
};
|
|
|
|
rebindAll(area$$1, base, exclude('bandwidth', 'align'));
|
|
rebind(area$$1, join, 'key');
|
|
rebind(area$$1, areaData, 'curve');
|
|
|
|
return area$$1;
|
|
});
|
|
|
|
var area$2 = (function () {
|
|
var base = xyBase();
|
|
|
|
var areaData = d3Shape.area();
|
|
|
|
var area$$1 = function area$$1(data) {
|
|
var context = areaData.context();
|
|
|
|
areaData.defined(base.defined());
|
|
|
|
var projectedData = data.map(base.values);
|
|
areaData.x(function (_, i) {
|
|
return projectedData[i].transposedX;
|
|
}).y(function (_, i) {
|
|
return projectedData[i].transposedY;
|
|
});
|
|
|
|
var valueComponent = base.orient() === 'vertical' ? 'y' : 'x';
|
|
areaData[valueComponent + '0'](function (_, i) {
|
|
return projectedData[i].y0;
|
|
});
|
|
areaData[valueComponent + '1'](function (_, i) {
|
|
return projectedData[i].y;
|
|
});
|
|
|
|
context.beginPath();
|
|
areaData(data);
|
|
context.fillStyle = colors.gray;
|
|
context.strokeStyle = 'transparent';
|
|
|
|
base.decorate()(context, data);
|
|
|
|
context.fill();
|
|
context.stroke();
|
|
context.closePath();
|
|
};
|
|
|
|
rebindAll(area$$1, base, exclude('bandwidth', 'align'));
|
|
rebind(area$$1, areaData, 'curve', 'context');
|
|
|
|
return area$$1;
|
|
});
|
|
|
|
var ohlcBase$1 = (function () {
|
|
|
|
var base = void 0;
|
|
var crossValue = function crossValue(d) {
|
|
return d.date;
|
|
};
|
|
var openValue = function openValue(d) {
|
|
return d.open;
|
|
};
|
|
var highValue = function highValue(d) {
|
|
return d.high;
|
|
};
|
|
var lowValue = function lowValue(d) {
|
|
return d.low;
|
|
};
|
|
var closeValue = function closeValue(d) {
|
|
return d.close;
|
|
};
|
|
var bandwidth = function bandwidth() {
|
|
return 5;
|
|
};
|
|
var align = 'center';
|
|
var crossValueScaled = function crossValueScaled(d, i) {
|
|
return base.xScale()(crossValue(d, i));
|
|
};
|
|
|
|
base = createBase({
|
|
decorate: function decorate() {},
|
|
defined: function defined(d, i) {
|
|
return defined$1(crossValue, openValue, lowValue, highValue, closeValue)(d, i);
|
|
},
|
|
xScale: d3Scale.scaleIdentity(),
|
|
yScale: d3Scale.scaleIdentity()
|
|
});
|
|
|
|
base.values = function (d, i) {
|
|
var closeRaw = closeValue(d, i);
|
|
var openRaw = openValue(d, i);
|
|
var width = bandwidth(d, i);
|
|
var offset = alignOffset(align, width);
|
|
|
|
var direction = '';
|
|
if (closeRaw > openRaw) {
|
|
direction = 'up';
|
|
} else if (closeRaw < openRaw) {
|
|
direction = 'down';
|
|
}
|
|
|
|
return {
|
|
cross: crossValueScaled(d, i) + offset,
|
|
open: base.yScale()(openRaw),
|
|
high: base.yScale()(highValue(d, i)),
|
|
low: base.yScale()(lowValue(d, i)),
|
|
close: base.yScale()(closeRaw),
|
|
width: width,
|
|
direction: direction
|
|
};
|
|
};
|
|
|
|
base.crossValue = function () {
|
|
if (!arguments.length) {
|
|
return crossValue;
|
|
}
|
|
crossValue = arguments.length <= 0 ? undefined : arguments[0];
|
|
return base;
|
|
};
|
|
base.openValue = function () {
|
|
if (!arguments.length) {
|
|
return openValue;
|
|
}
|
|
openValue = arguments.length <= 0 ? undefined : arguments[0];
|
|
return base;
|
|
};
|
|
base.highValue = function () {
|
|
if (!arguments.length) {
|
|
return highValue;
|
|
}
|
|
highValue = arguments.length <= 0 ? undefined : arguments[0];
|
|
return base;
|
|
};
|
|
base.lowValue = function () {
|
|
if (!arguments.length) {
|
|
return lowValue;
|
|
}
|
|
lowValue = arguments.length <= 0 ? undefined : arguments[0];
|
|
return base;
|
|
};
|
|
base.yValue = base.closeValue = function () {
|
|
if (!arguments.length) {
|
|
return closeValue;
|
|
}
|
|
closeValue = arguments.length <= 0 ? undefined : arguments[0];
|
|
return base;
|
|
};
|
|
base.bandwidth = function () {
|
|
if (!arguments.length) {
|
|
return bandwidth;
|
|
}
|
|
bandwidth = functor$4(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return base;
|
|
};
|
|
base.align = function () {
|
|
if (!arguments.length) {
|
|
return align;
|
|
}
|
|
align = arguments.length <= 0 ? undefined : arguments[0];
|
|
return base;
|
|
};
|
|
|
|
return base;
|
|
});
|
|
|
|
var ohlcBase = (function (pathGenerator, seriesName) {
|
|
var base = ohlcBase$1();
|
|
var join = dataJoin('g', seriesName);
|
|
var containerTranslation = function containerTranslation(values) {
|
|
return 'translate(' + values.cross + ', ' + values.high + ')';
|
|
};
|
|
|
|
var propagateTransition = function propagateTransition(maybeTransition) {
|
|
return function (selection$$1) {
|
|
return maybeTransition.selection ? selection$$1.transition(maybeTransition) : selection$$1;
|
|
};
|
|
};
|
|
|
|
var candlestick = function candlestick(selection$$1) {
|
|
|
|
if (selection$$1.selection) {
|
|
join.transition(selection$$1);
|
|
}
|
|
|
|
var transitionPropagator = propagateTransition(selection$$1);
|
|
|
|
selection$$1.each(function (data, index, group) {
|
|
|
|
var filteredData = data.filter(base.defined());
|
|
|
|
var g = join(d3Selection.select(group[index]), filteredData);
|
|
|
|
g.enter().attr('transform', function (d, i) {
|
|
return containerTranslation(base.values(d, i)) + ' scale(1e-6, 1)';
|
|
}).append('path');
|
|
|
|
g.each(function (d, i, g) {
|
|
|
|
var values = base.values(d, i);
|
|
var color = values.direction === 'up' ? colors.green : colors.red;
|
|
|
|
var singleCandlestick = transitionPropagator(d3Selection.select(g[i])).attr('class', seriesName + ' ' + values.direction).attr('stroke', color).attr('fill', color).attr('transform', function () {
|
|
return containerTranslation(values) + ' scale(1)';
|
|
});
|
|
|
|
pathGenerator.x(0).width(values.width).open(function () {
|
|
return values.open - values.high;
|
|
}).high(0).low(function () {
|
|
return values.low - values.high;
|
|
}).close(function () {
|
|
return values.close - values.high;
|
|
});
|
|
|
|
singleCandlestick.select('path').attr('d', pathGenerator([d]));
|
|
});
|
|
|
|
base.decorate()(g, data, index);
|
|
});
|
|
};
|
|
|
|
rebind(candlestick, join, 'key');
|
|
rebindAll(candlestick, base);
|
|
|
|
return candlestick;
|
|
});
|
|
|
|
var candlestick = (function () {
|
|
return ohlcBase(shapeCandlestick(), 'candlestick');
|
|
});
|
|
|
|
var ohlcBase$2 = (function (pathGenerator) {
|
|
|
|
var base = ohlcBase$1();
|
|
|
|
var candlestick = function candlestick(data) {
|
|
var filteredData = data.filter(base.defined());
|
|
var context = pathGenerator.context();
|
|
|
|
filteredData.forEach(function (d, i) {
|
|
context.save();
|
|
|
|
var values = base.values(d, i);
|
|
context.translate(values.cross, values.high);
|
|
context.beginPath();
|
|
|
|
pathGenerator.x(0).open(function () {
|
|
return values.open - values.high;
|
|
}).width(values.width).high(0).low(function () {
|
|
return values.low - values.high;
|
|
}).close(function () {
|
|
return values.close - values.high;
|
|
})([d]);
|
|
|
|
var color = values.direction === 'up' ? colors.green : colors.red;
|
|
context.strokeStyle = color;
|
|
context.fillStyle = color;
|
|
|
|
base.decorate()(context, d, i);
|
|
|
|
context.fill();
|
|
context.stroke();
|
|
context.closePath();
|
|
|
|
context.restore();
|
|
});
|
|
};
|
|
|
|
rebind(candlestick, pathGenerator, 'context');
|
|
rebindAll(candlestick, base);
|
|
|
|
return candlestick;
|
|
});
|
|
|
|
var candlestick$1 = (function () {
|
|
return ohlcBase$2(shapeCandlestick());
|
|
});
|
|
|
|
var boxPlotBase = (function () {
|
|
|
|
var upperQuartileValue = function upperQuartileValue(d) {
|
|
return d.upperQuartile;
|
|
};
|
|
var lowerQuartileValue = function lowerQuartileValue(d) {
|
|
return d.lowerQuartile;
|
|
};
|
|
var highValue = function highValue(d) {
|
|
return d.high;
|
|
};
|
|
var lowValue = function lowValue(d) {
|
|
return d.low;
|
|
};
|
|
var crossValue = function crossValue(d) {
|
|
return d.value;
|
|
};
|
|
var medianValue = function medianValue(d) {
|
|
return d.median;
|
|
};
|
|
var orient = 'vertical';
|
|
var align = 'center';
|
|
var bandwidth = function bandwidth() {
|
|
return 5;
|
|
};
|
|
|
|
var base = createBase({
|
|
decorate: function decorate() {},
|
|
defined: function defined(d, i) {
|
|
return defined$1(lowValue, highValue, lowerQuartileValue, upperQuartileValue, crossValue, medianValue)(d, i);
|
|
},
|
|
xScale: d3Scale.scaleIdentity(),
|
|
yScale: d3Scale.scaleIdentity()
|
|
});
|
|
|
|
base.values = function (d, i) {
|
|
var width = bandwidth(d, i);
|
|
var offset = alignOffset(align, width);
|
|
var xScale = base.xScale();
|
|
var yScale = base.yScale();
|
|
|
|
if (orient === 'vertical') {
|
|
var y = yScale(highValue(d, i));
|
|
return {
|
|
origin: [xScale(crossValue(d, i)) + offset, y],
|
|
high: 0,
|
|
upperQuartile: yScale(upperQuartileValue(d, i)) - y,
|
|
median: yScale(medianValue(d, i)) - y,
|
|
lowerQuartile: yScale(lowerQuartileValue(d, i)) - y,
|
|
low: yScale(lowValue(d, i)) - y,
|
|
width: width
|
|
};
|
|
} else {
|
|
var x = xScale(lowValue(d, i));
|
|
return {
|
|
origin: [x, yScale(crossValue(d, i)) + offset],
|
|
high: xScale(highValue(d, i)) - x,
|
|
upperQuartile: xScale(upperQuartileValue(d, i)) - x,
|
|
median: xScale(medianValue(d, i)) - x,
|
|
lowerQuartile: xScale(lowerQuartileValue(d, i)) - x,
|
|
low: 0,
|
|
width: width
|
|
};
|
|
}
|
|
};
|
|
|
|
base.orient = function () {
|
|
if (!arguments.length) {
|
|
return orient;
|
|
}
|
|
orient = arguments.length <= 0 ? undefined : arguments[0];
|
|
return base;
|
|
};
|
|
base.lowerQuartileValue = function () {
|
|
if (!arguments.length) {
|
|
return lowerQuartileValue;
|
|
}
|
|
lowerQuartileValue = functor$4(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return base;
|
|
};
|
|
base.upperQuartileValue = function () {
|
|
if (!arguments.length) {
|
|
return upperQuartileValue;
|
|
}
|
|
upperQuartileValue = functor$4(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return base;
|
|
};
|
|
base.lowValue = function () {
|
|
if (!arguments.length) {
|
|
return lowValue;
|
|
}
|
|
lowValue = functor$4(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return base;
|
|
};
|
|
base.highValue = function () {
|
|
if (!arguments.length) {
|
|
return highValue;
|
|
}
|
|
highValue = functor$4(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return base;
|
|
};
|
|
base.crossValue = function () {
|
|
if (!arguments.length) {
|
|
return crossValue;
|
|
}
|
|
crossValue = functor$4(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return base;
|
|
};
|
|
base.medianValue = function () {
|
|
if (!arguments.length) {
|
|
return medianValue;
|
|
}
|
|
medianValue = functor$4(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return base;
|
|
};
|
|
base.bandwidth = function () {
|
|
if (!arguments.length) {
|
|
return bandwidth;
|
|
}
|
|
bandwidth = functor$4(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return base;
|
|
};
|
|
base.align = function () {
|
|
if (!arguments.length) {
|
|
return align;
|
|
}
|
|
align = arguments.length <= 0 ? undefined : arguments[0];
|
|
return base;
|
|
};
|
|
|
|
return base;
|
|
});
|
|
|
|
var boxPlot = (function () {
|
|
|
|
var base = boxPlotBase();
|
|
|
|
var join = dataJoin('g', 'box-plot');
|
|
|
|
var pathGenerator = shapeBoxPlot().value(0);
|
|
|
|
var propagateTransition = function propagateTransition(maybeTransition) {
|
|
return function (selection$$1) {
|
|
return maybeTransition.selection ? selection$$1.transition(maybeTransition) : selection$$1;
|
|
};
|
|
};
|
|
|
|
var containerTranslation = function containerTranslation(values) {
|
|
return 'translate(' + values.origin[0] + ', ' + values.origin[1] + ')';
|
|
};
|
|
|
|
var boxPlot = function boxPlot(selection$$1) {
|
|
|
|
if (selection$$1.selection) {
|
|
join.transition(selection$$1);
|
|
}
|
|
|
|
var transitionPropagator = propagateTransition(selection$$1);
|
|
|
|
selection$$1.each(function (data, index, group) {
|
|
|
|
var filteredData = data.filter(base.defined());
|
|
var g = join(d3Selection.select(group[index]), filteredData);
|
|
|
|
g.enter().attr('stroke', colors.black).attr('fill', colors.gray).attr('transform', function (d, i) {
|
|
return containerTranslation(base.values(d, i)) + ' scale(1e-6, 1)';
|
|
}).append('path');
|
|
|
|
pathGenerator.orient(base.orient());
|
|
|
|
g.each(function (d, i, g) {
|
|
var values = base.values(d, i);
|
|
pathGenerator.median(values.median).upperQuartile(values.upperQuartile).lowerQuartile(values.lowerQuartile).width(values.width).high(values.high).low(values.low);
|
|
|
|
transitionPropagator(d3Selection.select(g[i])).attr('transform', containerTranslation(values)).select('path').attr('d', pathGenerator([d]));
|
|
});
|
|
|
|
base.decorate()(g, data, index);
|
|
});
|
|
};
|
|
|
|
rebindAll(boxPlot, base);
|
|
rebind(boxPlot, join, 'key');
|
|
rebind(boxPlot, pathGenerator, 'cap');
|
|
|
|
return boxPlot;
|
|
});
|
|
|
|
var boxPlot$1 = (function () {
|
|
|
|
var base = boxPlotBase();
|
|
|
|
var pathGenerator = shapeBoxPlot().value(0);
|
|
|
|
var boxPlot = function boxPlot(data) {
|
|
var filteredData = data.filter(base.defined());
|
|
var context = pathGenerator.context();
|
|
|
|
pathGenerator.orient(base.orient());
|
|
|
|
filteredData.forEach(function (d, i) {
|
|
context.save();
|
|
|
|
var values = base.values(d, i);
|
|
context.translate(values.origin[0], values.origin[1]);
|
|
context.beginPath();
|
|
|
|
pathGenerator.median(values.median).upperQuartile(values.upperQuartile).lowerQuartile(values.lowerQuartile).high(values.high).width(values.width).low(values.low)([d]);
|
|
|
|
context.fillStyle = colors.gray;
|
|
context.strokeStyle = colors.black;
|
|
|
|
base.decorate()(context, d, i);
|
|
|
|
context.fill();
|
|
context.stroke();
|
|
context.closePath();
|
|
|
|
context.restore();
|
|
});
|
|
};
|
|
|
|
rebindAll(boxPlot, base);
|
|
rebind(boxPlot, pathGenerator, 'cap', 'context');
|
|
|
|
return boxPlot;
|
|
});
|
|
|
|
var ohlc = (function () {
|
|
return ohlcBase(shapeOhlc(), 'ohlc');
|
|
});
|
|
|
|
var ohlc$1 = (function () {
|
|
return ohlcBase$2(shapeOhlc());
|
|
});
|
|
|
|
var multiBase = (function () {
|
|
|
|
var series = [];
|
|
var mapping = function mapping(d) {
|
|
return d;
|
|
};
|
|
var key = function key(_, i) {
|
|
return i;
|
|
};
|
|
|
|
var multi = createBase({
|
|
decorate: function decorate() {},
|
|
xScale: d3Scale.scaleIdentity(),
|
|
yScale: d3Scale.scaleIdentity()
|
|
});
|
|
|
|
multi.mapping = function () {
|
|
if (!arguments.length) {
|
|
return mapping;
|
|
}
|
|
mapping = arguments.length <= 0 ? undefined : arguments[0];
|
|
return multi;
|
|
};
|
|
multi.key = function () {
|
|
if (!arguments.length) {
|
|
return key;
|
|
}
|
|
key = arguments.length <= 0 ? undefined : arguments[0];
|
|
return multi;
|
|
};
|
|
multi.series = function () {
|
|
if (!arguments.length) {
|
|
return series;
|
|
}
|
|
series = arguments.length <= 0 ? undefined : arguments[0];
|
|
return multi;
|
|
};
|
|
|
|
return multi;
|
|
});
|
|
|
|
var seriesSvgMulti = (function () {
|
|
|
|
var base = multiBase();
|
|
|
|
var innerJoin = dataJoin('g');
|
|
|
|
var join = dataJoin('g', 'multi');
|
|
|
|
var multi = function multi(selection$$1) {
|
|
|
|
if (selection$$1.selection) {
|
|
join.transition(selection$$1);
|
|
innerJoin.transition(selection$$1);
|
|
}
|
|
|
|
var mapping = base.mapping();
|
|
var series = base.series();
|
|
var xScale = base.xScale();
|
|
var yScale = base.yScale();
|
|
|
|
selection$$1.each(function (data, index, group) {
|
|
|
|
var container = join(d3Selection.select(group[index]), series);
|
|
|
|
// iterate over the containers, 'call'-ing the series for each
|
|
container.each(function (dataSeries, seriesIndex, seriesGroup) {
|
|
dataSeries.xScale(xScale).yScale(yScale);
|
|
|
|
var seriesData = mapping(data, seriesIndex, series);
|
|
var innerContainer = innerJoin(d3Selection.select(seriesGroup[seriesIndex]), [seriesData]);
|
|
|
|
innerContainer.call(dataSeries);
|
|
});
|
|
|
|
var unwrappedSelection = container.selection ? container.selection() : container;
|
|
unwrappedSelection.order();
|
|
|
|
base.decorate()(container, data, index);
|
|
});
|
|
};
|
|
|
|
rebindAll(multi, base);
|
|
rebind(multi, join, 'key');
|
|
|
|
return multi;
|
|
});
|
|
|
|
var seriesCanvasMulti = (function () {
|
|
|
|
var context = null;
|
|
var base = multiBase();
|
|
|
|
var multi = function multi(data) {
|
|
var mapping = base.mapping();
|
|
var series = base.series();
|
|
var xScale = base.xScale();
|
|
var yScale = base.yScale();
|
|
|
|
series.forEach(function (dataSeries, index) {
|
|
var seriesData = mapping(data, index, series);
|
|
dataSeries.context(context).xScale(xScale).yScale(yScale);
|
|
|
|
var adaptedDecorate = void 0;
|
|
if (dataSeries.decorate) {
|
|
adaptedDecorate = dataSeries.decorate();
|
|
dataSeries.decorate(function (c, d, i) {
|
|
base.decorate()(c, data, index);
|
|
adaptedDecorate(c, d, i);
|
|
});
|
|
} else {
|
|
base.decorate()(context, data, index);
|
|
}
|
|
|
|
dataSeries(seriesData);
|
|
|
|
if (adaptedDecorate) {
|
|
dataSeries.decorate(adaptedDecorate);
|
|
}
|
|
});
|
|
};
|
|
|
|
multi.context = function () {
|
|
if (!arguments.length) {
|
|
return context;
|
|
}
|
|
context = arguments.length <= 0 ? undefined : arguments[0];
|
|
return multi;
|
|
};
|
|
|
|
rebindAll(multi, base);
|
|
|
|
return multi;
|
|
});
|
|
|
|
var groupedBase = (function (series) {
|
|
|
|
var bandwidth = function bandwidth() {
|
|
return 50;
|
|
};
|
|
var align = 'center';
|
|
|
|
// the offset scale is used to offset each of the series within a group
|
|
var offsetScale = d3Scale.scaleBand();
|
|
|
|
var grouped = createBase({
|
|
decorate: function decorate() {},
|
|
xScale: d3Scale.scaleLinear(),
|
|
yScale: d3Scale.scaleLinear()
|
|
});
|
|
|
|
// the bandwidth for the grouped series can be a function of datum / index. As a result
|
|
// the offset scale required to cluster the 'sub' series is also dependent on datum / index.
|
|
// This function computes the offset scale for a specific datum / index of the grouped series
|
|
grouped.offsetScaleForDatum = function (data, d, i) {
|
|
var width = bandwidth(d, i);
|
|
var offset = alignOffset(align, width);
|
|
|
|
var halfWidth = width / 2;
|
|
return offsetScale.domain(d3Array.range(0, data.length)).range([-halfWidth + offset, halfWidth + offset]);
|
|
};
|
|
|
|
grouped.bandwidth = function () {
|
|
if (!arguments.length) {
|
|
return bandwidth;
|
|
}
|
|
bandwidth = functor$4(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return grouped;
|
|
};
|
|
grouped.align = function () {
|
|
if (!arguments.length) {
|
|
return align;
|
|
}
|
|
align = arguments.length <= 0 ? undefined : arguments[0];
|
|
return grouped;
|
|
};
|
|
|
|
rebindAll(grouped, offsetScale, includeMap({ 'paddingInner': 'paddingOuter' }));
|
|
|
|
return grouped;
|
|
});
|
|
|
|
var grouped = (function (series) {
|
|
|
|
var base = groupedBase(series);
|
|
|
|
var join = dataJoin('g', 'grouped');
|
|
|
|
var grouped = function grouped(selection$$1) {
|
|
|
|
if (selection$$1.selection) {
|
|
join.transition(selection$$1);
|
|
}
|
|
|
|
selection$$1.each(function (data, index, group) {
|
|
|
|
var g = join(d3Selection.select(group[index]), data);
|
|
|
|
g.enter().append('g');
|
|
|
|
g.select('g').each(function (_, index, group) {
|
|
var container = d3Selection.select(group[index]);
|
|
|
|
// create a composite scale that applies the required offset
|
|
var isVertical = series.orient() !== 'horizontal';
|
|
var compositeScale = function compositeScale(d, i) {
|
|
var offset = base.offsetScaleForDatum(data, d, i);
|
|
var baseScale = isVertical ? base.xScale() : base.yScale();
|
|
return baseScale(d) + offset(index) + offset.bandwidth() / 2;
|
|
};
|
|
|
|
if (isVertical) {
|
|
series.xScale(compositeScale);
|
|
series.yScale(base.yScale());
|
|
} else {
|
|
series.yScale(compositeScale);
|
|
series.xScale(base.xScale());
|
|
}
|
|
|
|
// if the sub-series has a bandwidth, set this from the offset scale
|
|
if (series.bandwidth) {
|
|
series.bandwidth(function (d, i) {
|
|
return base.offsetScaleForDatum(data, d, i).bandwidth();
|
|
});
|
|
}
|
|
|
|
// adapt the decorate function to give each series the correct index
|
|
series.decorate(function (s, d) {
|
|
return base.decorate()(s, d, index);
|
|
});
|
|
|
|
container.call(series);
|
|
});
|
|
});
|
|
};
|
|
|
|
rebindAll(grouped, series, exclude('decorate', 'xScale', 'yScale'));
|
|
rebindAll(grouped, base, exclude('offsetScaleForDatum'));
|
|
|
|
return grouped;
|
|
});
|
|
|
|
var grouped$1 = function (series) {
|
|
|
|
var base = groupedBase(series);
|
|
|
|
var grouped = function grouped(data) {
|
|
data.forEach(function (seriesData, index) {
|
|
|
|
// create a composite scale that applies the required offset
|
|
var isVertical = series.orient() !== 'horizontal';
|
|
var compositeScale = function compositeScale(d, i) {
|
|
var offset = base.offsetScaleForDatum(data, d, i);
|
|
var baseScale = isVertical ? base.xScale() : base.yScale();
|
|
return baseScale(d) + offset(index) + offset.bandwidth() / 2;
|
|
};
|
|
|
|
if (isVertical) {
|
|
series.xScale(compositeScale);
|
|
series.yScale(base.yScale());
|
|
} else {
|
|
series.yScale(compositeScale);
|
|
series.xScale(base.xScale());
|
|
}
|
|
|
|
// if the sub-series has a bandwidth, set this from the offset scale
|
|
if (series.bandwidth) {
|
|
series.bandwidth(function (d, i) {
|
|
return base.offsetScaleForDatum(data, d, i).bandwidth();
|
|
});
|
|
}
|
|
|
|
// adapt the decorate function to give each series the correct index
|
|
series.decorate(function (c, d) {
|
|
return base.decorate()(c, d, index);
|
|
});
|
|
series(seriesData);
|
|
});
|
|
};
|
|
|
|
rebindAll(grouped, series, exclude('decorate', 'xScale', 'yScale'));
|
|
rebindAll(grouped, base, exclude('offsetScaleForDatum'));
|
|
|
|
return grouped;
|
|
};
|
|
|
|
var repeat = (function () {
|
|
|
|
var orient = 'vertical';
|
|
var series = seriesSvgLine();
|
|
var multi = seriesSvgMulti();
|
|
|
|
var repeat = function repeat(selection$$1) {
|
|
return selection$$1.each(function (data, index, group) {
|
|
if (orient === 'vertical') {
|
|
multi.series(data[0].map(function (_) {
|
|
return series;
|
|
})).mapping(function (data, index) {
|
|
return data.map(function (d) {
|
|
return d[index];
|
|
});
|
|
});
|
|
} else {
|
|
multi.series(data.map(function (_) {
|
|
return series;
|
|
})).mapping(function (data, index) {
|
|
return data[index];
|
|
});
|
|
}
|
|
d3Selection.select(group[index]).call(multi);
|
|
});
|
|
};
|
|
|
|
repeat.series = function () {
|
|
if (!arguments.length) {
|
|
return series;
|
|
}
|
|
series = arguments.length <= 0 ? undefined : arguments[0];
|
|
return repeat;
|
|
};
|
|
|
|
repeat.orient = function () {
|
|
if (!arguments.length) {
|
|
return orient;
|
|
}
|
|
orient = arguments.length <= 0 ? undefined : arguments[0];
|
|
return repeat;
|
|
};
|
|
|
|
rebindAll(repeat, multi, exclude('series', 'mapping'));
|
|
|
|
return repeat;
|
|
});
|
|
|
|
var repeat$1 = (function () {
|
|
|
|
var orient = 'vertical';
|
|
var series = seriesCanvasLine();
|
|
var multi = seriesCanvasMulti();
|
|
|
|
var repeat = function repeat(data) {
|
|
if (orient === 'vertical') {
|
|
multi.series(data[0].map(function (_) {
|
|
return series;
|
|
})).mapping(function (data, index) {
|
|
return data.map(function (d) {
|
|
return d[index];
|
|
});
|
|
});
|
|
} else {
|
|
multi.series(data.map(function (_) {
|
|
return series;
|
|
})).mapping(function (data, index) {
|
|
return data[index];
|
|
});
|
|
}
|
|
multi(data);
|
|
};
|
|
|
|
repeat.series = function () {
|
|
if (!arguments.length) {
|
|
return series;
|
|
}
|
|
series = arguments.length <= 0 ? undefined : arguments[0];
|
|
return repeat;
|
|
};
|
|
|
|
repeat.orient = function () {
|
|
if (!arguments.length) {
|
|
return orient;
|
|
}
|
|
orient = arguments.length <= 0 ? undefined : arguments[0];
|
|
return repeat;
|
|
};
|
|
|
|
rebindAll(repeat, multi, exclude('series', 'mapping'));
|
|
|
|
return repeat;
|
|
});
|
|
|
|
var sortUnique = function sortUnique(arr) {
|
|
return arr.sort(d3Array.ascending).filter(function (value, index, self) {
|
|
return self.indexOf(value, index + 1) === -1;
|
|
});
|
|
};
|
|
|
|
var autoBandwidth = (function (adaptee) {
|
|
|
|
var widthFraction = 0.75;
|
|
|
|
// computes the bandwidth as a fraction of the smallest distance between the datapoints
|
|
var computeBandwidth = function computeBandwidth(screenValues) {
|
|
// return some default value if there are not enough datapoints to compute the width
|
|
if (screenValues.length <= 1) {
|
|
return 10;
|
|
}
|
|
|
|
screenValues = sortUnique(screenValues);
|
|
|
|
// compute the distance between neighbouring items
|
|
var neighbourDistances = d3Array.pairs(screenValues).map(function (tuple) {
|
|
return Math.abs(tuple[0] - tuple[1]);
|
|
});
|
|
|
|
var minDistance = d3Array.min(neighbourDistances);
|
|
return widthFraction * minDistance;
|
|
};
|
|
|
|
var determineBandwith = function determineBandwith(crossScale, data, accessor) {
|
|
// if the cross-scale has a bandwidth function, i.e. it is a scaleBand, use
|
|
// this to determine the width
|
|
if (crossScale.bandwidth) {
|
|
return crossScale.bandwidth();
|
|
} else {
|
|
var _ref;
|
|
|
|
// grouped series expect a nested array, which is flattened out
|
|
var flattenedData = Array.isArray(data) ? (_ref = []).concat.apply(_ref, toConsumableArray(data)) : data;
|
|
|
|
// obtain an array of points along the crossValue axis, mapped to screen coordinates.
|
|
var crossValuePoints = flattenedData.filter(adaptee.defined()).map(accessor()).map(crossScale);
|
|
|
|
var width = computeBandwidth(crossValuePoints);
|
|
|
|
return width;
|
|
}
|
|
};
|
|
|
|
var autoBandwidth = function autoBandwidth(arg) {
|
|
|
|
var computeWidth = function computeWidth(data) {
|
|
|
|
if (adaptee.xBandwidth && adaptee.yBandwidth) {
|
|
adaptee.xBandwidth(determineBandwith(adaptee.xScale(), data, adaptee.xValue));
|
|
adaptee.yBandwidth(determineBandwith(adaptee.yScale(), data, adaptee.yValue));
|
|
} else {
|
|
// if the series has an orient property, use this to determine the cross-scale, otherwise
|
|
// assume it is the x-scale
|
|
var crossScale = adaptee.orient && adaptee.orient() === 'horizontal' ? adaptee.yScale() : adaptee.xScale();
|
|
|
|
adaptee.bandwidth(determineBandwith(crossScale, data, adaptee.crossValue));
|
|
}
|
|
};
|
|
|
|
if (arg instanceof d3Selection.selection) {
|
|
arg.each(function (data, index, group) {
|
|
computeWidth(data);
|
|
adaptee(d3Selection.select(group[index]));
|
|
});
|
|
} else {
|
|
computeWidth(arg);
|
|
adaptee(arg);
|
|
}
|
|
};
|
|
|
|
rebindAll(autoBandwidth, adaptee);
|
|
|
|
autoBandwidth.widthFraction = function () {
|
|
if (!arguments.length) {
|
|
return widthFraction;
|
|
}
|
|
widthFraction = arguments.length <= 0 ? undefined : arguments[0];
|
|
return autoBandwidth;
|
|
};
|
|
|
|
return autoBandwidth;
|
|
});
|
|
|
|
var heatmapBase = (function () {
|
|
|
|
var xValue = function xValue(d) {
|
|
return d.x;
|
|
};
|
|
var yValue = function yValue(d) {
|
|
return d.y;
|
|
};
|
|
var colorValue = function colorValue(d) {
|
|
return d.color;
|
|
};
|
|
var yBandwidth = function yBandwidth() {
|
|
return 5;
|
|
};
|
|
var xBandwidth = function xBandwidth() {
|
|
return 5;
|
|
};
|
|
var colorInterpolate = d3Scale.interpolateViridis;
|
|
|
|
var heatmap = createBase({
|
|
decorate: function decorate() {},
|
|
defined: function defined(d, i) {
|
|
return defined$1(xValue, yValue, colorValue)(d, i);
|
|
},
|
|
xScale: d3Scale.scaleIdentity(),
|
|
yScale: d3Scale.scaleIdentity()
|
|
});
|
|
|
|
heatmap.pathGenerator = shapeBar().x(0).y(0);
|
|
|
|
heatmap.colorScale = function (data) {
|
|
var colorValues = data.map(colorValue);
|
|
// a scale that maps the color values onto a unit range, [0, 1]
|
|
return d3Scale.scaleLinear().domain([d3Array.min(colorValues), d3Array.max(colorValues)]);
|
|
};
|
|
|
|
heatmap.values = function (d, i) {
|
|
return {
|
|
x: heatmap.xScale()(xValue(d, i)),
|
|
y: heatmap.yScale()(yValue(d, i)),
|
|
colorValue: colorValue(d, i),
|
|
width: xBandwidth(d, i),
|
|
height: yBandwidth(d, i)
|
|
};
|
|
};
|
|
|
|
heatmap.xValue = function () {
|
|
if (!arguments.length) {
|
|
return xValue;
|
|
}
|
|
xValue = functor$4(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return heatmap;
|
|
};
|
|
heatmap.yValue = function () {
|
|
if (!arguments.length) {
|
|
return yValue;
|
|
}
|
|
yValue = functor$4(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return heatmap;
|
|
};
|
|
heatmap.colorValue = function () {
|
|
if (!arguments.length) {
|
|
return colorValue;
|
|
}
|
|
colorValue = functor$4(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return heatmap;
|
|
};
|
|
heatmap.colorInterpolate = function () {
|
|
if (!arguments.length) {
|
|
return colorInterpolate;
|
|
}
|
|
colorInterpolate = arguments.length <= 0 ? undefined : arguments[0];
|
|
return heatmap;
|
|
};
|
|
heatmap.xBandwidth = function () {
|
|
if (!arguments.length) {
|
|
return xBandwidth;
|
|
}
|
|
xBandwidth = functor$4(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return heatmap;
|
|
};
|
|
heatmap.yBandwidth = function () {
|
|
if (!arguments.length) {
|
|
return yBandwidth;
|
|
}
|
|
yBandwidth = functor$4(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return heatmap;
|
|
};
|
|
|
|
rebindAll(heatmap, heatmap.pathGenerator, includeMap({
|
|
'horizontalAlign': 'xAlign',
|
|
'verticalAlign': 'yAlign'
|
|
}));
|
|
|
|
return heatmap;
|
|
});
|
|
|
|
var heatmap = (function () {
|
|
|
|
var base = heatmapBase();
|
|
|
|
var join = dataJoin('g', 'box');
|
|
|
|
var containerTransform = function containerTransform(values) {
|
|
return 'translate(' + values.x + ', ' + values.y + ')';
|
|
};
|
|
|
|
var heatmap = function heatmap(selection$$1) {
|
|
|
|
selection$$1.each(function (data, index, group) {
|
|
|
|
var filteredData = data.filter(base.defined());
|
|
var colorValue = base.colorValue();
|
|
var colorInterpolate = base.colorInterpolate();
|
|
var colorScale = base.colorScale(filteredData);
|
|
|
|
var g = join(d3Selection.select(group[index]), filteredData);
|
|
|
|
g.enter().append('path').attr('stroke', 'transparent');
|
|
|
|
g.attr('transform', function (d, i) {
|
|
return containerTransform(base.values(d, i));
|
|
}).select('path').attr('d', function (d, i) {
|
|
return base.pathGenerator.width(base.values(d, i).width).height(base.values(d, i).height)([d]);
|
|
}).attr('fill', function (d, i) {
|
|
return colorInterpolate(colorScale(colorValue(d, i)));
|
|
});
|
|
|
|
base.decorate()(g, data, index);
|
|
});
|
|
};
|
|
|
|
rebindAll(heatmap, base);
|
|
|
|
return heatmap;
|
|
});
|
|
|
|
var heatmap$1 = (function () {
|
|
|
|
var context = null;
|
|
var base = heatmapBase();
|
|
|
|
var heatmap = function heatmap(data) {
|
|
var filteredData = data.filter(base.defined());
|
|
var colorValue = base.colorValue();
|
|
var colorInterpolate = base.colorInterpolate();
|
|
var colorScale = base.colorScale(filteredData);
|
|
var context = base.pathGenerator.context();
|
|
|
|
filteredData.forEach(function (d, i) {
|
|
context.save();
|
|
context.beginPath();
|
|
|
|
var values = base.values(d, i);
|
|
context.translate(values.x, values.y);
|
|
|
|
context.fillStyle = colorInterpolate(colorScale(values.colorValue));
|
|
context.strokeStyle = 'transparent';
|
|
|
|
base.pathGenerator.height(values.height).width(values.width)([d]);
|
|
|
|
base.decorate()(context, d, i);
|
|
|
|
context.fill();
|
|
context.stroke();
|
|
context.closePath();
|
|
context.restore();
|
|
});
|
|
};
|
|
|
|
rebind(heatmap, base.pathGenerator, 'context');
|
|
rebindAll(heatmap, base);
|
|
|
|
return heatmap;
|
|
});
|
|
|
|
var constant = (function (value) {
|
|
return typeof value === 'function' ? value : function () {
|
|
return value;
|
|
};
|
|
});
|
|
|
|
var band = (function () {
|
|
|
|
var xScale = d3Scale.scaleIdentity();
|
|
var yScale = d3Scale.scaleIdentity();
|
|
var orient = 'horizontal';
|
|
var fromValue = function fromValue(d) {
|
|
return d.from;
|
|
};
|
|
var toValue = function toValue(d) {
|
|
return d.to;
|
|
};
|
|
var decorate = function decorate() {};
|
|
|
|
var join = dataJoin('g', 'annotation-band');
|
|
|
|
var pathGenerator = shapeBar().horizontalAlign('center').verticalAlign('center').x(0).y(0);
|
|
|
|
var instance = function instance(selection$$1) {
|
|
|
|
if (selection$$1.selection) {
|
|
join.transition(selection$$1);
|
|
}
|
|
|
|
if (orient !== 'horizontal' && orient !== 'vertical') {
|
|
throw new Error('Invalid orientation');
|
|
}
|
|
|
|
var horizontal = orient === 'horizontal';
|
|
var translation = horizontal ? function (a, b) {
|
|
return 'translate(' + a + ', ' + b + ')';
|
|
} : function (a, b) {
|
|
return 'translate(' + b + ', ' + a + ')';
|
|
};
|
|
// the value scale which the annotation 'value' relates to, the crossScale
|
|
// is the other. Which is which depends on the orienation!
|
|
var crossScale = horizontal ? xScale : yScale;
|
|
var valueScale = horizontal ? yScale : xScale;
|
|
var crossScaleRange = crossScale.range();
|
|
var crossScaleSize = crossScaleRange[1] - crossScaleRange[0];
|
|
var valueAxisDimension = horizontal ? 'height' : 'width';
|
|
var crossAxisDimension = horizontal ? 'width' : 'height';
|
|
var containerTransform = function containerTransform() {
|
|
return translation((crossScaleRange[1] + crossScaleRange[0]) / 2, (valueScale(toValue.apply(undefined, arguments)) + valueScale(fromValue.apply(undefined, arguments))) / 2);
|
|
};
|
|
|
|
pathGenerator[crossAxisDimension](crossScaleSize);
|
|
pathGenerator[valueAxisDimension](function () {
|
|
return valueScale(toValue.apply(undefined, arguments)) - valueScale(fromValue.apply(undefined, arguments));
|
|
});
|
|
|
|
selection$$1.each(function (data, index, nodes) {
|
|
|
|
var g = join(d3Selection.select(nodes[index]), data);
|
|
|
|
g.enter().attr('transform', containerTransform).append('path').classed('band', true);
|
|
|
|
g.attr('class', 'annotation-band ' + orient).attr('transform', containerTransform).select('path')
|
|
// the path generator is being used to render a single path, hence
|
|
// an explicit index is provided
|
|
.attr('d', function (d, i) {
|
|
return pathGenerator([d], i);
|
|
});
|
|
|
|
decorate(g, data, index);
|
|
});
|
|
};
|
|
|
|
instance.xScale = function () {
|
|
if (!arguments.length) {
|
|
return xScale;
|
|
}
|
|
xScale = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
instance.yScale = function () {
|
|
if (!arguments.length) {
|
|
return yScale;
|
|
}
|
|
yScale = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
instance.orient = function () {
|
|
if (!arguments.length) {
|
|
return orient;
|
|
}
|
|
orient = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
instance.decorate = function () {
|
|
if (!arguments.length) {
|
|
return decorate;
|
|
}
|
|
decorate = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
instance.fromValue = function () {
|
|
if (!arguments.length) {
|
|
return fromValue;
|
|
}
|
|
fromValue = constant(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return instance;
|
|
};
|
|
instance.toValue = function () {
|
|
if (!arguments.length) {
|
|
return toValue;
|
|
}
|
|
toValue = constant(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return instance;
|
|
};
|
|
|
|
return instance;
|
|
});
|
|
|
|
var band$1 = (function () {
|
|
|
|
var xScale = d3Scale.scaleIdentity();
|
|
var yScale = d3Scale.scaleIdentity();
|
|
var orient = 'horizontal';
|
|
var fromValue = function fromValue(d) {
|
|
return d.from;
|
|
};
|
|
var toValue = function toValue(d) {
|
|
return d.to;
|
|
};
|
|
var decorate = function decorate() {};
|
|
|
|
var pathGenerator = shapeBar().horizontalAlign('right').verticalAlign('top');
|
|
|
|
var instance = function instance(data) {
|
|
|
|
if (orient !== 'horizontal' && orient !== 'vertical') {
|
|
throw new Error('Invalid orientation');
|
|
}
|
|
|
|
var context = pathGenerator.context();
|
|
var horizontal = orient === 'horizontal';
|
|
// the value scale which the annotation 'value' relates to, the crossScale
|
|
// is the other. Which is which depends on the orienation!
|
|
var crossScale = horizontal ? xScale : yScale;
|
|
var valueScale = horizontal ? yScale : xScale;
|
|
var crossScaleRange = crossScale.range();
|
|
var crossScaleSize = crossScaleRange[1] - crossScaleRange[0];
|
|
var valueAxisStart = horizontal ? 'x' : 'y';
|
|
var crossAxisStart = horizontal ? 'y' : 'x';
|
|
var valueAxisDimension = horizontal ? 'height' : 'width';
|
|
var crossAxisDimension = horizontal ? 'width' : 'height';
|
|
|
|
data.forEach(function (d, i) {
|
|
context.save();
|
|
context.beginPath();
|
|
context.strokeStyle = 'transparent';
|
|
|
|
pathGenerator[crossAxisStart](valueScale(fromValue(d)));
|
|
pathGenerator[valueAxisStart](crossScaleRange[0]);
|
|
pathGenerator[crossAxisDimension](crossScaleSize);
|
|
pathGenerator[valueAxisDimension](valueScale(toValue(d)) - valueScale(fromValue(d)));
|
|
|
|
decorate(context, d, i);
|
|
pathGenerator.context(context)([d], i);
|
|
|
|
context.fill();
|
|
context.stroke();
|
|
context.closePath();
|
|
context.restore();
|
|
});
|
|
};
|
|
|
|
instance.xScale = function () {
|
|
if (!arguments.length) {
|
|
return xScale;
|
|
}
|
|
xScale = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
instance.yScale = function () {
|
|
if (!arguments.length) {
|
|
return yScale;
|
|
}
|
|
yScale = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
instance.orient = function () {
|
|
if (!arguments.length) {
|
|
return orient;
|
|
}
|
|
orient = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
instance.decorate = function () {
|
|
if (!arguments.length) {
|
|
return decorate;
|
|
}
|
|
decorate = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
instance.fromValue = function () {
|
|
if (!arguments.length) {
|
|
return fromValue;
|
|
}
|
|
fromValue = constant(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return instance;
|
|
};
|
|
instance.toValue = function () {
|
|
if (!arguments.length) {
|
|
return toValue;
|
|
}
|
|
toValue = constant(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return instance;
|
|
};
|
|
|
|
rebind(instance, pathGenerator, 'context');
|
|
|
|
return instance;
|
|
});
|
|
|
|
var annotationLine = (function () {
|
|
|
|
var xScale = d3Scale.scaleIdentity();
|
|
var yScale = d3Scale.scaleIdentity();
|
|
var value = function value(d) {
|
|
return d;
|
|
};
|
|
var label = value;
|
|
var decorate = function decorate() {};
|
|
var orient = 'horizontal';
|
|
|
|
var join = dataJoin('g', 'annotation-line');
|
|
|
|
var instance = function instance(selection$$1) {
|
|
|
|
if (selection$$1.selection) {
|
|
join.transition(selection$$1);
|
|
}
|
|
|
|
if (orient !== 'horizontal' && orient !== 'vertical') {
|
|
throw new Error('Invalid orientation');
|
|
}
|
|
var horizontal = orient === 'horizontal';
|
|
var translation = horizontal ? function (a, b) {
|
|
return 'translate(' + a + ', ' + b + ')';
|
|
} : function (a, b) {
|
|
return 'translate(' + b + ', ' + a + ')';
|
|
};
|
|
var lineProperty = horizontal ? 'x2' : 'y2';
|
|
// the value scale which the annotation 'value' relates to, the crossScale
|
|
// is the other. Which is which depends on the orienation!
|
|
var crossScale = horizontal ? xScale : yScale;
|
|
var valueScale = horizontal ? yScale : xScale;
|
|
var handleOne = horizontal ? 'left-handle' : 'bottom-handle';
|
|
var handleTwo = horizontal ? 'right-handle' : 'top-handle';
|
|
var textOffsetX = horizontal ? '9' : '0';
|
|
var textOffsetY = horizontal ? '0' : '9';
|
|
var textOffsetDeltaY = horizontal ? '0.32em' : '0.71em';
|
|
var textAnchor = horizontal ? 'start' : 'middle';
|
|
|
|
var scaleRange = crossScale.range();
|
|
// the transform that sets the 'origin' of the annotation
|
|
var containerTransform = function containerTransform() {
|
|
return translation(scaleRange[0], valueScale(value.apply(undefined, arguments)));
|
|
};
|
|
var scaleWidth = scaleRange[1] - scaleRange[0];
|
|
|
|
selection$$1.each(function (data, selectionIndex, nodes) {
|
|
|
|
var g = join(d3Selection.select(nodes[selectionIndex]), data);
|
|
|
|
// create the outer container and line
|
|
var enter = g.enter().attr('transform', containerTransform).style('stroke', '#bbb');
|
|
enter.append('line').attr(lineProperty, scaleWidth);
|
|
|
|
// create containers at each end of the annotation
|
|
enter.append('g').classed(handleOne, true).style('stroke', 'none');
|
|
|
|
enter.append('g').classed(handleTwo, true).style('stroke', 'none').attr('transform', translation(scaleWidth, 0)).append('text').attr('text-anchor', textAnchor).attr('x', textOffsetX).attr('y', textOffsetY).attr('dy', textOffsetDeltaY);
|
|
|
|
// Update
|
|
g.attr('class', 'annotation-line ' + orient);
|
|
|
|
// translate the parent container to the left hand edge of the annotation
|
|
g.attr('transform', containerTransform);
|
|
|
|
// update the elements that depend on scale width
|
|
g.select('line').attr(lineProperty, scaleWidth);
|
|
g.select('g.' + handleTwo).attr('transform', translation(scaleWidth, 0));
|
|
|
|
// Update the text label
|
|
g.select('text').text(label);
|
|
|
|
decorate(g, data, selectionIndex);
|
|
});
|
|
};
|
|
|
|
instance.xScale = function () {
|
|
if (!arguments.length) {
|
|
return xScale;
|
|
}
|
|
xScale = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
instance.yScale = function () {
|
|
if (!arguments.length) {
|
|
return yScale;
|
|
}
|
|
yScale = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
instance.value = function () {
|
|
if (!arguments.length) {
|
|
return value;
|
|
}
|
|
value = constant(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return instance;
|
|
};
|
|
instance.label = function () {
|
|
if (!arguments.length) {
|
|
return label;
|
|
}
|
|
label = constant(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return instance;
|
|
};
|
|
instance.decorate = function () {
|
|
if (!arguments.length) {
|
|
return decorate;
|
|
}
|
|
decorate = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
instance.orient = function () {
|
|
if (!arguments.length) {
|
|
return orient;
|
|
}
|
|
orient = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
|
|
return instance;
|
|
});
|
|
|
|
var crosshair = function () {
|
|
|
|
var x = function x(d) {
|
|
return d.x;
|
|
};
|
|
var y = function y(d) {
|
|
return d.y;
|
|
};
|
|
var xScale = d3Scale.scaleIdentity();
|
|
var yScale = d3Scale.scaleIdentity();
|
|
var decorate = function decorate() {};
|
|
|
|
var join = dataJoin('g', 'annotation-crosshair');
|
|
|
|
var point = seriesSvgPoint();
|
|
|
|
var horizontalLine = annotationLine();
|
|
|
|
var verticalLine = annotationLine().orient('vertical');
|
|
|
|
// The line annotations and point series used to render the crosshair are positioned using
|
|
// screen coordinates. This function constructs an identity scale for these components.
|
|
var xIdentity = d3Scale.scaleIdentity();
|
|
var yIdentity = d3Scale.scaleIdentity();
|
|
|
|
var multi = seriesSvgMulti().series([horizontalLine, verticalLine, point]).xScale(xIdentity).yScale(yIdentity).mapping(function (data) {
|
|
return [data];
|
|
});
|
|
|
|
var instance = function instance(selection$$1) {
|
|
|
|
if (selection$$1.selection) {
|
|
join.transition(selection$$1);
|
|
}
|
|
|
|
selection$$1.each(function (data, index, nodes) {
|
|
|
|
var g = join(d3Selection.select(nodes[index]), data);
|
|
|
|
// Prevent the crosshair triggering pointer events on itself
|
|
g.enter().style('pointer-events', 'none');
|
|
|
|
// Assign the identity scales an accurate range to allow the line annotations to cover
|
|
// the full width/height of the chart.
|
|
xIdentity.range(xScale.range());
|
|
yIdentity.range(yScale.range());
|
|
|
|
point.crossValue(x).mainValue(y);
|
|
|
|
horizontalLine.value(y);
|
|
|
|
verticalLine.value(x);
|
|
|
|
g.call(multi);
|
|
|
|
decorate(g, data, index);
|
|
});
|
|
};
|
|
|
|
// Don't use the xValue/yValue convention to indicate that these values are in screen
|
|
// not domain co-ordinates and are therefore not scaled.
|
|
instance.x = function () {
|
|
if (!arguments.length) {
|
|
return x;
|
|
}
|
|
x = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
instance.y = function () {
|
|
if (!arguments.length) {
|
|
return y;
|
|
}
|
|
y = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
instance.xScale = function () {
|
|
if (!arguments.length) {
|
|
return xScale;
|
|
}
|
|
xScale = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
instance.yScale = function () {
|
|
if (!arguments.length) {
|
|
return yScale;
|
|
}
|
|
yScale = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
instance.decorate = function () {
|
|
if (!arguments.length) {
|
|
return decorate;
|
|
}
|
|
decorate = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
|
|
var lineIncludes = include('label');
|
|
rebindAll(instance, horizontalLine, lineIncludes, prefix('y'));
|
|
rebindAll(instance, verticalLine, lineIncludes, prefix('x'));
|
|
|
|
return instance;
|
|
};
|
|
|
|
var annotationLine$1 = (function () {
|
|
|
|
var xScale = d3Scale.scaleIdentity();
|
|
var yScale = d3Scale.scaleIdentity();
|
|
var value = function value(d) {
|
|
return d;
|
|
};
|
|
var label = value;
|
|
var decorate = function decorate() {};
|
|
var orient = 'horizontal';
|
|
|
|
var lineData = d3Shape.line();
|
|
|
|
var instance = function instance(data) {
|
|
if (orient !== 'horizontal' && orient !== 'vertical') {
|
|
throw new Error('Invalid orientation');
|
|
}
|
|
var horizontal = orient === 'horizontal';
|
|
var context = lineData.context();
|
|
// the value scale which the annotation 'value' relates to, the crossScale
|
|
// is the other. Which is which depends on the orienation!
|
|
var crossScale = horizontal ? xScale : yScale;
|
|
var valueScale = horizontal ? yScale : xScale;
|
|
var crossDomain = crossScale.domain();
|
|
var textOffsetX = horizontal ? 9 : 0;
|
|
var textOffsetY = horizontal ? 0 : 9;
|
|
var textAlign = horizontal ? 'left' : 'center';
|
|
var textBaseline = horizontal ? 'middle' : 'hanging';
|
|
|
|
data.forEach(function (d, i) {
|
|
context.save();
|
|
context.beginPath();
|
|
context.strokeStyle = '#bbb';
|
|
context.fillStyle = '#000';
|
|
context.textAlign = textAlign;
|
|
context.textBaseline = textBaseline;
|
|
|
|
decorate(context, d, i);
|
|
|
|
// Draw line
|
|
lineData.context(context)(crossDomain.map(function (extent$$1) {
|
|
var point = [crossScale(extent$$1), valueScale(value(d))];
|
|
return horizontal ? point : point.reverse();
|
|
}));
|
|
|
|
// Draw label
|
|
var x = horizontal ? crossScale(crossDomain[1]) : valueScale(value(d));
|
|
var y = horizontal ? valueScale(value(d)) : crossScale(crossDomain[1]);
|
|
context.fillText(label(d), x + textOffsetX, y + textOffsetY);
|
|
|
|
context.fill();
|
|
context.stroke();
|
|
context.closePath();
|
|
context.restore();
|
|
});
|
|
};
|
|
|
|
instance.xScale = function () {
|
|
if (!arguments.length) {
|
|
return xScale;
|
|
}
|
|
xScale = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
instance.yScale = function () {
|
|
if (!arguments.length) {
|
|
return yScale;
|
|
}
|
|
yScale = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
instance.value = function () {
|
|
if (!arguments.length) {
|
|
return value;
|
|
}
|
|
value = constant(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return instance;
|
|
};
|
|
instance.label = function () {
|
|
if (!arguments.length) {
|
|
return label;
|
|
}
|
|
label = constant(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return instance;
|
|
};
|
|
instance.decorate = function () {
|
|
if (!arguments.length) {
|
|
return decorate;
|
|
}
|
|
decorate = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
instance.orient = function () {
|
|
if (!arguments.length) {
|
|
return orient;
|
|
}
|
|
orient = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
|
|
rebind(instance, lineData, 'context');
|
|
|
|
return instance;
|
|
});
|
|
|
|
var crosshair$1 = (function () {
|
|
|
|
var x = function x(d) {
|
|
return d.x;
|
|
};
|
|
var y = function y(d) {
|
|
return d.y;
|
|
};
|
|
var xScale = d3Scale.scaleIdentity();
|
|
var yScale = d3Scale.scaleIdentity();
|
|
|
|
var point = seriesCanvasPoint();
|
|
|
|
var horizontalLine = annotationLine$1();
|
|
|
|
var verticalLine = annotationLine$1().orient('vertical');
|
|
|
|
// The line annotations and point series used to render the crosshair are positioned using
|
|
// screen coordinates. This function constructs an identity scale for these components.
|
|
var xIdentity = d3Scale.scaleIdentity();
|
|
var yIdentity = d3Scale.scaleIdentity();
|
|
|
|
var multi = seriesCanvasMulti().series([horizontalLine, verticalLine, point]).xScale(xIdentity).yScale(yIdentity).mapping(function (data) {
|
|
return [data];
|
|
});
|
|
|
|
var instance = function instance(data) {
|
|
|
|
data.forEach(function (d) {
|
|
// Assign the identity scales an accurate range to allow the line annotations to cover
|
|
// the full width/height of the chart.
|
|
xIdentity.range(xScale.range());
|
|
yIdentity.range(yScale.range());
|
|
|
|
point.crossValue(x).mainValue(y);
|
|
|
|
horizontalLine.value(y);
|
|
|
|
verticalLine.value(x);
|
|
|
|
multi(d);
|
|
});
|
|
};
|
|
|
|
// Don't use the xValue/yValue convention to indicate that these values are in screen
|
|
// not domain co-ordinates and are therefore not scaled.
|
|
instance.x = function () {
|
|
if (!arguments.length) {
|
|
return x;
|
|
}
|
|
x = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
instance.y = function () {
|
|
if (!arguments.length) {
|
|
return y;
|
|
}
|
|
y = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
instance.xScale = function () {
|
|
if (!arguments.length) {
|
|
return xScale;
|
|
}
|
|
xScale = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
instance.yScale = function () {
|
|
if (!arguments.length) {
|
|
return yScale;
|
|
}
|
|
yScale = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
|
|
var lineIncludes = include('label', 'decorate');
|
|
rebindAll(instance, horizontalLine, lineIncludes, prefix('y'));
|
|
rebindAll(instance, verticalLine, lineIncludes, prefix('x'));
|
|
rebind(instance, point, 'decorate');
|
|
rebind(instance, multi, 'context');
|
|
|
|
return instance;
|
|
});
|
|
|
|
var ticks = (function () {
|
|
|
|
var scale = d3Scale.scaleIdentity();
|
|
var tickArguments = [10];
|
|
var tickValues = null;
|
|
|
|
var ticks = function ticks() {
|
|
var _scale;
|
|
|
|
return tickValues != null ? tickValues : scale.ticks ? (_scale = scale).ticks.apply(_scale, toConsumableArray(tickArguments)) : scale.domain();
|
|
};
|
|
|
|
ticks.scale = function () {
|
|
if (!arguments.length) {
|
|
return scale;
|
|
}
|
|
scale = arguments.length <= 0 ? undefined : arguments[0];
|
|
return ticks;
|
|
};
|
|
|
|
ticks.ticks = function () {
|
|
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
|
args[_key] = arguments[_key];
|
|
}
|
|
|
|
tickArguments = args;
|
|
return ticks;
|
|
};
|
|
|
|
ticks.tickArguments = function () {
|
|
if (!arguments.length) {
|
|
return tickArguments;
|
|
}
|
|
tickArguments = arguments.length <= 0 ? undefined : arguments[0];
|
|
return ticks;
|
|
};
|
|
|
|
ticks.tickValues = function () {
|
|
if (!arguments.length) {
|
|
return tickValues;
|
|
}
|
|
tickValues = arguments.length <= 0 ? undefined : arguments[0];
|
|
return ticks;
|
|
};
|
|
|
|
return ticks;
|
|
});
|
|
|
|
var identity$2 = function identity$2(d) {
|
|
return d;
|
|
};
|
|
|
|
var gridline = (function () {
|
|
|
|
var xDecorate = function xDecorate() {};
|
|
var yDecorate = function yDecorate() {};
|
|
|
|
var xTicks = ticks();
|
|
var yTicks = ticks();
|
|
var xJoin = dataJoin('line', 'gridline-y').key(identity$2);
|
|
var yJoin = dataJoin('line', 'gridline-x').key(identity$2);
|
|
|
|
var instance = function instance(selection$$1) {
|
|
|
|
if (selection$$1.selection) {
|
|
xJoin.transition(selection$$1);
|
|
yJoin.transition(selection$$1);
|
|
}
|
|
|
|
selection$$1.each(function (data, index, nodes) {
|
|
|
|
var element = nodes[index];
|
|
var container = d3Selection.select(nodes[index]);
|
|
|
|
var xScale = xTicks.scale();
|
|
var yScale = yTicks.scale();
|
|
|
|
// Stash a snapshot of the scale, and retrieve the old snapshot.
|
|
var xScaleOld = element.__x_scale__ || xScale;
|
|
element.__x_scale__ = xScale.copy();
|
|
|
|
var xData = xTicks();
|
|
var xLines = xJoin(container, xData);
|
|
|
|
xLines.enter().attr('x1', xScaleOld).attr('x2', xScaleOld).attr('y1', yScale.range()[0]).attr('y2', yScale.range()[1]);
|
|
|
|
xLines.attr('x1', xScale).attr('x2', xScale).attr('y1', yScale.range()[0]).attr('y2', yScale.range()[1]).attr('stroke', '#bbb');
|
|
|
|
xLines.exit().attr('x1', xScale).attr('x2', xScale);
|
|
|
|
xDecorate(xLines, xData, index);
|
|
|
|
// Stash a snapshot of the scale, and retrieve the old snapshot.
|
|
var yScaleOld = element.__y_scale__ || yScale;
|
|
element.__y_scale__ = yScale.copy();
|
|
|
|
var yData = yTicks();
|
|
var yLines = yJoin(container, yData);
|
|
|
|
yLines.enter().attr('y1', yScaleOld).attr('y2', yScaleOld).attr('x1', xScale.range()[0]).attr('x2', xScale.range()[1]);
|
|
|
|
yLines.attr('y1', yScale).attr('y2', yScale).attr('x1', xScale.range()[0]).attr('x2', xScale.range()[1]).attr('stroke', '#bbb');
|
|
|
|
yLines.exit().attr('y1', yScale).attr('y2', yScale);
|
|
|
|
yDecorate(yLines, yData, index);
|
|
});
|
|
};
|
|
|
|
instance.yDecorate = function () {
|
|
if (!arguments.length) {
|
|
return yDecorate;
|
|
}
|
|
yDecorate = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
|
|
instance.xDecorate = function () {
|
|
if (!arguments.length) {
|
|
return xDecorate;
|
|
}
|
|
xDecorate = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
|
|
rebindAll(instance, xJoin, includeMap({ 'key': 'xKey' }));
|
|
rebindAll(instance, yJoin, includeMap({ 'key': 'yKey' }));
|
|
|
|
rebindAll(instance, xTicks, prefix('x'));
|
|
rebindAll(instance, yTicks, prefix('y'));
|
|
|
|
return instance;
|
|
});
|
|
|
|
var gridline$1 = (function () {
|
|
|
|
var xDecorate = function xDecorate() {};
|
|
var yDecorate = function yDecorate() {};
|
|
|
|
var xTicks = ticks();
|
|
var yTicks = ticks();
|
|
|
|
var lineData = d3Shape.line();
|
|
|
|
var instance = function instance() {
|
|
|
|
var context = lineData.context();
|
|
var xScale = xTicks.scale();
|
|
var yScale = yTicks.scale();
|
|
|
|
xTicks().forEach(function (xTick, i) {
|
|
context.save();
|
|
context.beginPath();
|
|
context.strokeStyle = '#bbb';
|
|
context.fillStyle = 'transparent';
|
|
|
|
xDecorate(context, xTick, i);
|
|
lineData.context(context)(yScale.domain().map(function (d) {
|
|
return [xScale(xTick), yScale(d)];
|
|
}));
|
|
|
|
context.fill();
|
|
context.stroke();
|
|
context.closePath();
|
|
context.restore();
|
|
});
|
|
|
|
yTicks().forEach(function (yTick, i) {
|
|
context.save();
|
|
context.beginPath();
|
|
context.strokeStyle = '#bbb';
|
|
context.fillStyle = 'transparent';
|
|
|
|
yDecorate(context, yTick, i);
|
|
lineData.context(context)(xScale.domain().map(function (d) {
|
|
return [xScale(d), yScale(yTick)];
|
|
}));
|
|
|
|
context.fill();
|
|
context.stroke();
|
|
context.closePath();
|
|
context.restore();
|
|
});
|
|
};
|
|
|
|
instance.yDecorate = function () {
|
|
if (!arguments.length) {
|
|
return yDecorate;
|
|
}
|
|
yDecorate = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
|
|
instance.xDecorate = function () {
|
|
if (!arguments.length) {
|
|
return xDecorate;
|
|
}
|
|
xDecorate = arguments.length <= 0 ? undefined : arguments[0];
|
|
return instance;
|
|
};
|
|
|
|
rebindAll(instance, xTicks, prefix('x'));
|
|
rebindAll(instance, yTicks, prefix('y'));
|
|
rebind(instance, lineData, 'context');
|
|
|
|
return instance;
|
|
});
|
|
|
|
var identity$3 = function identity$3(d) {
|
|
return d;
|
|
};
|
|
|
|
var axisBase = function axisBase(orient, scale) {
|
|
var custom = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
|
|
|
|
var tickArguments = [10];
|
|
var tickValues = null;
|
|
var decorate = function decorate() {};
|
|
var tickFormat = null;
|
|
var tickSizeOuter = 6;
|
|
var tickSizeInner = 6;
|
|
var tickPadding = 3;
|
|
|
|
var svgDomainLine = d3Shape.line();
|
|
|
|
var dataJoin$$1 = dataJoin('g', 'tick').key(identity$3);
|
|
|
|
var domainPathDataJoin = dataJoin('path', 'domain');
|
|
|
|
var defaultLabelOffset = function defaultLabelOffset() {
|
|
return { offset: [0, tickSizeInner + tickPadding] };
|
|
};
|
|
var defaultTickPath = function defaultTickPath() {
|
|
return { path: [[0, 0], [0, tickSizeInner]] };
|
|
};
|
|
|
|
var labelOffset = custom.labelOffset || defaultLabelOffset;
|
|
var tickPath = custom.tickPath || defaultTickPath;
|
|
|
|
// returns a function that creates a translation based on
|
|
// the bound data
|
|
var containerTranslate = function containerTranslate(scale, trans) {
|
|
var offset = 0;
|
|
if (scale.bandwidth) {
|
|
offset = scale.bandwidth() / 2;
|
|
if (scale.round()) {
|
|
offset = Math.round(offset);
|
|
}
|
|
}
|
|
return function (d) {
|
|
return trans(scale(d) + offset, 0);
|
|
};
|
|
};
|
|
|
|
var translate = function translate(x, y) {
|
|
return isVertical() ? 'translate(' + y + ', ' + x + ')' : 'translate(' + x + ', ' + y + ')';
|
|
};
|
|
|
|
var pathTranspose = function pathTranspose(arr) {
|
|
return isVertical() ? arr.map(function (d) {
|
|
return [d[1], d[0]];
|
|
}) : arr;
|
|
};
|
|
|
|
var isVertical = function isVertical() {
|
|
return orient === 'left' || orient === 'right';
|
|
};
|
|
|
|
var tryApply = function tryApply(fn, args, defaultVal) {
|
|
return scale[fn] ? scale[fn].apply(scale, args) : defaultVal;
|
|
};
|
|
|
|
var axis = function axis(selection$$1) {
|
|
|
|
if (selection$$1.selection) {
|
|
dataJoin$$1.transition(selection$$1);
|
|
domainPathDataJoin.transition(selection$$1);
|
|
}
|
|
|
|
selection$$1.each(function (data, index, group) {
|
|
|
|
var element = group[index];
|
|
|
|
var container = d3Selection.select(element);
|
|
if (!element.__scale__) {
|
|
container.attr('fill', 'none').attr('font-size', 10).attr('font-family', 'sans-serif').attr('text-anchor', orient === 'right' ? 'start' : orient === 'left' ? 'end' : 'middle');
|
|
}
|
|
|
|
// Stash a snapshot of the new scale, and retrieve the old snapshot.
|
|
var scaleOld = element.__scale__ || scale;
|
|
element.__scale__ = scale.copy();
|
|
|
|
var ticksArray = tickValues == null ? tryApply('ticks', tickArguments, scale.domain()) : tickValues;
|
|
var tickFormatter = tickFormat == null ? tryApply('tickFormat', tickArguments, identity$3) : tickFormat;
|
|
var sign = orient === 'bottom' || orient === 'right' ? 1 : -1;
|
|
var withSign = function withSign(_ref) {
|
|
var _ref2 = slicedToArray(_ref, 2),
|
|
x = _ref2[0],
|
|
y = _ref2[1];
|
|
|
|
return [x, sign * y];
|
|
};
|
|
|
|
// add the domain line
|
|
var range$$1 = scale.range();
|
|
var domainPathData = pathTranspose([[range$$1[0], sign * tickSizeOuter], [range$$1[0], 0], [range$$1[1], 0], [range$$1[1], sign * tickSizeOuter]]);
|
|
|
|
var domainLine = domainPathDataJoin(container, [data]);
|
|
domainLine.attr('d', svgDomainLine(domainPathData)).attr('stroke', '#000');
|
|
|
|
var g = dataJoin$$1(container, ticksArray);
|
|
|
|
var labelOffsets = ticksArray.map(function (d, i) {
|
|
return labelOffset(d, i, ticksArray);
|
|
});
|
|
var tickPaths = ticksArray.map(function (d, i) {
|
|
return tickPath(d, i, ticksArray);
|
|
});
|
|
|
|
// enter
|
|
g.enter().attr('transform', containerTranslate(scaleOld, translate)).append('path').attr('stroke', '#000');
|
|
|
|
g.enter().append('text').attr('transform', function (d, i) {
|
|
return translate.apply(undefined, toConsumableArray(withSign(labelOffsets[i].offset)));
|
|
}).attr('fill', '#000');
|
|
|
|
// exit
|
|
g.exit().attr('transform', containerTranslate(scale, translate));
|
|
|
|
// update
|
|
g.select('path').attr('visibility', function (d, i) {
|
|
return tickPaths[i].hidden && 'hidden';
|
|
}).attr('d', function (d, i) {
|
|
return svgDomainLine(pathTranspose(tickPaths[i].path.map(withSign)));
|
|
});
|
|
|
|
g.select('text').attr('visibility', function (d, i) {
|
|
return labelOffsets[i].hidden && 'hidden';
|
|
}).attr('transform', function (d, i) {
|
|
return translate.apply(undefined, toConsumableArray(withSign(labelOffsets[i].offset)));
|
|
}).attr('dy', function () {
|
|
var offset = '0em';
|
|
if (isVertical()) {
|
|
offset = '0.32em';
|
|
} else if (orient === 'bottom') {
|
|
offset = '0.71em';
|
|
}
|
|
return offset;
|
|
}).text(tickFormatter);
|
|
|
|
g.attr('transform', containerTranslate(scale, translate));
|
|
|
|
decorate(g, data, index);
|
|
});
|
|
};
|
|
|
|
axis.tickFormat = function () {
|
|
if (!arguments.length) {
|
|
return tickFormat;
|
|
}
|
|
tickFormat = arguments.length <= 0 ? undefined : arguments[0];
|
|
return axis;
|
|
};
|
|
|
|
axis.tickSize = function () {
|
|
if (!arguments.length) {
|
|
return tickSizeInner;
|
|
}
|
|
tickSizeInner = tickSizeOuter = Number(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return axis;
|
|
};
|
|
|
|
axis.tickSizeInner = function () {
|
|
if (!arguments.length) {
|
|
return tickSizeInner;
|
|
}
|
|
tickSizeInner = Number(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return axis;
|
|
};
|
|
|
|
axis.tickSizeOuter = function () {
|
|
if (!arguments.length) {
|
|
return tickSizeOuter;
|
|
}
|
|
tickSizeOuter = Number(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return axis;
|
|
};
|
|
|
|
axis.tickPadding = function () {
|
|
if (!arguments.length) {
|
|
return tickPadding;
|
|
}
|
|
tickPadding = arguments.length <= 0 ? undefined : arguments[0];
|
|
return axis;
|
|
};
|
|
|
|
axis.decorate = function () {
|
|
if (!arguments.length) {
|
|
return decorate;
|
|
}
|
|
decorate = arguments.length <= 0 ? undefined : arguments[0];
|
|
return axis;
|
|
};
|
|
|
|
axis.scale = function () {
|
|
if (!arguments.length) {
|
|
return scale;
|
|
}
|
|
scale = arguments.length <= 0 ? undefined : arguments[0];
|
|
return axis;
|
|
};
|
|
|
|
axis.ticks = function () {
|
|
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
|
args[_key] = arguments[_key];
|
|
}
|
|
|
|
tickArguments = [].concat(args);
|
|
return axis;
|
|
};
|
|
|
|
axis.tickArguments = function () {
|
|
if (!arguments.length) {
|
|
return tickArguments.slice();
|
|
}
|
|
tickArguments = (arguments.length <= 0 ? undefined : arguments[0]) == null ? [] : [].concat(toConsumableArray(arguments.length <= 0 ? undefined : arguments[0]));
|
|
return axis;
|
|
};
|
|
|
|
axis.tickValues = function () {
|
|
if (!arguments.length) {
|
|
return tickValues.slice();
|
|
}
|
|
tickValues = (arguments.length <= 0 ? undefined : arguments[0]) == null ? [] : [].concat(toConsumableArray(arguments.length <= 0 ? undefined : arguments[0]));
|
|
return axis;
|
|
};
|
|
|
|
axis.orient = function () {
|
|
return orient;
|
|
};
|
|
|
|
return axis;
|
|
};
|
|
|
|
var axis = function axis(orient, scale) {
|
|
var tickCenterLabel = false;
|
|
|
|
var labelOffset = function labelOffset(tick, index, ticksArray) {
|
|
var x = 0;
|
|
var y = base.tickSizeInner() + base.tickPadding();
|
|
var hidden = false;
|
|
if (tickCenterLabel) {
|
|
var thisPosition = scale(tick);
|
|
var nextPosition = index < ticksArray.length - 1 ? scale(ticksArray[index + 1]) : scale.range()[1];
|
|
x = (nextPosition - thisPosition) / 2;
|
|
|
|
y = base.tickPadding();
|
|
hidden = index === ticksArray.length - 1 && thisPosition === nextPosition;
|
|
}
|
|
return { offset: [x, y], hidden: hidden };
|
|
};
|
|
|
|
var base = axisBase(orient, scale, { labelOffset: labelOffset });
|
|
|
|
var axis = function axis(selection$$1) {
|
|
return base(selection$$1);
|
|
};
|
|
|
|
axis.tickCenterLabel = function () {
|
|
if (!arguments.length) {
|
|
return tickCenterLabel;
|
|
}
|
|
tickCenterLabel = arguments.length <= 0 ? undefined : arguments[0];
|
|
return axis;
|
|
};
|
|
|
|
rebindAll(axis, base);
|
|
return axis;
|
|
};
|
|
|
|
var axisTop = function axisTop(scale) {
|
|
return axis('top', scale);
|
|
};
|
|
|
|
var axisBottom = function axisBottom(scale) {
|
|
return axis('bottom', scale);
|
|
};
|
|
|
|
var axisLeft = function axisLeft(scale) {
|
|
return axis('left', scale);
|
|
};
|
|
|
|
var axisRight = function axisRight(scale) {
|
|
return axis('right', scale);
|
|
};
|
|
|
|
var axisOrdinal = function axisOrdinal(orient, scale) {
|
|
var tickOffset = null;
|
|
|
|
var step = function step(tick, index, ticksArray) {
|
|
if (scale.step) {
|
|
// Use the scale step size
|
|
return scale.step();
|
|
}
|
|
var thisPosition = scale(tick);
|
|
if (index < ticksArray.length - 1) {
|
|
// Distance between ticks
|
|
return scale(ticksArray[index + 1]) / thisPosition;
|
|
} else {
|
|
// 2* distance to end
|
|
return (scale.range()[1] - thisPosition) * 2;
|
|
}
|
|
};
|
|
|
|
var tickPath = function tickPath(tick, index, ticksArray) {
|
|
var x = 0;
|
|
if (tickOffset) {
|
|
x = tickOffset(tick, index);
|
|
} else {
|
|
x = step(tick, index, ticksArray) / 2;
|
|
}
|
|
return {
|
|
path: [[x, 0], [x, base.tickSizeInner()]],
|
|
hidden: index === ticksArray.length - 1
|
|
};
|
|
};
|
|
var labelOffset = function labelOffset() {
|
|
// Don't include the tickSizeInner in the label positioning
|
|
return { offset: [0, base.tickPadding()] };
|
|
};
|
|
|
|
var base = axisBase(orient, scale, { labelOffset: labelOffset, tickPath: tickPath });
|
|
|
|
var axis = function axis(selection$$1) {
|
|
base(selection$$1);
|
|
};
|
|
|
|
axis.tickOffset = function () {
|
|
if (!arguments.length) {
|
|
return tickOffset;
|
|
}
|
|
tickOffset = arguments.length <= 0 ? undefined : arguments[0];
|
|
return axis;
|
|
};
|
|
|
|
rebindAll(axis, base);
|
|
return axis;
|
|
};
|
|
|
|
var axisOrdinalTop = function axisOrdinalTop(scale) {
|
|
return axisOrdinal('top', scale);
|
|
};
|
|
|
|
var axisOrdinalBottom = function axisOrdinalBottom(scale) {
|
|
return axisOrdinal('bottom', scale);
|
|
};
|
|
|
|
var axisOrdinalLeft = function axisOrdinalLeft(scale) {
|
|
return axisOrdinal('left', scale);
|
|
};
|
|
|
|
var axisOrdinalRight = function axisOrdinalRight(scale) {
|
|
return axisOrdinal('right', scale);
|
|
};
|
|
|
|
var measureLabels = (function (scale) {
|
|
var measure = function measure(selection$$1) {
|
|
var labels = scale['ticks'] ? scale.ticks() : scale.domain();
|
|
|
|
var tester = selection$$1.append('text');
|
|
var boundingBoxes = labels.map(function (l) {
|
|
return tester.text(l).node().getBBox();
|
|
});
|
|
var maxHeight = Math.max.apply(Math, toConsumableArray(boundingBoxes.map(function (b) {
|
|
return b.height;
|
|
})));
|
|
var maxWidth = Math.max.apply(Math, toConsumableArray(boundingBoxes.map(function (b) {
|
|
return b.width;
|
|
})));
|
|
tester.remove();
|
|
|
|
return {
|
|
maxHeight: maxHeight,
|
|
maxWidth: maxWidth,
|
|
labelCount: labels.length
|
|
};
|
|
};
|
|
|
|
return measure;
|
|
});
|
|
|
|
var axisLabelRotate = (function (adaptee) {
|
|
|
|
var labelRotate = 'auto';
|
|
var decorate = function decorate() {};
|
|
|
|
var isVertical = function isVertical() {
|
|
return adaptee.orient() === 'left' || adaptee.orient() === 'right';
|
|
};
|
|
var sign = function sign() {
|
|
return adaptee.orient() === 'top' || adaptee.orient() === 'left' ? -1 : 1;
|
|
};
|
|
|
|
var labelAnchor = function labelAnchor() {
|
|
switch (adaptee.orient()) {
|
|
case 'top':
|
|
case 'right':
|
|
return 'start';
|
|
default:
|
|
return 'end';
|
|
}
|
|
};
|
|
|
|
var calculateRotation = function calculateRotation(s) {
|
|
var _measureLabels = measureLabels(adaptee.scale())(s),
|
|
maxHeight = _measureLabels.maxHeight,
|
|
maxWidth = _measureLabels.maxWidth,
|
|
labelCount = _measureLabels.labelCount;
|
|
|
|
var measuredSize = labelCount * maxWidth;
|
|
|
|
// The more the overlap, the more we rotate
|
|
var rotate = void 0;
|
|
if (labelRotate === 'auto') {
|
|
var range$$1 = adaptee.scale().range()[1];
|
|
rotate = range$$1 < measuredSize ? 90 * Math.min(1, (measuredSize / range$$1 - 0.8) / 2) : 0;
|
|
} else {
|
|
rotate = labelRotate;
|
|
}
|
|
|
|
return {
|
|
rotate: isVertical() ? Math.floor(sign() * (90 - rotate)) : Math.floor(-rotate),
|
|
maxHeight: maxHeight,
|
|
maxWidth: maxWidth,
|
|
anchor: rotate ? labelAnchor() : 'middle'
|
|
};
|
|
};
|
|
|
|
var decorateRotation = function decorateRotation(sel) {
|
|
var _calculateRotation = calculateRotation(sel),
|
|
rotate = _calculateRotation.rotate,
|
|
maxHeight = _calculateRotation.maxHeight,
|
|
anchor = _calculateRotation.anchor;
|
|
|
|
var text = sel.select('text');
|
|
var existingTransform = text.attr('transform');
|
|
|
|
var offset = sign() * Math.floor(maxHeight / 2);
|
|
var offsetTransform = isVertical() ? 'translate(' + offset + ', 0)' : 'translate(0, ' + offset + ')';
|
|
|
|
text.style('text-anchor', anchor).attr('transform', existingTransform + ' ' + offsetTransform + ' rotate(' + rotate + ' 0 0)');
|
|
};
|
|
|
|
var axisLabelRotate = function axisLabelRotate(arg) {
|
|
adaptee(arg);
|
|
};
|
|
|
|
adaptee.decorate(function (s) {
|
|
decorateRotation(s);
|
|
decorate(s);
|
|
});
|
|
|
|
axisLabelRotate.decorate = function () {
|
|
if (!arguments.length) {
|
|
return decorate;
|
|
}
|
|
decorate = arguments.length <= 0 ? undefined : arguments[0];
|
|
return axisLabelRotate;
|
|
};
|
|
|
|
axisLabelRotate.labelRotate = function () {
|
|
if (!arguments.length) {
|
|
return labelRotate;
|
|
}
|
|
labelRotate = arguments.length <= 0 ? undefined : arguments[0];
|
|
return axisLabelRotate;
|
|
};
|
|
|
|
rebindAll(axisLabelRotate, adaptee, exclude('decorate'));
|
|
|
|
return axisLabelRotate;
|
|
});
|
|
|
|
var axisLabelOffset = (function (adaptee) {
|
|
|
|
var labelOffsetDepth = 'auto';
|
|
var decorate = function decorate() {};
|
|
|
|
var isVertical = function isVertical() {
|
|
return adaptee.orient() === 'left' || adaptee.orient() === 'right';
|
|
};
|
|
|
|
var sign = function sign() {
|
|
return adaptee.orient() === 'top' || adaptee.orient() === 'left' ? -1 : 1;
|
|
};
|
|
|
|
var decorateOffset = function decorateOffset(sel) {
|
|
var _measureLabels = measureLabels(adaptee.scale())(sel),
|
|
maxHeight = _measureLabels.maxHeight,
|
|
maxWidth = _measureLabels.maxWidth,
|
|
labelCount = _measureLabels.labelCount;
|
|
|
|
var range$$1 = adaptee.scale().range()[1];
|
|
|
|
var offsetLevels = labelOffsetDepth === 'auto' ? Math.floor((isVertical() ? maxHeight : maxWidth) * labelCount / range$$1) + 1 : labelOffsetDepth;
|
|
|
|
var text = sel.select('text');
|
|
var existingTransform = text.attr('transform');
|
|
|
|
var transform = function transform(i) {
|
|
return isVertical() ? 'translate(' + i % offsetLevels * maxWidth * sign() + ', 0)' : 'translate(0, ' + i % offsetLevels * maxHeight * sign() + ')';
|
|
};
|
|
|
|
text.attr('transform', function (_, i) {
|
|
return existingTransform + ' ' + transform(i);
|
|
});
|
|
};
|
|
|
|
var axisLabelOffset = function axisLabelOffset(arg) {
|
|
return adaptee(arg);
|
|
};
|
|
|
|
adaptee.decorate(function (s) {
|
|
decorateOffset(s);
|
|
decorate(s);
|
|
});
|
|
|
|
axisLabelOffset.decorate = function () {
|
|
if (!arguments.length) {
|
|
return decorate;
|
|
}
|
|
decorate = arguments.length <= 0 ? undefined : arguments[0];
|
|
return axisLabelOffset;
|
|
};
|
|
|
|
axisLabelOffset.labelOffsetDepth = function () {
|
|
if (!arguments.length) {
|
|
return labelOffsetDepth;
|
|
}
|
|
labelOffsetDepth = arguments.length <= 0 ? undefined : arguments[0];
|
|
return axisLabelOffset;
|
|
};
|
|
|
|
rebindAll(axisLabelOffset, adaptee, exclude('decorate'));
|
|
|
|
return axisLabelOffset;
|
|
});
|
|
|
|
var key = '__d3fc-elements__';
|
|
|
|
var get$2 = function get$2(element) {
|
|
return element[key] || {};
|
|
};
|
|
|
|
var set$2 = function set$2(element, data) {
|
|
return void (element[key] = data);
|
|
};
|
|
|
|
var clear = function clear(element) {
|
|
return delete element[key];
|
|
};
|
|
|
|
/* eslint-env browser */
|
|
|
|
var find = function find(element) {
|
|
return element.tagName === 'D3FC-GROUP' ? [element].concat(toConsumableArray(element.querySelectorAll('d3fc-canvas, d3fc-group, d3fc-svg'))) : [element];
|
|
};
|
|
|
|
var measure = function measure(element) {
|
|
var _data$get = get$2(element),
|
|
previousWidth = _data$get.width,
|
|
previousHeight = _data$get.height;
|
|
|
|
var pixelRatio = element.useDevicePixelRatio && global.devicePixelRatio != null ? global.devicePixelRatio : 1;
|
|
var width = element.clientWidth * pixelRatio;
|
|
var height = element.clientHeight * pixelRatio;
|
|
var resized = width !== previousWidth || height !== previousHeight;
|
|
set$2(element, { pixelRatio: pixelRatio, width: width, height: height, resized: resized });
|
|
};
|
|
|
|
if (typeof CustomEvent !== 'function') {
|
|
throw new Error('d3fc-element depends on CustomEvent. Make sure that you load a polyfill in older browsers. See README.');
|
|
}
|
|
|
|
var resize = function resize(element) {
|
|
var detail = get$2(element);
|
|
var event$$1 = new CustomEvent('measure', { detail: detail });
|
|
element.dispatchEvent(event$$1);
|
|
};
|
|
|
|
var draw = function draw(element) {
|
|
var detail = get$2(element);
|
|
var event$$1 = new CustomEvent('draw', { detail: detail });
|
|
element.dispatchEvent(event$$1);
|
|
};
|
|
|
|
var redraw = (function (elements) {
|
|
var allElements = elements.map(find).reduce(function (a, b) {
|
|
return a.concat(b);
|
|
});
|
|
allElements.forEach(measure);
|
|
allElements.forEach(resize);
|
|
allElements.forEach(draw);
|
|
});
|
|
|
|
/* eslint-env browser */
|
|
|
|
var getQueue = function getQueue(element) {
|
|
return get$2(element.ownerDocument).queue || [];
|
|
};
|
|
|
|
var setQueue = function setQueue(element, queue) {
|
|
var _data$get = get$2(element.ownerDocument),
|
|
requestId = _data$get.requestId;
|
|
|
|
if (requestId == null) {
|
|
requestId = requestAnimationFrame(function () {
|
|
// This seems like a weak way of retrieving the queue
|
|
// but I can't see an edge case at the minute...
|
|
var queue = getQueue(element);
|
|
redraw(queue);
|
|
clearQueue(element);
|
|
});
|
|
}
|
|
set$2(element.ownerDocument, { queue: queue, requestId: requestId });
|
|
};
|
|
|
|
var clearQueue = function clearQueue(element) {
|
|
return clear(element.ownerDocument);
|
|
};
|
|
|
|
var isDescendentOf = function isDescendentOf(element, ancestor) {
|
|
var node = element;
|
|
do {
|
|
if (node.parentNode === ancestor) {
|
|
return true;
|
|
}
|
|
// eslint-disable-next-line no-cond-assign
|
|
} while (node = node.parentNode);
|
|
return false;
|
|
};
|
|
|
|
var _requestRedraw = (function (element) {
|
|
var queue = getQueue(element);
|
|
var queueContainsElement = queue.indexOf(element) > -1;
|
|
if (queueContainsElement) {
|
|
return;
|
|
}
|
|
var queueContainsAncestor = queue.some(function (queuedElement) {
|
|
return isDescendentOf(element, queuedElement);
|
|
});
|
|
if (queueContainsAncestor) {
|
|
return;
|
|
}
|
|
var queueExcludingDescendents = queue.filter(function (queuedElement) {
|
|
return !isDescendentOf(queuedElement, element);
|
|
});
|
|
queueExcludingDescendents.push(element);
|
|
setQueue(element, queueExcludingDescendents);
|
|
});
|
|
|
|
function _CustomElement() {
|
|
return Reflect.construct(HTMLElement, [], this.__proto__.constructor);
|
|
}
|
|
|
|
|
|
Object.setPrototypeOf(_CustomElement.prototype, HTMLElement.prototype);
|
|
Object.setPrototypeOf(_CustomElement, HTMLElement);
|
|
/* eslint-env browser */
|
|
|
|
if (typeof HTMLElement !== 'function') {
|
|
throw new Error('d3fc-element depends on Custom Elements (v1). Make sure that you load a polyfill in older browsers. See README.');
|
|
}
|
|
|
|
var addMeasureListener = function addMeasureListener(element) {
|
|
if (element.__measureListener__ != null) {
|
|
return;
|
|
}
|
|
element.__measureListener__ = function (event$$1) {
|
|
return element.setMeasurements(event$$1.detail);
|
|
};
|
|
element.addEventListener('measure', element.__measureListener__);
|
|
};
|
|
|
|
var removeMeasureListener = function removeMeasureListener(element) {
|
|
if (element.__measureListener__ == null) {
|
|
return;
|
|
}
|
|
element.removeEventListener('measure', element.__measureListener__);
|
|
element.__measureListener__ = null;
|
|
};
|
|
|
|
var element = (function (createNode, applyMeasurements) {
|
|
return function (_CustomElement2) {
|
|
inherits(_class, _CustomElement2);
|
|
|
|
function _class() {
|
|
classCallCheck(this, _class);
|
|
return possibleConstructorReturn(this, (_class.__proto__ || Object.getPrototypeOf(_class)).apply(this, arguments));
|
|
}
|
|
|
|
createClass(_class, [{
|
|
key: 'attributeChangedCallback',
|
|
value: function attributeChangedCallback(name) {
|
|
switch (name) {
|
|
case 'use-device-pixel-ratio':
|
|
this.requestRedraw();
|
|
break;
|
|
}
|
|
}
|
|
}, {
|
|
key: 'connectedCallback',
|
|
value: function connectedCallback() {
|
|
if (this.childNodes.length === 0) {
|
|
this.appendChild(createNode());
|
|
}
|
|
addMeasureListener(this);
|
|
}
|
|
}, {
|
|
key: 'disconnectedCallback',
|
|
value: function disconnectedCallback() {
|
|
removeMeasureListener(this);
|
|
}
|
|
}, {
|
|
key: 'setMeasurements',
|
|
value: function setMeasurements(_ref) {
|
|
var width = _ref.width,
|
|
height = _ref.height;
|
|
|
|
var _childNodes = toArray(this.childNodes),
|
|
node = _childNodes[0],
|
|
other = _childNodes.slice(1);
|
|
|
|
if (other.length > 0) {
|
|
throw new Error('A d3fc-svg/canvas element must only contain a single svg/canvas element.');
|
|
}
|
|
applyMeasurements(node, { width: width, height: height });
|
|
}
|
|
}, {
|
|
key: 'requestRedraw',
|
|
value: function requestRedraw() {
|
|
_requestRedraw(this);
|
|
}
|
|
}, {
|
|
key: 'useDevicePixelRatio',
|
|
get: function get() {
|
|
return this.hasAttribute('use-device-pixel-ratio') && this.getAttribute('use-device-pixel-ratio') !== 'false';
|
|
},
|
|
set: function set(useDevicePixelRatio) {
|
|
if (useDevicePixelRatio && !this.useDevicePixelRatio) {
|
|
this.setAttribute('use-device-pixel-ratio', '');
|
|
} else if (!useDevicePixelRatio && this.useDevicePixelRatio) {
|
|
this.removeAttribute('use-device-pixel-ratio');
|
|
}
|
|
this.requestRedraw();
|
|
}
|
|
}], [{
|
|
key: 'observedAttributes',
|
|
get: function get() {
|
|
return ['use-device-pixel-ratio'];
|
|
}
|
|
}]);
|
|
return _class;
|
|
}(_CustomElement);
|
|
});
|
|
|
|
var Canvas = element(function () {
|
|
return document.createElement('canvas');
|
|
}, function (node, _ref) {
|
|
var width = _ref.width,
|
|
height = _ref.height;
|
|
|
|
node.setAttribute('width', width);
|
|
node.setAttribute('height', height);
|
|
});
|
|
|
|
function _CustomElement$1() {
|
|
return Reflect.construct(HTMLElement, [], this.__proto__.constructor);
|
|
}
|
|
|
|
|
|
Object.setPrototypeOf(_CustomElement$1.prototype, HTMLElement.prototype);
|
|
Object.setPrototypeOf(_CustomElement$1, HTMLElement);
|
|
/* eslint-env browser */
|
|
|
|
var updateAutoResize = function updateAutoResize(element) {
|
|
if (element.autoResize) {
|
|
addAutoResizeListener(element);
|
|
} else {
|
|
removeAutoResizeListener(element);
|
|
}
|
|
};
|
|
|
|
var addAutoResizeListener = function addAutoResizeListener(element) {
|
|
if (element.__autoResizeListener__ != null) {
|
|
return;
|
|
}
|
|
element.__autoResizeListener__ = function () {
|
|
return _requestRedraw(element);
|
|
};
|
|
addEventListener('resize', element.__autoResizeListener__);
|
|
};
|
|
|
|
var removeAutoResizeListener = function removeAutoResizeListener(element) {
|
|
if (element.__autoResizeListener__ == null) {
|
|
return;
|
|
}
|
|
removeEventListener('resize', element.__autoResizeListener__);
|
|
element.__autoResizeListener__ = null;
|
|
};
|
|
|
|
var _class = function (_CustomElement2) {
|
|
inherits(_class, _CustomElement2);
|
|
|
|
function _class() {
|
|
classCallCheck(this, _class);
|
|
return possibleConstructorReturn(this, (_class.__proto__ || Object.getPrototypeOf(_class)).apply(this, arguments));
|
|
}
|
|
|
|
createClass(_class, [{
|
|
key: 'connectedCallback',
|
|
value: function connectedCallback() {
|
|
updateAutoResize(this);
|
|
}
|
|
}, {
|
|
key: 'disconnectedCallback',
|
|
value: function disconnectedCallback() {
|
|
removeAutoResizeListener(this);
|
|
}
|
|
}, {
|
|
key: 'requestRedraw',
|
|
value: function requestRedraw() {
|
|
_requestRedraw(this);
|
|
}
|
|
}, {
|
|
key: 'attributeChangedCallback',
|
|
value: function attributeChangedCallback(name) {
|
|
switch (name) {
|
|
case 'auto-resize':
|
|
updateAutoResize(this);
|
|
break;
|
|
}
|
|
}
|
|
}, {
|
|
key: 'autoResize',
|
|
get: function get() {
|
|
return this.hasAttribute('auto-resize') && this.getAttribute('auto-resize') !== 'false';
|
|
},
|
|
set: function set(autoResize) {
|
|
if (autoResize && !this.autoResize) {
|
|
this.setAttribute('auto-resize', '');
|
|
} else if (!autoResize && this.autoResize) {
|
|
this.removeAttribute('auto-resize');
|
|
}
|
|
updateAutoResize(this);
|
|
}
|
|
}], [{
|
|
key: 'observedAttributes',
|
|
get: function get() {
|
|
return ['auto-resize'];
|
|
}
|
|
}]);
|
|
return _class;
|
|
}(_CustomElement$1);
|
|
|
|
var Svg = element(function () {
|
|
return document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
}, function (node, _ref) {
|
|
var width = _ref.width,
|
|
height = _ref.height;
|
|
|
|
node.setAttribute('viewBox', '0 0 ' + width + ' ' + height);
|
|
});
|
|
|
|
// Adapted from https://github.com/substack/insert-css
|
|
var css = 'd3fc-canvas,d3fc-svg{position:relative;display:block}d3fc-canvas>canvas,d3fc-svg>svg{position:absolute;height:100%;width:100%}d3fc-svg>svg{overflow:visible}';
|
|
|
|
var styleElement = document.createElement('style');
|
|
styleElement.setAttribute('type', 'text/css');
|
|
|
|
document.querySelector('head').appendChild(styleElement);
|
|
|
|
if (styleElement.styleSheet) {
|
|
styleElement.styleSheet.cssText += css;
|
|
} else {
|
|
styleElement.textContent += css;
|
|
}
|
|
|
|
/* globals customElements */
|
|
if ((typeof customElements === 'undefined' ? 'undefined' : _typeof(customElements)) !== 'object' || typeof customElements.define !== 'function') {
|
|
throw new Error('d3fc-element depends on Custom Elements (v1). Make sure that you load a polyfill in older browsers. See README.');
|
|
}
|
|
|
|
customElements.define('d3fc-canvas', Canvas);
|
|
customElements.define('d3fc-group', _class);
|
|
customElements.define('d3fc-svg', Svg);
|
|
|
|
var pointer = (function () {
|
|
var event$$1 = d3Dispatch.dispatch('point');
|
|
|
|
function mousemove() {
|
|
var point = d3Selection.mouse(this);
|
|
event$$1.call('point', this, [{ x: point[0], y: point[1] }]);
|
|
}
|
|
|
|
function mouseleave() {
|
|
void event$$1.call('point', this, []);
|
|
}
|
|
|
|
var instance = function instance(selection$$1) {
|
|
selection$$1.on('mouseenter.pointer', mousemove).on('mousemove.pointer', mousemove).on('mouseleave.pointer', mouseleave);
|
|
};
|
|
|
|
rebind(instance, event$$1, 'on');
|
|
|
|
return instance;
|
|
});
|
|
|
|
var group = (function () {
|
|
|
|
var key = '';
|
|
var orient = 'vertical';
|
|
// D3 CSV returns all values as strings, this converts them to numbers
|
|
// by default.
|
|
var value = function value(row, column) {
|
|
return Number(row[column]);
|
|
};
|
|
|
|
var verticalgroup = function verticalgroup(data) {
|
|
return Object.keys(data[0]).filter(function (k) {
|
|
return k !== key;
|
|
}).map(function (k) {
|
|
var values = data.filter(function (row) {
|
|
return row[k];
|
|
}).map(function (row) {
|
|
var cell = [row[key], value(row, k)];
|
|
cell.data = row;
|
|
return cell;
|
|
});
|
|
values.key = k;
|
|
return values;
|
|
});
|
|
};
|
|
|
|
var horizontalgroup = function horizontalgroup(data) {
|
|
return data.map(function (row) {
|
|
var values = Object.keys(row).filter(function (d) {
|
|
return d !== key;
|
|
}).map(function (k) {
|
|
var cell = [k, value(row, k)];
|
|
cell.data = row;
|
|
return cell;
|
|
});
|
|
values.key = row[key];
|
|
return values;
|
|
});
|
|
};
|
|
|
|
var group = function group(data) {
|
|
return orient === 'vertical' ? verticalgroup(data) : horizontalgroup(data);
|
|
};
|
|
|
|
group.key = function () {
|
|
if (!arguments.length) {
|
|
return key;
|
|
}
|
|
key = arguments.length <= 0 ? undefined : arguments[0];
|
|
return group;
|
|
};
|
|
|
|
group.value = function () {
|
|
if (!arguments.length) {
|
|
return value;
|
|
}
|
|
value = arguments.length <= 0 ? undefined : arguments[0];
|
|
return group;
|
|
};
|
|
|
|
group.orient = function () {
|
|
if (!arguments.length) {
|
|
return orient;
|
|
}
|
|
orient = arguments.length <= 0 ? undefined : arguments[0];
|
|
return group;
|
|
};
|
|
|
|
return group;
|
|
});
|
|
|
|
var store = (function () {
|
|
for (var _len = arguments.length, names = Array(_len), _key = 0; _key < _len; _key++) {
|
|
names[_key] = arguments[_key];
|
|
}
|
|
|
|
var data = {};
|
|
|
|
var store = function store(target) {
|
|
var _iteratorNormalCompletion = true;
|
|
var _didIteratorError = false;
|
|
var _iteratorError = undefined;
|
|
|
|
try {
|
|
for (var _iterator = Object.keys(data)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
var key = _step.value;
|
|
|
|
target[key](data[key]);
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError = true;
|
|
_iteratorError = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion && _iterator.return) {
|
|
_iterator.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError) {
|
|
throw _iteratorError;
|
|
}
|
|
}
|
|
}
|
|
|
|
return target;
|
|
};
|
|
|
|
var _loop = function _loop(name) {
|
|
store[name] = function () {
|
|
if (!arguments.length) {
|
|
return data[name];
|
|
}
|
|
data[name] = arguments.length <= 0 ? undefined : arguments[0];
|
|
return store;
|
|
};
|
|
};
|
|
|
|
var _iteratorNormalCompletion2 = true;
|
|
var _didIteratorError2 = false;
|
|
var _iteratorError2 = undefined;
|
|
|
|
try {
|
|
for (var _iterator2 = names[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
|
|
var name = _step2.value;
|
|
|
|
_loop(name);
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError2 = true;
|
|
_iteratorError2 = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion2 && _iterator2.return) {
|
|
_iterator2.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError2) {
|
|
throw _iteratorError2;
|
|
}
|
|
}
|
|
}
|
|
|
|
return store;
|
|
});
|
|
|
|
// Adapted from https://github.com/substack/insert-css
|
|
var css$1 = 'd3fc-group.cartesian-chart{width:100%;height:100%;overflow:hidden;display:grid;display:-ms-grid;grid-template-columns:minmax(1em,max-content) auto 1fr auto minmax(1em,max-content);-ms-grid-columns:minmax(1em,max-content) auto 1fr auto minmax(1em,max-content);grid-template-rows:minmax(1em,max-content) auto 1fr auto minmax(1em,max-content);-ms-grid-rows:minmax(1em,max-content) auto 1fr auto minmax(1em,max-content);}\nd3fc-group.cartesian-chart>.top-label{align-self:center;-ms-grid-column-align:center;justify-self:center;-ms-grid-row-align:center;grid-column:3;-ms-grid-column:3;-ms-grid-row:1;-ms-grid-row:1;}\nd3fc-group.cartesian-chart>.top-axis{height:2em;grid-column:3;-ms-grid-column:3;grid-row:2;-ms-grid-row:2;}\nd3fc-group.cartesian-chart>.left-label{align-self:center;-ms-grid-column-align:center;justify-self:center;-ms-grid-row-align:center;grid-column:1;-ms-grid-column:1;grid-row:3;-ms-grid-row:3;}\nd3fc-group.cartesian-chart>.left-axis{width:3em;grid-column:2;-ms-grid-column:2;grid-row:3;-ms-grid-row:3;}\nd3fc-group.cartesian-chart>.plot-area{overflow:hidden;grid-column:3;-ms-grid-column:3;grid-row:3;-ms-grid-row:3;}\nd3fc-group.cartesian-chart>.right-axis{width:3em;grid-column:4;-ms-grid-column:4;grid-row:3;-ms-grid-row:3;}\nd3fc-group.cartesian-chart>.right-label{align-self:center;-ms-grid-column-align:center;justify-self:center;-ms-grid-row-align:center;grid-column:5;-ms-grid-column:5;grid-row:3;-ms-grid-row:3;}\nd3fc-group.cartesian-chart>.bottom-axis{height:2em;grid-column:3;-ms-grid-column:3;grid-row:4;-ms-grid-row:4;}\nd3fc-group.cartesian-chart>.bottom-label{align-self:center;-ms-grid-column-align:center;justify-self:center;-ms-grid-row-align:center;grid-column:3;-ms-grid-column:3;grid-row:5;-ms-grid-row:5;}';
|
|
|
|
var styleElement$1 = document.createElement('style');
|
|
styleElement$1.setAttribute('type', 'text/css');
|
|
|
|
document.querySelector('head').appendChild(styleElement$1);
|
|
|
|
if (styleElement$1.styleSheet) {
|
|
styleElement$1.styleSheet.cssText += css$1;
|
|
} else {
|
|
styleElement$1.textContent += css$1;
|
|
}
|
|
|
|
var functor$6 = function functor$6(v) {
|
|
return typeof v === 'function' ? v : function () {
|
|
return v;
|
|
};
|
|
};
|
|
|
|
var cartesianChart = (function () {
|
|
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
|
args[_key] = arguments[_key];
|
|
}
|
|
|
|
var _getArguments = getArguments.apply(undefined, args),
|
|
xScale = _getArguments.xScale,
|
|
yScale = _getArguments.yScale,
|
|
xAxis = _getArguments.xAxis,
|
|
yAxis = _getArguments.yAxis;
|
|
|
|
var xLabel = functor$6('');
|
|
var yLabel = functor$6('');
|
|
var xAxisHeight = functor$6(null);
|
|
var yAxisWidth = functor$6(null);
|
|
var yOrient = functor$6('right');
|
|
var xOrient = functor$6('bottom');
|
|
var canvasPlotArea = seriesCanvasMulti();
|
|
var svgPlotArea = seriesSvgMulti();
|
|
var xAxisStore = store('tickFormat', 'ticks', 'tickArguments', 'tickSize', 'tickSizeInner', 'tickSizeOuter', 'tickValues', 'tickPadding', 'tickCenterLabel');
|
|
var xDecorate = function xDecorate() {};
|
|
var yAxisStore = store('tickFormat', 'ticks', 'tickArguments', 'tickSize', 'tickSizeInner', 'tickSizeOuter', 'tickValues', 'tickPadding', 'tickCenterLabel');
|
|
var yDecorate = function yDecorate() {};
|
|
var decorate = function decorate() {};
|
|
|
|
var containerDataJoin = dataJoin('d3fc-group', 'cartesian-chart');
|
|
var xAxisDataJoin = dataJoin('d3fc-svg', 'x-axis').key(function (d) {
|
|
return d;
|
|
});
|
|
var yAxisDataJoin = dataJoin('d3fc-svg', 'y-axis').key(function (d) {
|
|
return d;
|
|
});
|
|
var xLabelDataJoin = dataJoin('div', 'x-label').key(function (d) {
|
|
return d;
|
|
});
|
|
var yLabelDataJoin = dataJoin('div', 'y-label').key(function (d) {
|
|
return d;
|
|
});
|
|
|
|
var propagateTransition = function propagateTransition(maybeTransition) {
|
|
return function (selection$$1) {
|
|
return maybeTransition.selection ? selection$$1.transition(maybeTransition) : selection$$1;
|
|
};
|
|
};
|
|
|
|
var cartesian = function cartesian(selection$$1) {
|
|
|
|
var transitionPropagator = propagateTransition(selection$$1);
|
|
|
|
selection$$1.each(function (data, index, group) {
|
|
var container = containerDataJoin(d3Selection.select(group[index]), [data]);
|
|
|
|
container.enter().attr('auto-resize', '').html('<d3fc-svg class="plot-area"></d3fc-svg>' + '<d3fc-canvas class="plot-area"></d3fc-canvas>');
|
|
|
|
xLabelDataJoin(container, [xOrient(data)]).attr('class', function (d) {
|
|
return 'x-label ' + d + '-label';
|
|
}).text(xLabel(data));
|
|
|
|
yLabelDataJoin(container, [yOrient(data)]).attr('class', function (d) {
|
|
return 'y-label ' + d + '-label';
|
|
}).text(yLabel(data));
|
|
|
|
xAxisDataJoin(container, [xOrient(data)]).attr('class', function (d) {
|
|
return 'x-axis ' + d + '-axis';
|
|
}).style('height', xAxisHeight(data)).on('measure', function (d, i, nodes) {
|
|
var _event$detail = d3Selection.event.detail,
|
|
width = _event$detail.width,
|
|
height = _event$detail.height;
|
|
|
|
if (d === 'top') {
|
|
d3Selection.select(nodes[i]).select('svg').attr('viewBox', '0 ' + -height + ' ' + width + ' ' + height);
|
|
}
|
|
xScale.range([0, width]);
|
|
}).on('draw', function (d, i, nodes) {
|
|
var xAxisComponent = d === 'top' ? xAxis.top(xScale) : xAxis.bottom(xScale);
|
|
xAxisComponent.decorate(xDecorate);
|
|
transitionPropagator(d3Selection.select(nodes[i])).select('svg').call(xAxisStore(xAxisComponent));
|
|
});
|
|
|
|
yAxisDataJoin(container, [yOrient(data)]).attr('class', function (d) {
|
|
return 'y-axis ' + d + '-axis';
|
|
}).style('width', yAxisWidth(data)).on('measure', function (d, i, nodes) {
|
|
var _event$detail2 = d3Selection.event.detail,
|
|
width = _event$detail2.width,
|
|
height = _event$detail2.height;
|
|
|
|
if (d === 'left') {
|
|
d3Selection.select(nodes[i]).select('svg').attr('viewBox', -width + ' 0 ' + width + ' ' + height);
|
|
}
|
|
yScale.range([height, 0]);
|
|
}).on('draw', function (d, i, nodes) {
|
|
var yAxisComponent = d === 'left' ? yAxis.left(yScale) : yAxis.right(yScale);
|
|
yAxisComponent.decorate(yDecorate);
|
|
transitionPropagator(d3Selection.select(nodes[i])).select('svg').call(yAxisStore(yAxisComponent));
|
|
});
|
|
|
|
container.select('d3fc-canvas.plot-area').on('draw', function (d, i, nodes) {
|
|
var canvas = d3Selection.select(nodes[i]).select('canvas').node();
|
|
canvasPlotArea.context(canvas.getContext('2d')).xScale(xScale).yScale(yScale);
|
|
canvasPlotArea(d);
|
|
});
|
|
|
|
container.select('d3fc-svg.plot-area').on('draw', function (d, i, nodes) {
|
|
svgPlotArea.xScale(xScale).yScale(yScale);
|
|
transitionPropagator(d3Selection.select(nodes[i])).select('svg').call(svgPlotArea);
|
|
});
|
|
|
|
container.each(function (d, i, nodes) {
|
|
return nodes[i].requestRedraw();
|
|
});
|
|
|
|
decorate(container, data, index);
|
|
});
|
|
};
|
|
|
|
var scaleExclusions = exclude(/range\w*/, // the scale range is set via the component layout
|
|
/tickFormat/ // use axis.tickFormat instead (only present on linear scales)
|
|
);
|
|
rebindAll(cartesian, xScale, scaleExclusions, prefix('x'));
|
|
rebindAll(cartesian, yScale, scaleExclusions, prefix('y'));
|
|
rebindAll(cartesian, xAxisStore, prefix('x'));
|
|
rebindAll(cartesian, yAxisStore, prefix('y'));
|
|
|
|
cartesian.xOrient = function () {
|
|
if (!arguments.length) {
|
|
return xOrient;
|
|
}
|
|
xOrient = functor$6(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return cartesian;
|
|
};
|
|
cartesian.yOrient = function () {
|
|
if (!arguments.length) {
|
|
return yOrient;
|
|
}
|
|
yOrient = functor$6(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return cartesian;
|
|
};
|
|
cartesian.xDecorate = function () {
|
|
if (!arguments.length) {
|
|
return xDecorate;
|
|
}
|
|
xDecorate = arguments.length <= 0 ? undefined : arguments[0];
|
|
return cartesian;
|
|
};
|
|
cartesian.yDecorate = function () {
|
|
if (!arguments.length) {
|
|
return yDecorate;
|
|
}
|
|
yDecorate = arguments.length <= 0 ? undefined : arguments[0];
|
|
return cartesian;
|
|
};
|
|
cartesian.xLabel = function () {
|
|
if (!arguments.length) {
|
|
return xLabel;
|
|
}
|
|
xLabel = functor$6(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return cartesian;
|
|
};
|
|
cartesian.yLabel = function () {
|
|
if (!arguments.length) {
|
|
return yLabel;
|
|
}
|
|
yLabel = functor$6(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return cartesian;
|
|
};
|
|
cartesian.xAxisHeight = function () {
|
|
if (!arguments.length) {
|
|
return xAxisHeight;
|
|
}
|
|
xAxisHeight = functor$6(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return cartesian;
|
|
};
|
|
cartesian.yAxisWidth = function () {
|
|
if (!arguments.length) {
|
|
return yAxisWidth;
|
|
}
|
|
yAxisWidth = functor$6(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return cartesian;
|
|
};
|
|
cartesian.canvasPlotArea = function () {
|
|
if (!arguments.length) {
|
|
return canvasPlotArea;
|
|
}
|
|
canvasPlotArea = arguments.length <= 0 ? undefined : arguments[0];
|
|
return cartesian;
|
|
};
|
|
cartesian.svgPlotArea = function () {
|
|
if (!arguments.length) {
|
|
return svgPlotArea;
|
|
}
|
|
svgPlotArea = arguments.length <= 0 ? undefined : arguments[0];
|
|
return cartesian;
|
|
};
|
|
cartesian.decorate = function () {
|
|
if (!arguments.length) {
|
|
return decorate;
|
|
}
|
|
decorate = arguments.length <= 0 ? undefined : arguments[0];
|
|
return cartesian;
|
|
};
|
|
|
|
return cartesian;
|
|
});
|
|
|
|
var getArguments = function getArguments() {
|
|
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
args[_key2] = arguments[_key2];
|
|
}
|
|
|
|
var defaultSettings = {
|
|
xScale: d3Scale.scaleIdentity(),
|
|
yScale: d3Scale.scaleIdentity(),
|
|
xAxis: { bottom: axisBottom, top: axisTop },
|
|
yAxis: { right: axisRight, left: axisLeft }
|
|
};
|
|
|
|
if (args.length === 1 && !args[0].domain && !args[0].range) {
|
|
// Settings object
|
|
return Object.assign(defaultSettings, args[0]);
|
|
}
|
|
|
|
// xScale/yScale parameters
|
|
return Object.assign(defaultSettings, {
|
|
xScale: args[0] || defaultSettings.xScale,
|
|
yScale: args[1] || defaultSettings.yScale
|
|
});
|
|
};
|
|
|
|
var functor$5 = function functor$5(v) {
|
|
return typeof v === 'function' ? v : function () {
|
|
return v;
|
|
};
|
|
};
|
|
|
|
var cartesianBase = (function (setPlotArea, defaultPlotArea) {
|
|
return function () {
|
|
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
|
args[_key] = arguments[_key];
|
|
}
|
|
|
|
var chartLabel = functor$5('');
|
|
var yLabel = functor$5('');
|
|
var plotArea = defaultPlotArea;
|
|
var decorate = function decorate() {};
|
|
|
|
var cartesian = cartesianChart.apply(undefined, args);
|
|
|
|
var cartesianBase = function cartesianBase(selection$$1) {
|
|
setPlotArea(cartesian, plotArea);
|
|
|
|
cartesian.decorate(function (container, data, index) {
|
|
container.enter().select('.x-label').style('height', '1em').style('line-height', '1em');
|
|
|
|
var yOrientValue = cartesian.yOrient()(data);
|
|
|
|
container.enter().append('div').attr('class', 'y-label-container').style('grid-column', yOrientValue === 'left' ? 1 : 5).style('-ms-grid-column', yOrientValue === 'left' ? 1 : 5).style('grid-row', 3).style('-ms-grid-row', 3).style('width', '1em').style('display', 'flex').style('align-items', 'center').style('justify-content', 'center').append('div').attr('class', 'y-label').style('transform', 'rotate(-90deg)');
|
|
|
|
container.select('.y-label-container>.y-label').text(yLabel);
|
|
|
|
container.select('.top-label').style('margin-top', '2em');
|
|
|
|
container.enter().append('div').attr('class', 'chart-label').style('grid-column', 3).style('-ms-grid-column', 3).style('grid-row', 1).style('-ms-grid-row', 1).style('height', '2em').style('line-height', '2em').style('text-align', 'center');
|
|
|
|
container.select('.chart-label').text(chartLabel(data));
|
|
|
|
decorate(container, data, index);
|
|
});
|
|
|
|
selection$$1.call(cartesian);
|
|
};
|
|
|
|
rebindAll(cartesianBase, cartesian, include(/^x/, /^y/));
|
|
|
|
cartesianBase.chartLabel = function () {
|
|
if (!arguments.length) {
|
|
return chartLabel;
|
|
}
|
|
chartLabel = functor$5(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return cartesianBase;
|
|
};
|
|
cartesianBase.yLabel = function () {
|
|
if (!arguments.length) {
|
|
return yLabel;
|
|
}
|
|
yLabel = functor$5(arguments.length <= 0 ? undefined : arguments[0]);
|
|
return cartesianBase;
|
|
};
|
|
cartesianBase.plotArea = function () {
|
|
if (!arguments.length) {
|
|
return plotArea;
|
|
}
|
|
plotArea = arguments.length <= 0 ? undefined : arguments[0];
|
|
return cartesianBase;
|
|
};
|
|
cartesianBase.decorate = function () {
|
|
if (!arguments.length) {
|
|
return decorate;
|
|
}
|
|
decorate = arguments.length <= 0 ? undefined : arguments[0];
|
|
return cartesianBase;
|
|
};
|
|
|
|
return cartesianBase;
|
|
};
|
|
});
|
|
|
|
var cartesian = cartesianBase(function (cartesian, plotArea) {
|
|
return cartesian.svgPlotArea(plotArea);
|
|
}, seriesSvgLine);
|
|
|
|
var cartesian$1 = cartesianBase(function (cartesian, plotArea) {
|
|
return cartesian.canvasPlotArea(plotArea);
|
|
}, seriesCanvasLine);
|
|
|
|
var brushForOrient = function brushForOrient(orient) {
|
|
switch (orient) {
|
|
case 'x':
|
|
return d3Brush.brushX();
|
|
case 'y':
|
|
return d3Brush.brushY();
|
|
case 'xy':
|
|
return d3Brush.brush();
|
|
}
|
|
};
|
|
|
|
var invertRange = function invertRange(range$$1) {
|
|
return [range$$1[1], range$$1[0]];
|
|
};
|
|
|
|
var brushBase = function brushBase(orient) {
|
|
|
|
var brush$$1 = brushForOrient(orient);
|
|
var eventDispatch = d3Dispatch.dispatch('brush', 'start', 'end');
|
|
var xScale = d3Scale.scaleIdentity();
|
|
var yScale = d3Scale.scaleIdentity();
|
|
|
|
var innerJoin = dataJoin('g', 'brush');
|
|
|
|
var mapSelection = function mapSelection(selection$$1, xMapping, yMapping) {
|
|
switch (orient) {
|
|
case 'x':
|
|
return selection$$1.map(xMapping);
|
|
case 'y':
|
|
return selection$$1.map(yMapping);
|
|
case 'xy':
|
|
return [[xMapping(selection$$1[0][0]), yMapping(selection$$1[0][1])], [xMapping(selection$$1[1][0]), yMapping(selection$$1[1][1])]];
|
|
}
|
|
};
|
|
|
|
var percentToSelection = function percentToSelection(percent) {
|
|
return mapSelection(percent, d3Scale.scaleLinear().domain(xScale.range()).invert, d3Scale.scaleLinear().domain(invertRange(yScale.range())).invert);
|
|
};
|
|
|
|
var selectionToPercent = function selectionToPercent(selection$$1) {
|
|
return mapSelection(selection$$1, d3Scale.scaleLinear().domain(xScale.range()), d3Scale.scaleLinear().domain(invertRange(yScale.range())));
|
|
};
|
|
|
|
var updateXDomain = function updateXDomain(selection$$1) {
|
|
var f = d3Scale.scaleLinear().domain(xScale.domain());
|
|
if (orient === 'x') {
|
|
return selection$$1.map(f.invert);
|
|
} else if (orient === 'xy') {
|
|
return [f.invert(selection$$1[0][0]), f.invert(selection$$1[1][0])];
|
|
}
|
|
};
|
|
|
|
var updateYDomain = function updateYDomain(selection$$1) {
|
|
var g = d3Scale.scaleLinear().domain(invertRange(yScale.domain()));
|
|
if (orient === 'y') {
|
|
return [selection$$1[1], selection$$1[0]].map(g.invert);
|
|
} else if (orient === 'xy') {
|
|
return [g.invert(selection$$1[1][1]), g.invert(selection$$1[0][1])];
|
|
}
|
|
};
|
|
|
|
var transformEvent = function transformEvent(event$$1) {
|
|
// The render function calls brush.move, which triggers, start, brush and end events. We don't
|
|
// really want those events so suppress them.
|
|
if (event$$1.sourceEvent && event$$1.sourceEvent.type === 'draw') return;
|
|
|
|
if (event$$1.selection) {
|
|
var mappedSelection = selectionToPercent(event$$1.selection);
|
|
eventDispatch.call(event$$1.type, {}, {
|
|
selection: mappedSelection,
|
|
xDomain: updateXDomain(mappedSelection),
|
|
yDomain: updateYDomain(mappedSelection)
|
|
});
|
|
} else {
|
|
eventDispatch.call(event$$1.type, {}, {});
|
|
}
|
|
};
|
|
|
|
var base = function base(selection$$1) {
|
|
selection$$1.each(function (data, index, group) {
|
|
|
|
// set the extent
|
|
brush$$1.extent([[xScale.range()[0], yScale.range()[1]], [xScale.range()[1], yScale.range()[0]]]);
|
|
|
|
// forwards events
|
|
brush$$1.on('end', function () {
|
|
return transformEvent(d3Selection.event);
|
|
}).on('brush', function () {
|
|
return transformEvent(d3Selection.event);
|
|
}).on('start', function () {
|
|
return transformEvent(d3Selection.event);
|
|
});
|
|
|
|
// render
|
|
var container = innerJoin(d3Selection.select(group[index]), [data]);
|
|
container.call(brush$$1).call(brush$$1.move, data ? percentToSelection(data) : null);
|
|
});
|
|
};
|
|
|
|
base.xScale = function () {
|
|
if (!arguments.length) {
|
|
return xScale;
|
|
}
|
|
xScale = arguments.length <= 0 ? undefined : arguments[0];
|
|
return base;
|
|
};
|
|
|
|
base.yScale = function () {
|
|
if (!arguments.length) {
|
|
return yScale;
|
|
}
|
|
yScale = arguments.length <= 0 ? undefined : arguments[0];
|
|
return base;
|
|
};
|
|
|
|
rebind(base, eventDispatch, 'on');
|
|
rebind(base, brush$$1, 'filter', 'handleSize');
|
|
|
|
return base;
|
|
};
|
|
|
|
var brushX$1 = function brushX$1() {
|
|
return brushBase('x');
|
|
};
|
|
|
|
var brushY$1 = function brushY$1() {
|
|
return brushBase('y');
|
|
};
|
|
|
|
var brush$1 = function brush$1() {
|
|
return brushBase('xy');
|
|
};
|
|
|
|
exports.indicatorBollingerBands = bollingerBands;
|
|
exports.indicatorExponentialMovingAverage = exponentialMovingAverage;
|
|
exports.indicatorMacd = macd;
|
|
exports.indicatorRelativeStrengthIndex = relativeStrengthIndex;
|
|
exports.indicatorStochasticOscillator = stochasticOscillator;
|
|
exports.indicatorForceIndex = forceIndex;
|
|
exports.indicatorEnvelope = envelope;
|
|
exports.indicatorElderRay = elderRay;
|
|
exports.indicatorMovingAverage = movingAverage;
|
|
exports.scaleDiscontinuous = discontinuous;
|
|
exports.discontinuitySkipWeekends = skipWeekends;
|
|
exports.discontinuityIdentity = identity$1;
|
|
exports.discontinuityRange = provider;
|
|
exports.extentLinear = linearExtent;
|
|
exports.extentTime = time;
|
|
exports.extentDate = time;
|
|
exports.randomFinancial = financial;
|
|
exports.randomGeometricBrownianMotion = geometricBrownianMotion;
|
|
exports.randomSkipWeekends = skipWeekends$1;
|
|
exports.feedGdax = gdax;
|
|
exports.bucket = bucket;
|
|
exports.largestTriangleOneBucket = largestTriangleOneBucket;
|
|
exports.largestTriangleThreeBucket = largestTriangleThreeBucket;
|
|
exports.modeMedian = modeMedian;
|
|
exports.rebind = rebind;
|
|
exports.rebindAll = rebindAll;
|
|
exports.exclude = exclude;
|
|
exports.include = include;
|
|
exports.includeMap = includeMap;
|
|
exports.prefix = prefix;
|
|
exports.shapeOhlc = shapeOhlc;
|
|
exports.shapeBar = shapeBar;
|
|
exports.shapeCandlestick = shapeCandlestick;
|
|
exports.shapeBoxPlot = shapeBoxPlot;
|
|
exports.shapeErrorBar = shapeErrorBar;
|
|
exports.layoutLabel = label;
|
|
exports.layoutTextLabel = textLabel;
|
|
exports.layoutGreedy = greedy;
|
|
exports.layoutAnnealing = annealing;
|
|
exports.layoutRemoveOverlaps = removeOverlaps;
|
|
exports.layoutBoundingBox = boundingBox;
|
|
exports.dataJoin = dataJoin;
|
|
exports.effectivelyZero = effectivelyZero;
|
|
exports.seriesSvgLine = seriesSvgLine;
|
|
exports.seriesCanvasLine = seriesCanvasLine;
|
|
exports.seriesSvgPoint = seriesSvgPoint;
|
|
exports.seriesCanvasPoint = seriesCanvasPoint;
|
|
exports.seriesSvgBar = bar;
|
|
exports.seriesCanvasBar = bar$1;
|
|
exports.seriesSvgErrorBar = errorBar;
|
|
exports.seriesCanvasErrorBar = errorBar$1;
|
|
exports.seriesSvgArea = area$1;
|
|
exports.seriesCanvasArea = area$2;
|
|
exports.seriesSvgCandlestick = candlestick;
|
|
exports.seriesCanvasCandlestick = candlestick$1;
|
|
exports.seriesSvgBoxPlot = boxPlot;
|
|
exports.seriesCanvasBoxPlot = boxPlot$1;
|
|
exports.seriesSvgOhlc = ohlc;
|
|
exports.seriesCanvasOhlc = ohlc$1;
|
|
exports.seriesSvgMulti = seriesSvgMulti;
|
|
exports.seriesCanvasMulti = seriesCanvasMulti;
|
|
exports.seriesSvgGrouped = grouped;
|
|
exports.seriesCanvasGrouped = grouped$1;
|
|
exports.seriesSvgRepeat = repeat;
|
|
exports.seriesCanvasRepeat = repeat$1;
|
|
exports.autoBandwidth = autoBandwidth;
|
|
exports.seriesSvgHeatmap = heatmap;
|
|
exports.seriesCanvasHeatmap = heatmap$1;
|
|
exports.annotationSvgBand = band;
|
|
exports.annotationCanvasBand = band$1;
|
|
exports.annotationSvgCrosshair = crosshair;
|
|
exports.annotationCanvasCrosshair = crosshair$1;
|
|
exports.annotationSvgLine = annotationLine;
|
|
exports.annotationCanvasLine = annotationLine$1;
|
|
exports.annotationSvgGridline = gridline;
|
|
exports.annotationCanvasGridline = gridline$1;
|
|
exports.axisLabelRotate = axisLabelRotate;
|
|
exports.axisLabelOffset = axisLabelOffset;
|
|
exports.axisTop = axisTop;
|
|
exports.axisBottom = axisBottom;
|
|
exports.axisLeft = axisLeft;
|
|
exports.axisRight = axisRight;
|
|
exports.axisOrdinalTop = axisOrdinalTop;
|
|
exports.axisOrdinalBottom = axisOrdinalBottom;
|
|
exports.axisOrdinalLeft = axisOrdinalLeft;
|
|
exports.axisOrdinalRight = axisOrdinalRight;
|
|
exports.pointer = pointer;
|
|
exports.group = group;
|
|
exports.chartSvgCartesian = cartesian;
|
|
exports.chartCanvasCartesian = cartesian$1;
|
|
exports.chartCartesian = cartesianChart;
|
|
exports.brushX = brushX$1;
|
|
exports.brushY = brushY$1;
|
|
exports.brush = brush$1;
|
|
|
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
|
})));
|