Image pointStyle doesn't load on initial chart render? - javascript

I want to load an image for one of the data points in a Scatter chart. The problem I have is the image doesn’t load on the initial page/chart render. Image only appears when you click/interact with the chart.
I am using react-chartjs-2, any suggestions would be appreciated.
I’ve tried the following (snippet)
import { Scatter, Chart } from "react-chartjs-2";
const chartReference = useRef();
const myImage = new Image(25, 35);
myImage.src = '/img/myimage.svg';
const chartData = {
datasets: [{
label: 'my Image',
data: [{ x: dummyData, y: 25 }],
pointStyle: myImage,
radius: 1,
pointRadius: 10,
borderWidth: 0,
type: 'line',
}],
}
return (
<Scatter
height={height}
width={width}
data={chartData}
options={options}
plugins={[Zoom]}
ref={chartReference}
redraw={true}
/>
I also through of this but where should do I place this?
chartReference.current.chartInstance.data.datasets[0].pointStyle = myImage;
chartReference.current.chartInstance.update();
If you manage to solve that I would like to ask a part 2 question that is the when you pan the chart unlike the built in data pointStyle the image goes off the y-axis. It only hide when at the charts actual width

It should work if you define the Image inside the component constructor...
constructor() {
super();
const myImage = new Image(25, 35);
myImage.src = "/img/myimage.svg";
and create the Scatter chart inside the render method.
render() {
return (
<div>
<Scatter
data={this.state.chartData }
options={this.state.chartOptions}
...
/>
</div>
);
}
Please have a look at this StackBlitz.

Related

React-chartjs-2 chart component doesn't refresh when hook state changes

I have this chart component which gets an address from its parent and it gets the chartData for that address from the hook useData. When a new address is passed in, the chart data does change but only the labels render for some reason. I'm wondering if there is a better way of doing this.
function Chart({ address }) {
const { labels, Data: chartData } = useData(address);
const data = (labels, chartData) => {
return {
labels: labels,
datasets: [
{
label: "Line 1",
data: chartData,
},
],
};
};
return <Bar id={address} data={data(labels, chartData)} redraw={true} />;
}

LightningChart JS crashes with t.toFixed is not a function

I am using a LightningChart JS by Arction to plot a bar graph and it keeps crashing after adding the rectangle figures with an error message: t.toFixed is not a function
The series being used is a rectangle series and I'd like to use only one rectangle series because I need them all under one group.
Below is my code
// Core react imports
import React, { useEffect, useCallback } from 'react'
// React bootstrap imports
import { Col } from "react-bootstrap"
// Chart imports
import {
lightningChart,
SolidFill,
SolidLine,
emptyTick,
emptyLine,
FontSettings,
ColorHEX,
} from "#arction/lcjs"
import axios from "axios"
export default function Histogram() {
const createChart = useCallback(
() => {
const chart = lightningChart().ChartXY({ containerId: "myplot" });
chart
.setTitle("RR Histogram")
.setTitleFillStyle((solidFill) => solidFill.setColor(ColorHEX("#000")))
.setTitleMarginTop(0)
.setTitleMarginBottom(0)
.setChartBackgroundFillStyle((solidFill) =>
solidFill.setColor(ColorHEX("#FFF"))
)
.setBackgroundFillStyle((solidFill) =>
solidFill.setColor(ColorHEX("#FFF"))
)
.setZoomingRectangleStrokeStyle(
new SolidLine({
fillStyle: new SolidFill({ color: ColorHEX("#000") }),
})
)
.setTitleFont(new FontSettings({ size: 20 }));
// Configure X-axis of chart to be progressive and have nice interval.
chart
.getDefaultAxisX();
// .setTickStyle(emptyTick)
// .setNibStyle(emptyLine)
// .setTitleFont(new FontSettings({ size: 12 }))
// .setStrokeStyle(emptyLine);
chart
.getDefaultAxisY();
// .setTickStyle(emptyTick)
// .setNibStyle(emptyLine)
// .setStrokeStyle(emptyLine);
let rectSeries = chart
.addRectangleSeries()
.setDefaultStyle(figure => figure.setFillStyle(new SolidFill({
color: ColorHEX("#000")
})));
let rr_hist = {};
axios
.get("Api url here")
.then((res) => {
console.log(res)
rr_hist = res.data;
})
.catch((err) => console.log(err));
setTimeout(() => {
for (let point in rr_hist) {
let insert_Point = {
height: rr_hist[point],
y: 0,
x: point,
width: 1
}
let bar = rectSeries.add(insert_Point);
bar.setDimensions(insert_Point);
bar.setFillStyle(new SolidFill({ color: ColorHEX("#000") }));
bar.setStrokeStyle(new SolidLine({
fillStyle: new SolidFill({ color: ColorHEX("#000") }),
}))
}
console.log(rr_hist)
}, 2000)
},
[],
)
useEffect(() => {
createChart()
}, [createChart])
return (
<Col xs={12} style={{ height: "100%", width: "100%" }}>
<div id="myplot" style={{ height: "100%", width: "100%" }}></div>
</Col>
)
}
Also could you please let me know how to improve the styling?
Most likely reason for the crash is that your height or x field for the new rectangle figure is not a number. LightningChart JS doesn't do type conversions for input values.
So when adding new rectangles to rectangle series make sure to do the type conversion from string to number yourself.
let insert_Point = {
height: Number(rr_hist[point]),
y: 0,
x: Number(point),
width: 1
}
let bar = rectSeries.add(insert_Point);
Instead of using Number for the conversion you could use parseFloat or parseInt depending on the type of data you use. See https://stackoverflow.com/a/13676265/6198227 that answer for more detailed differences between Number and parseFloat.
For styling, it looks like you would benefit from using a light colored theme. When creating the chart with ChartXY you can specify theme option.
const chart = lightningChart().ChartXY({
theme: Themes.light
})
You can see the available themes in our docs Themes

Accessing a slice of a react-chartjs Pie chart

I'm trying to create a static (non-clickable) Pie chart using react-chartjs-2.
However I want one of the slices to "pop out", or appear bigger than the others:
Hence, I'm trying to access one of the slices in the pie chart and modify its outerRadius property.
I've encountered multiple similar questions both in Stack Overflow and in Github, which helped me come up with this:
import { Pie } from 'react-chartjs-2';
<Pie
data={data}
options={options}
getElementsAtEvent={(elems) => {
// Modify the size of the clicked slice
elems[0]['_model'].outerRadius = 100;
}}
/>
However I didn't find anything about getting a slice to pop out without the user clicking it.
After looking under Pie component's hood, I ended up finding the answer.You can find it inside componentDidMount():
import React, { Component } from 'react';
import { Pie } from 'react-chartjs-2';
class PieChart extends Component {
componentDidMount() {
const change = {
sliceIndex: 0,
newOuterRadius: 100
}
const meta = this.pie.props.data.datasets[0]._meta;
meta[Object.keys(meta)[0]]
.data[change.sliceIndex]
._model
.outerRadius = change.newOuterRadius;
}
render() {
const data = {
type: 'pie',
datasets: [ { data: [10, 20, 30] } ],
labels: ['a', 'b', 'c'],
};
const options = {};
return <Pie
ref={(self) => this.pie = self}
data={data}
options={options}
/>
}
}
export default PieChart;
I have one more solution with version 4.3.1.
Try to add offset property into datasets.
import { Pie } from 'react-chartjs-2';
<Pie
data={
datasets: [
{
data: [1, 1],
borderColor: ['black', 'transparent'],
offset: [10, 0],
},
],
}
/>
It will render Pie with 2 segments. For the first segment, you will have black border and 10px offset

React-Vis Legend toggle filter for line chart

I am using react-vis and trying to implement a line chart with legends that can filter as shown on the first plot on top of this website: https://uber.github.io/react-vis/examples/showcases/plots
Basically when the legend item is clicked the whole series goes dim, along with the legend item.
I am guessing that I need to use onItemClick attribute in under Legends in https://uber.github.io/react-vis/documentation/api-reference/legends to change the opacity of the line, which I have successfully created
<LineSeries
data={data1}
opacity={1}
stroke="#f5222d"
strokeStyle="solid"
/>
I am not sure on how to proceed from here, building the function for onItemClick
Here is a simple example
import React from "react";
import {
XYPlot,
LineSeries,
DiscreteColorLegend
} from "react-vis";
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
series: [{
title: "Apples",
disabled: false,
data: [{ x: 0, y: 12 }, { x: 1, y: 22 }]
}]
};
}
clickHandler = (item, i) => {
const { series } = this.state;
series[0].disabled = !series[0].disabled;
this.setState({ series });
};
render() {
const { series } = this.state;
return (
<div>
<DiscreteColorLegend
onItemClick={this.clickHandler}
width={180}
items={series}
/>
<XYPlot height={200} width={200}>
<LineSeries
data={series[0].data}
opacity={series[0].disabled ? 0.2 : 1}
stroke="#f5222d"
strokeStyle="solid"
/>
</XYPlot>
</div>
);
}
}

ChartJS in React - changing dataset props doesn't change the view even when render method is triggered

I have a doughnut chart with static labels - what is changing, is only the data with values for labels. It's all about filtering data. But I have some weird issue and I can't figure out whats going on.
For example I've got something like this:
labels with hidden option set to true
I figure out that 'undefined' value in Array, makes item hidden so in case from picture it will be for example: [234, undefined, 21, undefined, 8].
Ok it's seems to be fine but when I use filter panel to change data in my application, and props with this Array of values is changing it's not rerendering label view, for example when I change array to [234, 100, 21, undefined, 8], label at position label1 should change 'hidden' property to false - it won't happening and I don't know why.
I paste here only render method, if u need to know something else please tell me:
render() {
const chartOptions = {
legend: {
display: true,
position: 'right',
labels: {
boxWidth: 12
}
}
};
const chartData =
[{
label: 'SomeLabel',
data: this.props.chartData.values,
yAxisId: 'yAxisA',
type: 'doughnut',
backgroundColor: ['#a3e1d4', '#dedede', '#9CC3DA', '#0475ad', '#f8ac59', '#ED5565', '#23c6c8', '#c2c2c2', '#1c84c6'],
}];
const title = (<h5>{this.props.title}</h5>);
const doughnutData = {
labels: this.props.chartData.labels,
datasets: chartData
};
const clonedDoughnutData = Object.assign({}, doughnutData);
const chart = (
<CustomDoughnut
data={clonedDoughnutData}
options={chartOptions}
height={150}
/>
);
const noData = (<NoData isDataVolume={false}/>);
const waveLoader = (<WaveLoader loading={this.props.loading}/>);
return (
<div>
<Tile
loading={this.props.overlayLoading}
title={title}
content={this.props.loading ? waveLoader : this.props.chartData.values.length > 0 ? chart : noData}
dynamicElementsService={this.props.dynamicElementsService}
parentView={this.props.parentView}
element={this.props.element}
status={this.props.status}
label={this.props.title}
/>
</div>
);
}
EDIT 1:
All calculations I make in other component, then I'm dispatching them to store, and then I'm getting them from store in parent component and I'm sending values as a props to component with the chart rendering.
This is how I'm handling proper values to labels:
const SomethingValues = [];
this.somethingLabels.forEach(element => {
if (analytics.chartData.Something.Map.get(element)) {
somethingValues.push(analytics.chartData.Something.Map.get(element));
} else {
somethingValues.push(undefined);
}
}
);

Categories

Resources