first commit
This commit is contained in:
+7
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
|
||||
/*!
|
||||
* chartjs-adapter-luxon v0.1.1
|
||||
* https://www.chartjs.org
|
||||
* (c) 2019 Chart.js Contributors
|
||||
* Released under the MIT license
|
||||
*/
|
||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("chart.js"),require("luxon")):"function"==typeof define&&define.amd?define(["chart.js","luxon"],t):t((e=e||self).Chart,e.luxon)}(this,function(e,t){"use strict";var n={datetime:"MMM d, yyyy, h:mm:ss a",millisecond:"h:mm:ss.SSS a",second:"h:mm:ss a",minute:"h:mm a",hour:"ha",day:"MMM d",week:"DD",month:"MMM yyyy",quarter:"'Q'q - yyyy",year:"yyyy"};function r(e){return t.DateTime.fromMillis(e)}e._adapters._date.override({_id:"luxon",formats:function(){return n},parse:function(n,f){if(e.helpers.isNullOrUndef(n))return null;var a=typeof n;return"number"===a?n=r(n):"string"===a?n="string"==typeof f?t.DateTime.fromFormat(n,f):t.DateTime.fromISO(n):"object"===a?n=t.DateTime.fromObject(n):n instanceof Date&&(n=t.DateTime.fromJSDate(n)),n.isValid?n.valueOf():null},format:function(e,t){return r(e).toFormat(t)},add:function(e,t,n){var f={};return f[n]=t,r(e).plus(f).valueOf()},diff:function(e,t,n){return r(e).diff(r(t)).as(n).valueOf()},startOf:function(e,t,n){return"isoWeek"===t?r(e).isoWeekday(n).valueOf():t?r(e).startOf(t).valueOf():e},endOf:function(e,t){return r(e).endOf(t).valueOf()}})});
|
||||
@@ -0,0 +1,462 @@
|
||||
/*!
|
||||
* @license
|
||||
* chartjs-chart-financial
|
||||
* http://chartjs.org/
|
||||
* Version: 0.1.0
|
||||
*
|
||||
* Copyright 2019 Chart.js Contributors
|
||||
* Released under the MIT license
|
||||
* https://github.com/chartjs/chartjs-chart-financial/blob/master/LICENSE.md
|
||||
*/
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('chart.js')) :
|
||||
typeof define === 'function' && define.amd ? define(['chart.js'], factory) :
|
||||
(global = global || self, factory(global.Chart));
|
||||
}(this, function (Chart) { 'use strict';
|
||||
|
||||
Chart = Chart && Chart.hasOwnProperty('default') ? Chart['default'] : Chart;
|
||||
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
var defaultConfig = {
|
||||
position: 'left',
|
||||
ticks: {
|
||||
callback: Chart.Ticks.formatters.linear
|
||||
}
|
||||
};
|
||||
|
||||
var FinancialLinearScale = Chart.scaleService.getScaleConstructor('linear').extend({
|
||||
|
||||
determineDataLimits: function() {
|
||||
var me = this;
|
||||
var chart = me.chart;
|
||||
var data = chart.data;
|
||||
var datasets = data.datasets;
|
||||
var isHorizontal = me.isHorizontal();
|
||||
|
||||
function IDMatches(meta) {
|
||||
return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
|
||||
}
|
||||
|
||||
// First Calculate the range
|
||||
me.min = null;
|
||||
me.max = null;
|
||||
|
||||
// Regular charts use x, y values
|
||||
// For the financial chart we have rawValue.h (hi) and rawValue.l (low) for each point
|
||||
helpers.each(datasets, function(dataset, datasetIndex) {
|
||||
var meta = chart.getDatasetMeta(datasetIndex);
|
||||
if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
|
||||
helpers.each(dataset.data, function(rawValue) {
|
||||
var high = rawValue.h;
|
||||
var low = rawValue.l;
|
||||
|
||||
if (me.min === null) {
|
||||
me.min = low;
|
||||
} else if (low < me.min) {
|
||||
me.min = low;
|
||||
}
|
||||
|
||||
if (me.max === null) {
|
||||
me.max = high;
|
||||
} else if (high > me.max) {
|
||||
me.max = high;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Add whitespace around bars. Axis shouldn't go exactly from min to max
|
||||
var space = (me.max - me.min) * 0.05;
|
||||
me.min -= space;
|
||||
me.max += space;
|
||||
|
||||
// Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
|
||||
this.handleTickRangeOptions();
|
||||
}
|
||||
});
|
||||
|
||||
Chart.scaleService.registerScaleType('financialLinear', FinancialLinearScale, defaultConfig);
|
||||
|
||||
var helpers$1 = Chart.helpers;
|
||||
|
||||
Chart.defaults.financial = {
|
||||
label: '',
|
||||
|
||||
hover: {
|
||||
mode: 'label'
|
||||
},
|
||||
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: 'time',
|
||||
distribution: 'series',
|
||||
categoryPercentage: 0.8,
|
||||
barPercentage: 0.9,
|
||||
ticks: {
|
||||
source: 'data'
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
type: 'financialLinear'
|
||||
}]
|
||||
},
|
||||
|
||||
tooltips: {
|
||||
intersect: false,
|
||||
mode: 'index',
|
||||
callbacks: {
|
||||
label: function(tooltipItem, data) {
|
||||
var p = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index].p;
|
||||
var o = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index].o;
|
||||
var h = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index].h;
|
||||
var l = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index].l;
|
||||
var c = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index].c;
|
||||
|
||||
var dataset = data.datasets[tooltipItem.datasetIndex];
|
||||
var precision = helpers$1.valueOrDefault(dataset.precision, 2);
|
||||
precision = Math.max(0, Math.min(100, precision));
|
||||
o = o.toFixed(precision);
|
||||
h = h.toFixed(precision);
|
||||
l = l.toFixed(precision);
|
||||
c = c.toFixed(precision);
|
||||
|
||||
return (p!=''?(p+'\r'):'') + ' O: ' + o + ' H: ' + h + ' L: ' + l + ' C: ' + c;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This class is based off controller.bar.js from the upstream Chart.js library
|
||||
*/
|
||||
var FinancialController = Chart.controllers.bar.extend({
|
||||
|
||||
dataElementType: Chart.elements.Financial,
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_updateElementGeometry: function(element, index, reset) {
|
||||
var me = this;
|
||||
var model = element._model;
|
||||
var vscale = me._getValueScale();
|
||||
var base = vscale.getBasePixel();
|
||||
var horizontal = vscale.isHorizontal();
|
||||
var ruler = me._ruler || me.getRuler();
|
||||
var vpixels = me.calculateBarValuePixels(me.index, index);
|
||||
var ipixels = me.calculateBarIndexPixels(me.index, index, ruler);
|
||||
var chart = me.chart;
|
||||
var datasets = chart.data.datasets;
|
||||
var indexData = datasets[me.index].data[index];
|
||||
|
||||
model.horizontal = horizontal;
|
||||
model.base = reset ? base : vpixels.base;
|
||||
model.x = horizontal ? reset ? base : vpixels.head : ipixels.center;
|
||||
model.y = horizontal ? ipixels.center : reset ? base : vpixels.head;
|
||||
model.height = horizontal ? ipixels.size : undefined;
|
||||
model.width = horizontal ? undefined : ipixels.size;
|
||||
model.candleOpen = vscale.getPixelForValue(Number(indexData.o));
|
||||
model.candleHigh = vscale.getPixelForValue(Number(indexData.h));
|
||||
model.candleLow = vscale.getPixelForValue(Number(indexData.l));
|
||||
model.candleClose = vscale.getPixelForValue(Number(indexData.c));
|
||||
},
|
||||
|
||||
draw: function() {
|
||||
var ctx = this.chart.chart.ctx;
|
||||
var elements = this.getMeta().data;
|
||||
var dataset = this.getDataset();
|
||||
var ilen = elements.length;
|
||||
var i = 0;
|
||||
var d;
|
||||
|
||||
Chart.canvasHelpers.clipArea(ctx, this.chart.chartArea);
|
||||
|
||||
for (; i < ilen; ++i) {
|
||||
d = dataset.data[i].o;
|
||||
if (d !== null && d !== undefined && !isNaN(d)) {
|
||||
elements[i].draw();
|
||||
}
|
||||
}
|
||||
|
||||
Chart.canvasHelpers.unclipArea(ctx);
|
||||
},
|
||||
});
|
||||
|
||||
var helpers$2 = Chart.helpers;
|
||||
var globalOpts = Chart.defaults.global;
|
||||
|
||||
globalOpts.elements.financial = {
|
||||
color: {
|
||||
up: 'rgba(80, 160, 115, 1)',
|
||||
down: 'rgba(215, 85, 65, 1)',
|
||||
unchanged: 'rgba(90, 90, 90, 1)',
|
||||
}
|
||||
};
|
||||
|
||||
function isVertical(bar) {
|
||||
return bar._view.width !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get the bounds of the candle
|
||||
* @private
|
||||
* @param bar {Chart.Element.financial} the bar
|
||||
* @return {Bounds} bounds of the bar
|
||||
*/
|
||||
function getBarBounds(candle) {
|
||||
var vm = candle._view;
|
||||
var x1, x2, y1, y2;
|
||||
|
||||
var halfWidth = vm.width / 2;
|
||||
x1 = vm.x - halfWidth;
|
||||
x2 = vm.x + halfWidth;
|
||||
y1 = vm.candleHigh;
|
||||
y2 = vm.candleLow;
|
||||
|
||||
return {
|
||||
left: x1,
|
||||
top: y1,
|
||||
right: x2,
|
||||
bottom: y2
|
||||
};
|
||||
}
|
||||
|
||||
var FinancialElement = Chart.Element.extend({
|
||||
|
||||
height: function() {
|
||||
var vm = this._view;
|
||||
return vm.base - vm.y;
|
||||
},
|
||||
inRange: function(mouseX, mouseY) {
|
||||
var inRange = false;
|
||||
|
||||
if (this._view) {
|
||||
var bounds = getBarBounds(this);
|
||||
inRange = mouseX >= bounds.left && mouseX <= bounds.right && mouseY >= bounds.top && mouseY <= bounds.bottom;
|
||||
}
|
||||
|
||||
return inRange;
|
||||
},
|
||||
inLabelRange: function(mouseX, mouseY) {
|
||||
var me = this;
|
||||
if (!me._view) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var inRange = false;
|
||||
var bounds = getBarBounds(me);
|
||||
|
||||
if (isVertical(me)) {
|
||||
inRange = mouseX >= bounds.left && mouseX <= bounds.right;
|
||||
} else {
|
||||
inRange = mouseY >= bounds.top && mouseY <= bounds.bottom;
|
||||
}
|
||||
|
||||
return inRange;
|
||||
},
|
||||
inXRange: function(mouseX) {
|
||||
var bounds = getBarBounds(this);
|
||||
return mouseX >= bounds.left && mouseX <= bounds.right;
|
||||
},
|
||||
inYRange: function(mouseY) {
|
||||
var bounds = getBarBounds(this);
|
||||
return mouseY >= bounds.top && mouseY <= bounds.bottom;
|
||||
},
|
||||
getCenterPoint: function() {
|
||||
var vm = this._view;
|
||||
return {
|
||||
x: vm.x,
|
||||
y: (vm.candleHigh + vm.candleLow) / 2
|
||||
};
|
||||
},
|
||||
getArea: function() {
|
||||
var vm = this._view;
|
||||
return vm.width * Math.abs(vm.y - vm.base);
|
||||
},
|
||||
tooltipPosition: function() {
|
||||
var vm = this._view;
|
||||
return {
|
||||
x: vm.x,
|
||||
y: (vm.candleOpen + vm.candleClose) / 2
|
||||
};
|
||||
},
|
||||
hasValue: function() {
|
||||
var model = this._model;
|
||||
return helpers$2.isNumber(model.x) &&
|
||||
helpers$2.isNumber(model.candleOpen) &&
|
||||
helpers$2.isNumber(model.candleHigh) &&
|
||||
helpers$2.isNumber(model.candleLow) &&
|
||||
helpers$2.isNumber(model.candleClose);
|
||||
}
|
||||
});
|
||||
|
||||
var helpers$3 = Chart.helpers;
|
||||
var globalOpts$1 = Chart.defaults.global;
|
||||
|
||||
globalOpts$1.elements.candlestick = helpers$3.merge({}, [globalOpts$1.elements.financial, {
|
||||
borderColor: globalOpts$1.elements.financial.color.unchanged,
|
||||
borderWidth: 1,
|
||||
}]);
|
||||
|
||||
var CandlestickElement = FinancialElement.extend({
|
||||
draw: function() {
|
||||
var ctx = this._chart.ctx;
|
||||
var vm = this._view;
|
||||
|
||||
var x = vm.x;
|
||||
var o = vm.candleOpen;
|
||||
var h = vm.candleHigh;
|
||||
var l = vm.candleLow;
|
||||
var c = vm.candleClose;
|
||||
|
||||
var borderColors = vm.borderColor;
|
||||
|
||||
if (typeof borderColors === 'string') {
|
||||
borderColors = {
|
||||
up: borderColors,
|
||||
down: borderColors,
|
||||
unchanged: borderColors
|
||||
};
|
||||
}
|
||||
|
||||
var borderColor;
|
||||
if (c < o) {
|
||||
borderColor = helpers$3.getValueOrDefault(borderColors ? borderColors.up : undefined, globalOpts$1.elements.candlestick.borderColor);
|
||||
ctx.fillStyle = helpers$3.getValueOrDefault(vm.color ? vm.color.up : undefined, globalOpts$1.elements.candlestick.color.up);
|
||||
} else if (c > o) {
|
||||
borderColor = helpers$3.getValueOrDefault(borderColors ? borderColors.down : undefined, globalOpts$1.elements.candlestick.borderColor);
|
||||
ctx.fillStyle = helpers$3.getValueOrDefault(vm.color ? vm.color.down : undefined, globalOpts$1.elements.candlestick.color.down);
|
||||
} else {
|
||||
borderColor = helpers$3.getValueOrDefault(borderColors ? borderColors.unchanged : undefined, globalOpts$1.elements.candlestick.borderColor);
|
||||
ctx.fillStyle = helpers$3.getValueOrDefault(vm.color ? vm.color.unchanged : undefined, globalOpts$1.elements.candlestick.color.unchanged);
|
||||
}
|
||||
|
||||
ctx.lineWidth = helpers$3.getValueOrDefault(vm.borderWidth, globalOpts$1.elements.candlestick.borderWidth);
|
||||
ctx.strokeStyle = helpers$3.getValueOrDefault(borderColor, globalOpts$1.elements.candlestick.borderColor);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, h);
|
||||
ctx.lineTo(x, Math.min(o, c));
|
||||
ctx.moveTo(x, l);
|
||||
ctx.lineTo(x, Math.max(o, c));
|
||||
ctx.stroke();
|
||||
ctx.fillRect(x - vm.width / 2, c, vm.width, o - c);
|
||||
ctx.strokeRect(x - vm.width / 2, c, vm.width, o - c);
|
||||
ctx.closePath();
|
||||
},
|
||||
});
|
||||
|
||||
Chart.defaults.candlestick = Chart.helpers.merge({}, Chart.defaults.financial);
|
||||
|
||||
var CandlestickController = Chart.controllers.candlestick = FinancialController.extend({
|
||||
dataElementType: CandlestickElement,
|
||||
|
||||
updateElement: function(element, index, reset) {
|
||||
var me = this;
|
||||
var meta = me.getMeta();
|
||||
var dataset = me.getDataset();
|
||||
|
||||
element._xScale = me.getScaleForId(meta.xAxisID);
|
||||
element._yScale = me.getScaleForId(meta.yAxisID);
|
||||
element._datasetIndex = me.index;
|
||||
element._index = index;
|
||||
|
||||
element._model = {
|
||||
datasetLabel: dataset.label || '',
|
||||
// label: '', // to get label value please use dataset.data[index].label
|
||||
|
||||
// Appearance
|
||||
color: dataset.color,
|
||||
borderColor: dataset.borderColor,
|
||||
borderWidth: dataset.borderWidth,
|
||||
};
|
||||
|
||||
me._updateElementGeometry(element, index, reset);
|
||||
|
||||
element.pivot();
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
var helpers$4 = Chart.helpers;
|
||||
var globalOpts$2 = Chart.defaults.global;
|
||||
|
||||
globalOpts$2.elements.ohlc = helpers$4.merge({}, [globalOpts$2.elements.financial, {
|
||||
lineWidth: 2,
|
||||
armLength: null,
|
||||
armLengthRatio: 0.8,
|
||||
}]);
|
||||
|
||||
var OhlcElement = FinancialElement.extend({
|
||||
draw: function() {
|
||||
var ctx = this._chart.ctx;
|
||||
var vm = this._view;
|
||||
|
||||
var x = vm.x;
|
||||
var o = vm.candleOpen;
|
||||
var h = vm.candleHigh;
|
||||
var l = vm.candleLow;
|
||||
var c = vm.candleClose;
|
||||
var armLength = helpers$4.getValueOrDefault(vm.armLength, globalOpts$2.elements.ohlc.armLength);
|
||||
var armLengthRatio = helpers$4.getValueOrDefault(vm.armLengthRatio, globalOpts$2.elements.ohlc.armLengthRatio);
|
||||
if (armLength === null) {
|
||||
// The width of an ohlc is affected by barPercentage and categoryPercentage
|
||||
// This behavior is caused by extending controller.financial, which extends controller.bar
|
||||
// barPercentage and categoryPercentage are now set to 1.0 (see controller.ohlc)
|
||||
// and armLengthRatio is multipled by 0.5,
|
||||
// so that when armLengthRatio=1.0, the arms from neighbour ohcl touch,
|
||||
// and when armLengthRatio=0.0, ohcl are just vertical lines.
|
||||
armLength = vm.width * armLengthRatio * 0.5;
|
||||
}
|
||||
|
||||
if (c < o) {
|
||||
ctx.strokeStyle = helpers$4.getValueOrDefault(vm.color ? vm.color.up : undefined, globalOpts$2.elements.ohlc.color.up);
|
||||
} else if (c > o) {
|
||||
ctx.strokeStyle = helpers$4.getValueOrDefault(vm.color ? vm.color.down : undefined, globalOpts$2.elements.ohlc.color.down);
|
||||
} else {
|
||||
ctx.strokeStyle = helpers$4.getValueOrDefault(vm.color ? vm.color.unchanged : undefined, globalOpts$2.elements.ohlc.color.unchanged);
|
||||
}
|
||||
ctx.lineWidth = helpers$4.getValueOrDefault(vm.lineWidth, globalOpts$2.elements.ohlc.lineWidth);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, h);
|
||||
ctx.lineTo(x, l);
|
||||
ctx.moveTo(x - armLength, o);
|
||||
ctx.lineTo(x, o);
|
||||
ctx.moveTo(x + armLength, c);
|
||||
ctx.lineTo(x, c);
|
||||
ctx.stroke();
|
||||
},
|
||||
});
|
||||
|
||||
Chart.defaults.ohlc = Chart.helpers.merge({}, Chart.defaults.financial);
|
||||
Chart.defaults.ohlc.scales.xAxes[0].barPercentage = 1.0;
|
||||
Chart.defaults.ohlc.scales.xAxes[0].categoryPercentage = 1.0;
|
||||
|
||||
var OhlcController = Chart.controllers.ohlc = FinancialController.extend({
|
||||
|
||||
dataElementType: OhlcElement,
|
||||
|
||||
updateElement: function(element, index, reset) {
|
||||
var me = this;
|
||||
var meta = me.getMeta();
|
||||
var dataset = me.getDataset();
|
||||
element._xScale = me.getScaleForId(meta.xAxisID);
|
||||
element._yScale = me.getScaleForId(meta.yAxisID);
|
||||
element._datasetIndex = me.index;
|
||||
element._index = index;
|
||||
element._model = {
|
||||
datasetLabel: dataset.label || '',
|
||||
lineWidth: dataset.lineWidth,
|
||||
armLength: dataset.armLength,
|
||||
armLengthRatio: dataset.armLengthRatio,
|
||||
color: dataset.color,
|
||||
};
|
||||
me._updateElementGeometry(element, index, reset);
|
||||
element.pivot();
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
}));
|
||||
+1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user