diff --git a/src/components/Chart/__test__/chart.spec.js b/src/components/Chart/__test__/chart.spec.js index dcfbf399f..e2c6102eb 100644 --- a/src/components/Chart/__test__/chart.spec.js +++ b/src/components/Chart/__test__/chart.spec.js @@ -1,12 +1,12 @@ import React from 'react'; import { mount } from 'enzyme'; -import ChartJS from 'chart.js'; +import ChartJS from '../chart'; import { Chart } from '../index'; import Dataset from '../../Dataset'; jest.mock('../helpers/unregisterGlobalPlugins', () => jest.fn()); -jest.mock('chart.js', () => +jest.mock('../chart', () => jest.fn(() => ({ update: jest.fn(), config: {}, diff --git a/src/components/Chart/chart.js b/src/components/Chart/chart.js new file mode 100644 index 000000000..710614d3e --- /dev/null +++ b/src/components/Chart/chart.js @@ -0,0 +1,55 @@ +/* eslint-disable no-underscore-dangle */ +import Chart from 'chart.js'; + +const maxRadius = 20; +const getRadius = (height, width) => { + const min = Math.min(height, width); + if (maxRadius > min / 2) { + return min / 2; + } + return maxRadius; +}; + +function drawRectVertical(context, view) { + const { x, y, base, width } = view; + const left = x - width / 2; + const height = base - y; + const radius = getRadius(height, width); + context.moveTo(left + radius, y); + context.lineTo(left + width - radius, y); + context.quadraticCurveTo(left + width, y, left + width, y + radius); + context.lineTo(left + width, base); + context.lineTo(left, base); + context.lineTo(left, y + radius); + context.quadraticCurveTo(left, y, left + radius, y); +} + +function drawRectHorizontal(context, view) { + const { x, y, base, height } = view; + const width = x; + const top = y - height / 2; + const radius = getRadius(height, width); + context.moveTo(x - radius, top); + context.quadraticCurveTo(x, top, x, top + radius); + context.lineTo(x, top + height - radius); + context.quadraticCurveTo(x, top + height, x - radius, top + height); + context.lineTo(base, top + height); + context.lineTo(base, top); + context.lineTo(top - radius, top); +} + +Chart.elements.Rectangle.prototype.draw = function drawRect() { + const context = this._chart.ctx; + const view = this._view; + context.beginPath(); + context.fillStyle = view.backgroundColor; + context.strokeStyle = view.borderColor; + if (view.horizontal) { + drawRectHorizontal(context, view); + } else { + drawRectVertical(context, view); + } + context.fill(); +}; + +export default Chart; diff --git a/src/components/Chart/index.js b/src/components/Chart/index.js index c3e126ec9..5b019a2e9 100644 --- a/src/components/Chart/index.js +++ b/src/components/Chart/index.js @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import ChartJS from 'chart.js'; import { withTheme } from 'styled-components'; +import ChartJS from './chart'; import resolveOptions from './resolveOptions'; import resolveDatasets from './resolveDatasets'; import StyledContainer from './styled/container'; diff --git a/src/components/Chart/readme.md b/src/components/Chart/readme.md index 6769470e0..5d8f71a2d 100644 --- a/src/components/Chart/readme.md +++ b/src/components/Chart/readme.md @@ -184,6 +184,156 @@ class BarChartExample extends React.Component { ; ``` +##### Bar chart horizontal: + +```js +import React from 'react'; +import { Chart, Dataset, ButtonGroup, Button } from 'react-rainbow-components'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faPlus, faMinus } from '@fortawesome/free-solid-svg-icons'; + +const containerStyles = { + maxWidth: 600, +}; + +class BarChartExample extends React.Component { + constructor(props) { + super(props); + this.titles = ['Data-Blue', 'Data-Purple', 'Data-Dark']; + this.colors = ['#01b6f5', '#663398', '#061c3f']; + this.months = ['July', 'August', 'September', 'October', 'November', 'December']; + this.state = { + labels: ['January', 'February', 'March', 'April', 'May', 'June'], + datasets: [ + { + title: 'Data-Red', + backgroundColor: '#fe4849', + values: [18, 42, 58, 50, 19, undefined], + }, + { + title: 'Data-Orange', + backgroundColor: '#ff6837', + values: [undefined, 40, undefined, 45, 95, 33], + }, + { + title: 'Data-Yellow', + backgroundColor: '#ffcc00', + values: [undefined, 30, 80, undefined, 65, 50], + }, + { + title: 'Data-Green', + backgroundColor: '#1ad1a3', + values: [undefined, 15, undefined, 60, 45, 85], + }, + ], + }; + } + + addDataset() { + const { labels, datasets } = this.state; + const newValues = labels.map(label => Math.round(Math.random() * 100)); + const newDatasets = datasets.concat({ + title: this.titles.shift(), + values: newValues, + backgroundColor: this.colors.shift(), + }); + this.setState({ datasets: newDatasets }); + } + + removeDataset() { + const { datasets } = this.state; + const dataset = datasets[datasets.length - 1]; + this.titles.unshift(dataset.title); + this.colors.unshift(dataset.backgroundColor); + const newDatasets = datasets.filter(d => d.title !== dataset.title); + this.setState({ datasets: newDatasets }); + } + + addMonth() { + const { labels, datasets } = this.state; + const newlabels = labels.concat(this.months.shift()); + const newDatasets = datasets.map(dataset => { + const { values, ...rest } = dataset; + const newValues = values.concat(Math.round(Math.random() * 100)); + return { + ...rest, + values: newValues, + }; + }); + this.setState({ labels: newlabels, datasets: newDatasets }); + } + + removeMonth() { + const { labels, datasets } = this.state; + const label = labels[labels.length - 1]; + this.months.unshift(label); + const newLabels = labels.filter(l => l !== label); + const newDatasets = datasets.map(dataset => { + const { values, ...rest } = dataset; + const newValues = values.slice(0, values.length - 1); + return { + ...rest, + values: newValues, + }; + }); + this.setState({ labels: newLabels, datasets: newDatasets }); + } + + renderDatasets() { + const { datasets } = this.state; + return datasets.map(({ title, values, backgroundColor }) => ( + + )); + } + + render() { + const { labels, datasets } = this.state; + + const noMoreTitles = this.titles.length === 0; + const noMoreDatasets = datasets.length === 0; + const noMoreMonths = this.months.length === 0; + const noMoreLabels = labels.length === 0; + + return ( +
+
+ + + + + + + + +
+
+ + {this.renderDatasets()} + +
+
+ ); + } +} + +; +``` + ##### Line chart: ```js