JSFiddle - React, Tailwind, and code Playground
by akmiecik
HTML
<script>
/*!
* @license
* chartjs-chart-financial
* http://chartjs.org/
* Version: 0.1.0
*
* Copyright 2021 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'), require('chart.js/helpers')) :
typeof define === 'function' && define.amd ? define(['chart.js', 'chart.js/helpers'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Chart, global.Chart.helpers));
}(this, (function (chart_js, helpers) { 'use strict';
/**
* Computes the "optimal" sample size to maintain bars equally sized while preventing overlap.
* @private
*/
function computeMinSampleSize(scale, pixels) {
let min = scale._length;
let prev, curr, i, ilen;
for (i = 1, ilen = pixels.length; i < ilen; ++i) {
min = Math.min(min, Math.abs(pixels[i] - pixels[i - 1]));
}
for (i = 0, ilen = scale.ticks.length; i < ilen; ++i) {
curr = scale.getPixelForTick(i);
min = i > 0 ? Math.min(min, Math.abs(curr - prev)) : min;
prev = curr;
}
return min;
}
/**
* This class is based off controller.bar.js from the upstream Chart.js library
*/
class FinancialController extends chart_js.BarController {
getLabelAndValue(index) {
const me = this;
const parsed = me.getParsed(index);
const axis = me._cachedMeta.iScale.axis;
const {o, h, l, c} = parsed;
const value = `O: ${o} H: ${h} L: ${l} C: ${c}`;
return {
label: `${me._cachedMeta.iScale.getLabelForValue(parsed[axis])}`,
value
};
}
getAllParsedValues() {
const meta = this._cachedMeta;
const axis = meta.iScale.axis;
const parsed = meta._parsed;
const values = [];
for (let i = 0; i < parsed.length; ++i) {
values.push(parsed[i][axis]);
}
return values;
}
/**
* Implement this ourselves since it doesn't handle high and low values
*...
CSS
* {
font-family: Sans-Serif;
}
h1 {
font-size: 1.5em;
}
h2 {
font-size: 1.25em;
}
JavaScript
var barCount = 60;
var initialDateStr = '01 Apr 2017 00:00 Z';
var ctx = document.getElementById('chart').getContext('2d');
ctx.canvas.width = 1000;
ctx.canvas.height = 250;
var barData = getRandomData(initialDateStr, barCount);
function lineData() { return barData.map(d => { return { x: d.x, y: d.c} }) };
var chart = new Chart(ctx, {
type: 'candlestick',
data: {
datasets: [{
label: 'CHRT - Chart.js Corporation',
data: barData
}]
}
});
var getRandomInt = function(max) {
return Math.floor(Math.random() * Math.floor(max));
};
function randomNumber(min, max) {
return Math.random() * (max - min) + min;
}
function randomBar(date, lastClose) {
var open = +randomNumber(lastClose * 0.95, lastClose * 1.05).toFixed(2);
var close = +randomNumber(open * 0.95, open * 1.05).toFixed(2);
var high = +randomNumber(Math.max(open, close), Math.max(open, close) * 1.1).toFixed(2);
var low = +randomNumber(Math.min(open, close) * 0.9, Math.min(open, close)).toFixed(2);
return {
x: date.valueOf(),
o: open,
h: high,
l: low,
c: close
};
}
function getRandomData(dateStr, count) {
var date = luxon.DateTime.fromRFC2822(dateStr);
var data = [randomBar(date, 30)];
while (data.length < count) {
date = date.plus({days: 1});
if (date.weekday <= 5) {
data.push(randomBar(date, data[data.length - 1].c));
}
}
return data;
}
var update = function() {
var dataset = chart.config.data.datasets[0];
// candlestick vs ohlc
var type = document.getElementById('type').value;
dataset.type = type;
// linear vs log
var scaleType = document.getElementById('scale-type').value;
chart.config.options.scales.y.type = scaleType;
// color
var colorScheme = document.getElementById('color-scheme').value;
if (colorScheme === 'neon') {
dataset.color = {
up: '#01ff01',
down: '#fe0000',
unchanged: '#999',
};
} else {
delete dataset.color;
}
// border
var border = document.getElementById('border').value;
var defaultOpts =...