next chart.js how to change date display - reactjs

how to change date display on my chart? Here below my chart:
How to change date displaying way? Is there any way to display it horizontaly and f.e. not every date, but every third?
Here below my code:
import { ChartProps } from "./Chart.props";
import styles from "./Chart.module.css";
import React, { useState, useEffect, useRef } from 'react';
import { Button } from "../Button/Button";
import { options } from "./ChartConfig.js";
import { Chart as ChartJS, ArcElement, CategoryScale, LinearScale, PointElement, LineElement, Filler, Tooltip, Legend, ScriptableContext, } from "chart.js";
import { Chart as ReactChart, Line } from "react-chartjs-2";
import coinGecko from "../../../apis/coinGecko";
ChartJS.register(ArcElement, Tooltip, Filler, Legend, CategoryScale, LinearScale, PointElement, LineElement);
export const CoinPriceChart = (props) => {
const [timeFormat, setTimeFormat] = useState("30d");
const [interval, setInterval] = useState("hourly");
const [coinPrice, setCoinPrice] = useState([]);
const [coinHistory, setCoinHistory] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const x = [];
const y = [];
const determineTimeFormat = () => {
switch (timeFormat) {
case "1":
setInterval("5min");
setTimeFormat("1");
case "7":
setInterval("hourly");
setTimeFormat("7");
case "30":
setInterval("daily");
setTimeFormat("30");
default:
setInterval("hourly");
}
};
useEffect(() => {
const fetchData = async () => {
setIsLoading(true);
await fetch(`https://api.coingecko.com/api/v3/coins/bitcoin/market_chart?vs_currency=usd&days=${timeFormat}&interval=${interval}`)
.then((response) => {
return response.json();
})
.then((data) => {
for (let i = 0; i < data.prices.length; i++) {
x.push(data.prices[i][1])
setCoinPrice(x)
}
for (let i = 0; i < data.prices.length; i++) {
y.push(new Date(data.prices[i][0]).toLocaleDateString("en-GB"))
setCoinHistory(y)
}
})
setIsLoading(false);
};
fetchData();
}, [timeFormat]);
const chart = {
labels: coinHistory,
datasets: [
{
data: coinPrice,
pointRadius: 0,
pointHoverRadius: 2,
backgroundColor: (context: ScriptableContext<"line">) => {
const ctx = context.chart.ctx;
const gradient = ctx.createLinearGradient(0, 0, 0, 330);
gradient.addColorStop(0, "rgba(91,56,237,0.45)");
gradient.addColorStop(1, "rgba(91,56,237,0.0)");
return gradient;
},
borderColor: "rgba(91,56,237,255)",
fill: true,
}
],
options: {
...options
},
};
console.log(timeFormat)
return (
<div
className={styles.Chart}
{...props}
>
<Line id="myChart" data={chart} options={options} />
<div className="chart-button mt-1">
<Button
onClick={() => setTimeFormat("1")}
appearance={"primary"} >
24h
</Button>
<Button
onClick={() => setTimeFormat("7")}
appearance={"primary"}
>
7d
</Button>
<Button
onClick={() => setTimeFormat("30")}
appearance={"primary"}
>
30d
</Button>
</div>
</div>
);
};
I've been searching for it on a doc., but I haven't found this info.
And here below my options code:
export const options = {
plugins: {
// show legends for our graph
legend: {
display: false,
},
},
lineHeightAnnotation: {
always: true,
lineWeight: 3,
},
// animate in
animation: {
duration: 1,
},
// show the x and y scales
scales: {
x: {
display: true,
},
y: { display: true },
},
time: {
useUTC: true
},
xAxis: {
type: 'datetime'
},
};
Thanks in advance!:)

Okay here it is my ChartConfig.js
export const options = {
plugins: {
// show legends for our graph
legend: {
display: false,
},
},
lineHeightAnnotation: {
always: true,
lineWeight: 3,
},
// animate in
animation: {
duration: 1,
},
// show the x and y scales
scales: {
x: {
display: true,
ticks: {
maxRotation: 0, // this line to make labels horizontal
maxTicksLimit: 5, // this is num of labels limit
}
},
y: {
display: true
},
xAxes: [{
ticks: {
maxRotation: 90
}
}]
},
time: {
useUTC: true
},
};
And as a result:

Related

Property 'toBase64Image' does not exist on type 'FC<LineChartProps>'. I am trying to download chartjs chart to image

interface LineChartProps {
title: string,
labelProp: string,
dataProp: string
data: any,
}
const LineChart: React.FC < LineChartProps > = ({
title,
data,
labelProp,
dataProp
}: LineChartProps) => {
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend
);
const colorHash = new ColorHash();
const options = {
responsive: true,
plugins: {
legend: {
display: false,
},
title: {
display: true,
text: title,
},
},
maintainAspectRatio: false,
};
const labels = data.map((item: any) => item[labelProp]);
const chartData = {
labels,
datasets: [{
label: title,
data: data.map((item: any) => item[dataProp]),
borderColor: colorHash.hex(title),
backgroundColor: colorHash.hex(title),
}],
};
return <Line options = {
options
}
data = {
chartData
}
/>;
};
var image = LineChart.toBase64Image();
console.log(image);

How to import useCombinedRefs when using react-data-grid

I am trying to implement the draggable columns with react-data-grid based on this example: https://github.com/adazzle/react-data-grid/blob/canary/stories/demos/ColumnsReordering.tsx
I see that this example requires creating a DraggableHeaderRenderer file, so I have copied the following file into my project and converted it to React: https://github.com/adazzle/react-data-grid/blob/canary/stories/demos/components/HeaderRenderers/DraggableHeaderRenderer.tsx
My issue is that I do not know where to import useCombinedRefs from. It is not exported from react-data-grid. I see in the repo that it resides in src/hooks.
I have tried the following:
import {useCombinedRefs} from 'react-data-grid'
// Error: Attempted import error: 'useCombinedRefs' is not exported from 'react-data-grid'.
import {useCombinedRefs} from 'react-data-grid/lib/hooks';
// Error: Module not found: Can't resolve 'react-data-grid/lib/hooks' in 'C:\Users\Liam\Desktop\Work\MyProject\src\ReactDataGrid'
import useCombinedRefs from 'react-data-grid/lib/hooks/useCombinedRefs';
// Error: Module not found: Can't resolve 'react-data-grid/lib/hooks/useCombinedRefs' in 'C:\Users\Liam\Desktop\Work\MyProject\src\ReactDataGrid'
Thanks to anyone who can help.
Here is my code:
DraggableHeaderRenderer.js
import { useDrag, useDrop } from 'react-dnd';
import React from 'react'
import { SortableHeaderCell } from 'react-data-grid';
import useCombinedRefs from 'react-data-grid/lib/hooks/useCombinedRefs';
export function DraggableHeaderRenderer({ onColumnsReorder, column, sortColumn, sortDirection, onSort }) {
const [{ isDragging }, drag] = useDrag({
item: { key: column.key, type: 'COLUMN_DRAG' },
collect: monitor => ({
isDragging: !!monitor.isDragging()
})
});
const [{ isOver }, drop] = useDrop({
accept: 'COLUMN_DRAG',
drop({ key, type }) {
if (type === 'COLUMN_DRAG') {
onColumnsReorder(key, column.key);
}
},
collect: monitor => ({
isOver: !!monitor.isOver(),
canDrop: !!monitor.canDrop()
})
});
return (
<div
ref={useCombinedRefs(drag, drop)}
style={{
opacity: isDragging ? 0.5 : 1,
backgroundColor: isOver ? '#ececec' : 'inherit',
cursor: 'move'
}}
>
<SortableHeaderCell
column={column}
sortColumn={sortColumn}
sortDirection={sortDirection}
onSort={onSort}
>
{column.name}
</SortableHeaderCell>
</div>
);
}
TestDataGrid.js
import React from 'react';
import DataGrid from 'react-data-grid';
import {DraggableHeaderRenderer} from './DraggableHeaderRenderer';
import { useState, useCallback, useMemo } from 'react';
import 'react-data-grid/dist/react-data-grid.css';
const createRows = () => {
const rows = [];
for (let i = 1; i < 500; i++) {
rows.push({
id: i,
task: `Task ${i}`,
complete: Math.min(100, Math.round(Math.random() * 110)),
priority: ['Critical', 'High', 'Medium', 'Low'][Math.round(Math.random() * 3)],
issueType: ['Bug', 'Improvement', 'Epic', 'Story'][Math.round(Math.random() * 3)]
});
}
return rows;
}
const createColumns = () => {
return [
{
key: 'id',
name: 'ID',
width: 80,
},
{
key: 'task',
name: 'Title',
resizable: true,
sortable: true,
draggable: true
},
{
key: 'priority',
name: 'Priority',
resizable: true,
sortable: true,
draggable: true
},
{
key: 'issueType',
name: 'Issue Type',
resizable: true,
sortable: true,
draggable: true
},
{
key: 'complete',
name: '% Complete',
resizable: true,
sortable: true,
draggable: true
}
];
}
export default function TestDataGrid() {
const [rows] = useState(createRows)
const [columns, setColumns] = useState(createColumns)
const draggableColumns = useMemo(() => {
const HeaderRenderer = (props) => {
return <DraggableHeaderRenderer {...props} onColumnsReorder={handleColumnsReorder}/>
}
const handleColumnsReorder = (sourceKey, targetKey) => {
const sourceColumnIndex = columns.findIndex(c => c.key === sourceKey);
const targetColumnIndex = columns.findIndex(c => c.key === targetKey);
const reorderedColumns = [...columns];
reorderedColumns.splice(
targetColumnIndex,
0,
reorderedColumns.splice(sourceColumnIndex, 1)[0]
);
setColumns(reorderedColumns);
}
return columns.map(c => {
if(c.key === "id") return c;
return {...c, HeaderRenderer}
});
}, [columns])
return (
<DataGrid
columns={draggableColumns}
rows={rows}
/>
);
}

Why is the data from my API not displaying on my chart.js chart in React?

I am making a SPA in React that displays data in a chart.js graph from the Carbon Intensity API which can be found here: https://carbon-intensity.github.io/api-definitions/?shell#get-intensity-from-to .
I have been able to get the data from the API using axios and can see this when I inspect the console, however it just parses in NaN for all the data when you inspect it in the console:
I will post all relevant code below, my desired output is for the data from the API to be displayed on the line chart.
Chart3.js
import React, { useState, useEffect } from "react";
import { Line } from "react-chartjs-2";
import axios from "axios";
const Chart3 = () => {
const [chartData, setChartData] = useState({});
const [Forecast, setForecast] = useState([]);
const [Actual, setActual] = useState([]);
const chart = () => {
let Fore = [];
let Act = [];
axios
.get('https://api.carbonintensity.org.uk/intensity/2020-08-25T15:30Z/2020-09-10T17:00Z')
.then(res => {
console.log(res);
for (const dataObj of res.data.data) {
Fore.push(parseInt(dataObj.forecast));
Act.push(parseInt(dataObj.actual));
}
setChartData({
labels: Fore,
datasets: [
{
label: "Forestreet",
data: Act,
backgroundColor: ["rgba(75, 192, 192, 0.6)"],
borderWidth: 4
}
]
});
})
.catch(err => {
console.log(err);
});
console.log(Fore, Act);
};
useEffect(() => {
chart();
}, []);
return (
<div className="App">
<h1>Dankmemes</h1>
<div style={{height:"500px", width:"500px"}}>
<Line
data={chartData}
options={{
responsive: true,
title: { text: "ForeStreet", display: true },
scales: {
yAxes: [
{
ticks: {
autoSkip: true,
maxTicksLimit: 10,
beginAtZero: true
},
gridLines: {
display: false
}
}
],
xAxes: [
{
gridLines: {
display: false
}
}
]
}
}}
/>
</div>
</div>
);
};
export default Chart3;
App.js
import React from 'react';
import { BrowserRouter as Router} from 'react-router-dom';
import './App.css';
import Chart from './Components/Chart/Chart';
import Chart1 from './Components/Chart/Chart1';
import Chart2 from './Components/Chart/Chart2';
import Chart3 from './Components/Chart/Chart3';
import Footer from './Components/Footer/Footer';
import Header from './Components/Header/Header';
import Container from './Components/Hero/Hero';
import Hero from './Components/Hero/Hero';
function App() {
return (
<Router>
<Header />
<Chart3 />
<Footer />
</Router>
);
}
export default App;
This is what my chart currently looks like it with the API data:
Your dataObject in axios res is not correct, you forgot intensity.
your Chart3.js have to look like:
import axios from "axios";
import React, {useState, useEffect} from "react";
import { Line } from "react-chartjs-2";
const Chart3 = () => {
const [chartData, setChartData] = useState({});
const [Forecast, setForecast] = useState([]);
const [Actual, setActual] = useState([]);
const chart = () => {
let Fore = [];
let Act = [];
axios
.get('https://api.carbonintensity.org.uk/intensity/2020-08-25T15:30Z/2020-09-10T17:00Z')
.then(res => {
console.log(res);
for (const dataObj of res.data.data) {
Fore.push(parseInt(dataObj.intensity.forecast));
Act.push(parseInt(dataObj.intensity.actual));
}
setChartData({
labels: Fore,
datasets: [
{
label: "Forestreet",
data: Act,
backgroundColor: ["rgba(75, 192, 192, 0.6)"],
borderWidth: 4
}
]
});
})
.catch(err => {
console.log(err);
});
console.log(Fore, Act);
};
useEffect(() => {
chart();
}, []);
return (
<div className="App">
<h1>Dankmemes</h1>
<div style={{height:"500px", width:"500px"}}>
<Line
data={chartData}
options={{
responsive: true,
title: { text: "ForeStreet", display: true },
scales: {
yAxes: [
{
ticks: {
autoSkip: true,
maxTicksLimit: 10,
beginAtZero: true
},
gridLines: {
display: false
}
}
],
xAxes: [
{
gridLines: {
display: false
}
}
]
}
}}
/>
</div>
</div>
);
};
export default Chart3;
the only difference is dataObject :
dataObj.intensity.forecast instead of dataObj.forecast
sandBox

using react-chartjs-2 , How can I save my chart as png using a download button

I'm trying to download my chart.js charts as png using a button Onclick, but I have no idea how I'm going to achieve this , I've went through this answer React-chartjs-2 Doughnut chart export to png but it wasn't quite clear enough for me as I'm quite new in chart.js don't know how I'm going to connect those variables with my button.
import React from 'react';
import { Component, useRef } from 'react';
import { Bar } from 'react-chartjs-2';
import 'chartjs-plugin-datalabels';
const data = {
labels: ['Finance & Business', 'Mining', 'Community Services', 'Electricity', 'Agriculture', 'Construction', 'Manufacture', "Trade & Tourism", "Transport & Logistics"],
datasets: [
{
label: 'My First dataset',
backgroundColor: ["#3283FC", "", "", "#00C0C8", "#C0BD00", "#3A46B1", "#00A150", "#FEB200", "#9302a1"],
borderWidth: 1,
hoverBackgroundColor: 'rgba(255,99,132,0.4)',
hoverBorderColor: 'rgba(255,99,132,1)',
data: [0.6, 0.0, 0.0, -0.1, -0.1, -0.3, -0.3, -0.6, -1.0],
}
]
};
class StackedBar extends Component {
render() {
return (
<div>
<h2>Bar Example (custom size)</h2>
<Bar
data={data}
options={{
plugins: {
datalabels: {
display: true,
color: '#fff'
}
},
title: {
display: true,
text: 'Contribution Percentage',
position: 'left'
},
maintainAspectRatio: true,
scales: {
xAxes: [{
stacked: true,
gridLines: {
borderDash: [2, 6],
color: "black"
},
scales: {
}
}],
yAxes: [{
ticks: {
beginAtZero: true,
steps: 0.5,
stepSize: 0.5,
max: 1.5,
min: -1.0
},
}]
},
}}
/>
</div>
);
}
}
export default StackedBar;
So I installed a plugin called FileSave.js //
npm install
npm i file-saver
import the plugin
import { saveAs } from 'file-saver';
than just write this blob function
class StackedBar extends Component {
saveCanvas() {
//save to png
const canvasSave = document.getElementById('stackD');
canvasSave.toBlob(function (blob) {
saveAs(blob, "testing.png")
})
}
render() {
return (
<div>
<a onClick={this.saveCanvas}>Download as PNG</a>
<Bar id="stackD" data={data} options={options} />
</div>
);
}
}
export default StackedBar;
another option is to use the chart ref, and then use the chart.js toBase64Image function. save this out as base64, convert to blob and save as a file using the file-saver package.
import { saveAs } from 'file-saver';
/**
* #param b64Data
* #param contentType
* #param sliceSize
* #returns {Blob}
* #link https://stackoverflow.com/questions/16245767/creating-a-blob-from-a-base64-string-in-javascript
*/
const b64toBlob = (b64Data, contentType = '', sliceSize = 512) => {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
// eslint-disable-next-line no-plusplus
for (let i = 0; i < slice.length; i += 1) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
return new Blob(byteArrays, { type: contentType });
};
... in component
const chartRef = useRef(null);
... in jsx...
<Button
onClick={() => {
const b64 = chartRef.current.toBase64Image().replace('data:image/png;base64,', '');
const content = b64toBlob(b64);
const file = new File([content], 'Revenue_chart.png', { type: 'image/png' });
saveAs(file);
}}
>
img
</Button>
<Line data={data} options={options} ref={chartRef} />

How to customize border style on React Chart.js 2

I am trying to add dashed border to my bar charts. I am following this example here- https://jsfiddle.net/jt100/ghksq1xv/3/
I am not getting much luck I have followed the instruction very carefully and passing in the correct values but I am not adding the dashed border to my bar chart. Any help will be very much appreciated
This is what I have done
1) passed in 4 arguments: my chart instance, dataset, data and dash
```
this.dashedBorder(myLineChart, 0, 2, [15, 10]);
2) This is my function.
dashedBorder(chart, dataset, data, dash) {
chart.config.data.datasets[dataset]._meta[0].data[data].draw = function() {
chart.chart.ctx.setLineDash(dash);
Chart.elements.Rectangle.prototype.draw.apply(this,
arguments,
);
};
}
3) my whole react component. You can see what I have done here.
import React, { PureComponent } from "react";
import classes from "./YourLineGraph.module.css";
import Chart from "chart.js";
let myLineChart;
let myChartRef;
let ctx;
//--Chart Style Options--//
// Chart.defaults.global.defaultFontFamily = "'PT Sans', sans-serif";
Chart.defaults.global.defaultFontFamily = "'Cooper Hewitt'";
Chart.defaults.global.legend.display = false;
Chart.defaults.global.elements.line.tension = 0;
Chart.defaults.global.scaleLineColor = "tranparent";
Chart.defaults.global.tooltipenabled = false;
//--Chart Style Options--//
export default class YourLineGraph extends PureComponent {
chartRef = React.createRef();
componentDidMount() {
this.buildChart();
}
componentDidUpdate() {
this.buildChart();
}
buildChart = () => {
myChartRef = this.chartRef.current.getContext("2d");
ctx = document.getElementById("myChart").getContext("2d");
const { data, average, labels, attribute } = this.props;
if (typeof myLineChart !== "undefined") myLineChart.destroy();
myLineChart = new Chart(myChartRef, {
type: "bar",
data: {
//Bring in data
labels:
labels.length === data.length
? labels
: new Array(data.length).fill("Data"),
datasets: [
{
label: "Sales",
data: data,
borderColor: "#98B9AB",
borderWidth: 3,
borderStyle: "dash" //has no effect
}
]
},
options: {
plugins: {
datalabels: {
formatter: function(value, context) {
return attribute === "pounds" ? `£ ${value}` : value;
},
anchor: "end",
align: "end",
color: "#888"
}
},
scales: {
yAxes: [
{
gridLines: {
drawBorder: false,
display: false
},
ticks: {
display: false //this will remove only the label
}
}
],
xAxes: [
{
gridLines: {
drawBorder: false,
display: false
},
ticks: {
display: false //this will remove only the label
}
}
]
}
}
});
this.dashedBorder(myLineChart, 0, 2, [15, 10]);
};
dashedBorder(chart, dataset, data, dash) {
chart.config.data.datasets[dataset]._meta[0].data[data].draw = function() {
chart.chart.ctx.setLineDash(dash);
Chart.elements.Rectangle.prototype.draw.apply(this, arguments);
chart.chart.ctx.setLineDash([1, 0]);
};
}
render() {
return (
<div className={classes.graphContainer}>
<canvas id="myChart" ref={this.chartRef} />
</div>
);
}
}

Resources