LightningChart JS crashes with t.toFixed is not a function - javascript

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

Related

Monaco editor prevent line decorations from expanding

My objective is to instantiate a Monaco editor line decoration that does not expand to the lower rows when I hit enter at the end of the created decoration.
For example, when I create a Monaco editor(in React) and instantiate a line decoration with the following code:
`js
import { createStyles } from "#mantine/styles";
import Editor from "#monaco-editor/react";
import monaco from "monaco-editor/esm/vs/editor/editor.api";
import { useRef, useState } from "react";
const DecoratedEditor = () => {
const { classes } = useStyles();
const [code, setCode] = useState(`#include <iostream>
using namespace std;
//press enter on my end to see decoration expand
int main() {
cout << "Hello World!";
return 0;
}`);
const editorRef = useRef<monaco.editor.IStandaloneCodeEditor | null>(null);
return (
<Editor
value={code}
language="cpp"
theme="vs-dark"
onChange={(newValue) => {
if (!newValue) return;
setCode(newValue);
}}
beforeMount={(monaco) => {}}
onMount={(editor, monaco) => {
editorRef.current = editor;
editor.getModel()?.deltaDecorations(
[],
[
{
range: new monaco.Range(4, 1, 4, 47),
options: {
inlineClassName: classes.lineDecoration,
},
},
]
);
}}
height={400}
/>
);
};
export default DecoratedEditor;
const useStyles = createStyles((theme) => {
return {
lineDecoration: {
width: "10px !important ",
backgroundColor: "rgb(255, 0, 0, 0.4)",
},
};
});
I get the following output: Normal editor with normal decoration
But, if I press "Enter" at the end of the decoration at line 4 and write on the following line I get this: New decoration
Is there a way to prevent the decoration from expanding itself? Thank you.
I already searched for options in Monaco editor documentation to prevent this from happening, but I didn't find out anythigh that could satisfy my needs.
I have been there.
It would help you get the job done as well.
That is
stickiness: 1
In you case, you can add one more option to the list.
options: {
inlineClassName: classes.lineDecoration,
stickiness: 1
}
stickness 1 is AlwaysGrowsWhenTypingAtEdges
/**
* Describes the behavior of decorations when typing/editing near their edges.
* Note: Please do not edit the values, as they very carefully match `DecorationRangeBehavior`
*/
export enum TrackedRangeStickiness {
AlwaysGrowsWhenTypingAtEdges = 0,
NeverGrowsWhenTypingAtEdges = 1,
GrowsOnlyWhenTypingBefore = 2,
GrowsOnlyWhenTypingAfter = 3
}
In case, a code snippet goes like this (you can use it as you would like) :
decorations = editor.deltaDecorations([],
[
{
range: new monaco.Range(1, 1, 4, 4),
options: {
stickiness: 1, // NeverGrowsWhenTypingAtEdges
}
}
])
}

SVG overlapping shapes with Recharts

I am using Recharts to create a simple pie chart.
My issue likely stems from the fact the entire thing is SVG-based.
I would like to have a selected pie slice change color (both fill and stroke).
So I do the following:
import { useState } from 'react';
import { Sector, Pie, PieChart, ResponsiveContainer } from 'recharts';
export function SinglePie({ data }) {
const [selectedCellLabel, setHighlightedCell] = useState(undefined);
const onMouseEnter = (event) => setHighlightedCell(event.payload.payload.label);
const onMouseLeave = () => setHighlightedCell(undefined);
function renderActiveShape(props) {
return <Sector {...props} fill="#CFBCF7" stroke="#7C53E4" />;
}
return (
<ResponsiveContainer width="100%" height="100%">
<PieChart>
<Pie
data={data}
activeIndex={data.findIndex((datum) => datum.label === selectedCellLabel)}
activeShape={renderActiveShape}
dataKey={ChartDataKeys.VALUE}
nameKey={ChartDataKeys.LABEL}
fill="#CEF1EE"
stroke="#64E0D5"
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
/>
</PieChart>
</ResponsiveContainer>
);
}
Then render with:
<div style={{ width: 250, height: 250 }}>
<SinglePie data={[
{
label: 'First Slice',
value: 4,
},
{
label: 'Second Slice',
value: 6,
},
{
label: 'Third Slice',
value: 2,
},
]} />
</div>
And unfortunately, on hovering the First Slice, what I see is this:
However, hovering the Third Slice looks ok:
You can see the difference between stroke width in the two cases. this is because the SVG slices overlap each other.
I know that SVG rendering is based on order, and adding a z prop won't help. But what will?
I would like to be able to see all slices with their strokes, as is required by my UI designer:
You can use .raise() function of d3 library.
First, you need to add <script src="https://d3js.org/d3.v7.min.js"></script> tag to your index.html.
And then you can move the selected slice to last in your onMouseEnter function like this:
const onMouseEnter = (event) => {
setHighlightedCell(event.payload.payload.label);
const selectedIndex = data.findIndex(
(datum) => datum.label === event.payload.payload.label
);
if (selectedIndex > -1) {
const gListItem = d3.select(
`.recharts-pie-sector:has(path[name="${event.payload.payload.label}"])`
);
gListItem.raise();
}
};
You can take a look at this stackblitz for a live working example of this solution.

get full Width of Labels Automatically in charts.js on Hover of DoNutChart

I am Using Charts.js Library for Displaying DoNutChart Chart.
Issue i am Facing is when i hover over the DoNutChart the label name is truncating not getting the complete width of the Labels
Js
import React from 'react';
import { Doughnut } from 'react-chartjs-2';
import { withStyles } from '#material-ui/core/styles';
import { Chart, registerables } from 'chart.js';
Chart.register(...registerables);
const style = (theme) => ({
donut: {
backgroundColor: '',
'& canvas': { zIndex: 999 }
}
});
const DoNutChart = ({
chartData = [],//Array of Objects is received here from Parent Component
keyValue,//gets the key name which need to be mapped from Parent Component
styles = {},
labels = [],//getting the array of label names from Parent Component
classes
}) => {
let data = {
labels: [...labels],
datasets: [
{
data: chartData.map((x) => x[keyValue]),
backgroundColor: [
'#008712',
'#6C5AE0',
'#6FB1F7',
'#ED4E78',
'#FFEE80'
],
borderColor: ['#008712', '#6C5AE0', '#6FB1F7', '#ED4E78', '#FFEE80'],
borderWidth: 1
}
]
};
let options = {
maintainAspectRatio: true,
scales: {
y: {
beginAtZero: true,
display: false
}
},
plugins: {
legend: {
display: false
}
}
};
return (
// <div style={{ ...(styles || {}) }}>
<div className={classes.donut}>
<Doughnut data={data} height={100} options={options} />
</div>
);
};
export default withStyles(style)(DoNutChart);
I have tried using this reference
Changing the z index of tooltip in chartjs-2
by increasing the z-index still i am not getting the expected result
Attached image of truncated label Names need the full Label Names
enter image description here

How to get onClick Event for a Label in ChartJS and React?

I have a Radar chart with labels, I want to have a click event on the Label of the Radar chart but the element always returns null. I have looked at other Stack over flow questions notedly
1 and this 2. one talks about doing it in vanilla JS approach and other one just is not working for me , Can some one point me to what am i doing wrong ?
End goal -> I want to get the label which is clicked and add a strike through toggle to that label so that i can toggle the data point on and off in the radar chart.
My Implementation
class Chart extends Component {
constructor(props) {
super(props);
this.state = {
chartData: props.chartData
};
}
render() {
return (
<div className="chart">
<Radar
data={this.state.chartData}
options={{
title: {
display: true,
text: "Testing",
fontSize: 25
},
legend: {
display: true,
position: "right"
},
onClick: function(evt, element) {
// onClickNot working element null
console.log(evt, element);
if (element.length > 0) {
console.log(element, element[0]._datasetInde);
// you can also get dataset of your selected element
console.log(data.datasets[element[0]._datasetIndex]);
}
}
}}
/>
</div>
);
}
}
**Link to the sample implementation **
Note: This answer implementation doesn't implement strikethrough. Strikethrough could be implemented by putting unicode character \u0366 between each character of the label string. Here's an example how do this with Javascript. The reason I'm not showcasing this here, is because it didn't really look that great when I tested it on codesandbox.
In a newer version of chart.js radial scale point label positions were exposed. In the example below I'm using chart.js version 3.2.0 and react-chartjs-2 version 3.0.3.
We can use the bounding box of each label and the clicked position to determine if we've clicked on a label.
I've used a ref on the chart to get access to the label data.
I've chosen to set the data value corresponding to a label to 0. I do this, because if you were to remove an element corresponding to a label, the label would disappear along with it. My choice probably makes more sense if you see it in action in the demo below.
const swapPreviousCurrent = (data) => {
const temp = data.currentValue;
data.currentValue = data.previousValue;
data.previousValue = temp;
};
class Chart extends Component {
constructor(props) {
super(props);
this.state = {
chartData: props.chartData
};
this.radarRef = {};
this.labelsStrikeThrough = props.chartData.datasets.map((dataset) => {
return dataset.data.map((d, dataIndex) => {
return {
data: {
previousValue: 0,
currentValue: d
},
label: {
previousValue: `${props.chartData.labels[dataIndex]} (x)`,
currentValue: props.chartData.labels[dataIndex]
}
};
});
});
}
render() {
return (
<div className="chart">
<Radar
ref={(radarRef) => (this.radarRef = radarRef)}
data={this.state.chartData}
options={{
title: {
display: true,
text: "Testing",
fontSize: 25
},
legend: {
display: true,
position: "right"
}
}}
getElementAtEvent={(element, event) => {
const clickX = event.nativeEvent.offsetX;
const clickY = event.nativeEvent.offsetY;
const scale = this.radarRef.scales.r;
const pointLabelItems = scale._pointLabelItems;
pointLabelItems.forEach((pointLabelItem, index) => {
if (
clickX >= pointLabelItem.left &&
clickX <= pointLabelItem.right &&
clickY >= pointLabelItem.top &&
clickY <= pointLabelItem.bottom
) {
// We've clicked inside the bounding box, swap labels and label data for each dataset
this.radarRef.data.datasets.forEach((dataset, datasetIndex) => {
swapPreviousCurrent(
this.labelsStrikeThrough[datasetIndex][index].data
);
swapPreviousCurrent(
this.labelsStrikeThrough[datasetIndex][index].label
);
this.radarRef.data.datasets[datasetIndex].data[
index
] = this.labelsStrikeThrough[datasetIndex][
index
].data.previousValue;
this.radarRef.data.labels[index] = this.labelsStrikeThrough[
datasetIndex
][index].label.previousValue;
});
// labels and data have been changed, update the graph
this.radarRef.update();
}
});
}}
/>
</div>
);
}
}
So I use the ref on the chart to get acces to the label positions and I use the event of getElementAtEvent to get the clicked x and y positions using event.nativeEvent.offsetX and event.nativeEvent.offsetY.
When we've clicked on the label I've chosen to update the value of the ref and swap the label data value between 0 and its actual value. I swap the label itself between itself and itself concatenated with '(x)'.
sandbox example
The reason I'm not using state here is because I don't want to rerender the chart when the label data updates.
You could run a function that modifies your dataset:
You would create the function where you have your data set
chartClick(index) {
console.log(index);
//this.setState({}) Modify your datasets properties
}
Pass the function as props
<Chart chartClick={this.chartClick} chartData={this.state.chartData} />
Execute the function when clicked
onClick: (e, element) => {
if (element.length) {
this.props.chartClick(element[0]._datasetIndex);
}
}

TypeError: this.querySelectorAll is not a function while using D3Funnel in react js

I am using d3funnel in my react application (which is based on typescript) and I keep getting the error of TypeError: this.querySelectorAll is not a function. And, I don't understand why it is happening. Here is a sample code of mine:
import * as React from 'react'
import * as D3Funnel from 'd3-funnel'
import * as d3 from "d3";
const FunnelChart: React.FC = () => {
const Ref = React.useRef(null)
var data = [
['Applicants', 267 , '#1e4684', '#1e4684'],
['Interviews', 134, '#1e4684'],
['Assessments', 48, '#1e4684'],
['Hired',26, '#1e4684']
];
var options = {
width : 200,
height : 400,
bottomWidth : 1/2,
bottomPinch : 0, // How many sections to pinch
isCurved : true, // Whether the funnel is curved
curveHeight : 10, // The curvature amount
fillType : "gradient", // Either "solid" or "gradient"
isInverted : false, // Whether the funnel is inverted
hoverEffects : true, // Whether the funnel has effects on hover
fontSize : '18px'
};
React.useEffect(() => {
var funnel = new D3Funnel( data, options );
funnel.draw (d3.select(Ref.current));
}, [])
return (
<>
<div ref = {Ref}>
</div>
</>
)
} `
I really appreciate any help.
Edit: Here is the error:
react-dom.development.min.js:1 Uncaught TypeError: this.querySelectorAll is not a function at Array.__webpack_exports__.default (d3-funnel.js?f3d7:2417) at Selection.eval [as selectAll] (d3-funnel.js?f3d7:2395) at D3Funnel.destroy (d3-funnel.js?f3d7:194) at D3Funnel.draw (d3-funnel.js?f3d7:217) at eval (index.tsx?21e5:57) at Sg (react-dom.development.min.js:1) at Eg (react-dom.development.min.js:1) at HTMLUnknownElement.e (react-dom.development.min.js:1) at at g (react-dom.development.min.js:1)
you need to pass ref.current to D3Funnel while initializing it and data & option as parameter of draw function.
Here's the solution
import React, { useRef, useEffect } from "react";
import D3Funnel from "d3-funnel";
export default function App() {
const chartRef = useRef(null);
var data = [
{ label: "Teal", value: 12000, backgroundColor: "#008080" },
{ label: "Byzantium", value: 4000, backgroundColor: "#702963" },
{ label: "Persimmon", value: 2500, backgroundColor: "#ff634d" },
{ label: "Azure", value: 1500, backgroundColor: "#007fff" }
];
var options = {
width: 200,
height: 400,
bottomWidth: 1 / 2,
bottomPinch: 2, // How many sections to pinch
isCurved: true, // Whether the funnel is curved
curveHeight: 10, // The curvature amount
fillType: "gradient", // Either "solid" or "gradient"
isInverted: true, // Whether the funnel is inverted
hoverEffects: true, // Whether the funnel has effects on hover
fontSize: "18px",
label: {
format: "{l}\n{f}"
}
};
useEffect(() => {
const chart = new D3Funnel(chartRef.current);
console.log(chart);
chart.draw(data, options);
}, []);
return <div className="App" ref={chartRef}></div>;
}

Categories

Resources