The highcharts render fine in browser without error, but when running test on the component, I got test failing:
● renders correctly
Highcharts error #13: www.highcharts.com/errors/13
22 |
23 | highChartsRender(options) {
> 24 | Highcharts.chart(this.props.id,{
| ^
25 | chart: {
26 | type: "line",
27 | renderTo: "lineChart",
and in my HCLineChart.test.js file, I have this:
it('renders correctly', () => {
const tree = TestRenderer
.create(<HCLineChart title={title} options={options} id={"LineChart1"} />)
.toJSON();
expect(tree).toMatchSnapshot();
});
and then in my HCLineChart.js file, I have this:
import React from "react";
import Highcharts from "highcharts";
import HC_exporting from "highcharts/modules/exporting";
import HC_exporting_data from "highcharts/modules/export-data";
import PropTypes from "prop-types";
class HCLineChart extends React.Component {
constructor(props){
super(props);
HC_exporting(Highcharts);
HC_exporting_data(Highcharts);
}
componentDidMount() {
this.highChartsRender(this.props.options);
}
shouldComponentUpdate(nextProps) {
this.highChartsRender(nextProps.options);
return false;
}
highChartsRender(options) {
Highcharts.chart(this.props.id,{
chart: {
type: "line",
renderTo: "lineChart",
height: 500,
},
title: {
text: this.props.title,
},
xAxis: {
categories: options.xAxisCategories,
},
yAxis: {
title: {
text: this.props.title,
},
},
plotOptions: {
series: {
marker: {
enabled: false,
},
},
},
credits:{
enabled: false,
},
exporting: {
buttons: {
contextButton: {
enabled: true,
menuItems: [
"printChart",
"downloadCSV",
"downloadXLS",
],
},
},
},
series: options.data,
});
Highcharts.setOptions({
lang: {
thousandsSep: ",",
},
});
}
render() {
return <div className="line-chart" id={this.props.id} />;
}
}
export default HCLineChart;
So why I got the error only in testing? I saw the div already there before calling the Highchart.chart ?
Thank you.
Lei
Related
I am using React ApexChart in order to show off some data, and I have a switch that shows and hides the data labels. The options are changing without problems, but the zoom level is resetting every time. Is there a way to keep the zoom level when changing the options?
Here is a small preview of the component:
import Chart from "react-apexcharts";
import React, { useEffect, useState } from 'react';
import { Layout } from "antd";
interface Props {
series?: ApexAxisChartSeries;
chartOptiosn?: Record<string, any>;
[ key: string ]: any;
}
export const DynamicChart: React.FC<Props> = React.memo( ( props: Props ) => {
const { Content } = Layout;
const { series, chartOptions, uuid } = props;
const [ initialRerender, setInitialRerender ] = useState( false );
useEffect( () => {
if ( !initialRerender ) {
setInitialRerender( true );
}
}, [ initialRerender ] );
useEffect( () => {
}, [] );
useEffect( () => {
console.log( chartOptions );
}, [ chartOptions ] );
return (
<Layout>
<Content>
<Chart
options={ { ...structuredClone( chartOptions || {} ), chart: { ...chartOptions.chart, id: uuid } } }
series={ series }
type="area"
height={ 350 }
/>
</Content>
</Layout>
);
} );
Here are the options:
export const defaultOptions: ApexCharts.ApexOptions = {
series: [],
chart: {
animations: {
enabled: true,
easing: "linear",
dynamicAnimation: {
speed: 300
}
},
toolbar: {
show: true,
tools: {
download: `<svg viewBox="64 64 896 896" focusable: "false" name= "download" theme="outlined"><path d="M505.7 661a8 8 0 0012.6 0l112-141.7c4.1-5.2.4-12.9-6.3-12.9h-74.1V168c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v338.3H400c-6.7 0-10.4 7.7-6.3 12.9l112 141.8zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg>`,
selection: false,
zoom: true,
zoomin: true,
zoomout: true,
pan: true,
customIcons: []
},
},
zoom: {
enabled: true
}
},
dataLabels: {
enabled: false
},
yaxis: {
labels: {
style: {
fontSize: "14px",
fontWeight: 600,
colors: [ "#8c8c8c" ],
},
},
},
xaxis: {
type: "datetime"
}
};
Here is a demo for more depth of the problem that I am facing.
Just zoom in between the 3 seconds interval and after the labels reappear, the zoom is refreshed. Is there a way to stop that in react, or should I seek a vanilla approach and ditch the react solution all together?
I am working on react application where I have used react google charts for displaying Line chart with annotation. But I am getting an issue with role attribute for column in Line chart, have already imported react-google-charts in the working component. Below is my code:
Home.tsx > component
import * as React from 'react';
import { Chart } from 'react-google-charts';
import GoogleDataTableColumnRoleType from 'react-google-charts/dist/types';
export class Home extends React.Component<IChildComponentProps,AddDataState> {
constructor(props) {
super(props);
public render() {
<div id="chart_div2">
<Chart
width={400}
height={'300px'}
chartType="LineChart"
loader={<div>Loading Chart</div>}
rows={this.state.o3TargetChart}
columns={[
{
type: "string",
label: "Week"
},
{
type: "number",
label: "O3Done"
},
{
type: "string",
role: GoogleDataTableColumnRoleType.annotation // getting error here
},
{
type: "number",
label: "Target"
}
]}
options={{
title: '',
hAxis: {
title: 'Week', titleTextStyle: {
},
baselineColor: '#cccccc'
},
vAxis: {
title: 'O3 Coverage ( in %)', minValue: 0, maxValue: 100, titleTextStyle: {
},
baselineColor: '#cccccc',
},
pointsVisible: true,
chartArea: {
left: 100
},
height: 400,
width: 1000,
}}
/>
</div>
}
}
Although I can find the type module under node_modules directory as below:
node_modules\react-google-charts\dist\types.d.ts
Have already added below code in webpack.config.js file as suggested by others:
resolve: {
extensions: ['', '.js', '.jsx']
},
Still I am getting module not found error. Please suggest..
I am using react apex chart to create a chart that will display the average response time for each agent.
I have managed to get the result in a timestamp format but i am unable to convert that into hours, minutes and seconds to display that in yaxis, i have checked the documentation docs link but they are giving examples for date time only.
here is the result that i am getting with the component bellow
import React, { useState } from 'react';
import Chart from 'react-apexcharts';
const AvgResponseTimeChart = (props) => {
const { prod_data } = props;
const [ data, setData ] = useState([
{
x: 'Agent one',
y: 1589670005
},
{
x: 'Agent one',
y: 1589670307
}
]);
const [ series, setSeries ] = useState([ { data } ]);
const [ options, setOptions ] = useState({
chart: {
type: 'bar',
height: 350
},
plotOptions: {
bar: {
horizontal: false,
columnWidth: '25%',
endingShape: 'rounded'
}
},
dataLabels: {
enabled: false
},
stroke: {
show: true,
width: 2,
colors: [ 'transparent' ]
},
xaxis: {
type: 'category'
},
yaxis: {
labels: {
datetimeFormatter: {
formatter: function(value, timestamp) {
return new Date(timestamp).toLocaleTimeString();
}
}
}
},
fill: {
opacity: 1
},
tooltip: {
y: {
formatter: function(value, timestamp) {
return new Date(timestamp);
}
}
}
});
return (
<div id="chart">
<Chart options={options} series={series} type="bar" height={350} />
</div>
);
};
export default AvgResponseTimeChart;
I have searched for similar issues without success if, someone can help me with that i will be really grateful
Try to add lables to yaxis in chartOptions this way:
labels: {
show: true,
formatter: (val) => { return new Date(val); }
}
And remove the tooltip as well.
Trying to bring up a highchart using react. I am having multiple fetch api calls(for illustration, I have added only 2) whose data I will be using to render something in the UI.
In this example data1 is used to render a table, data2 is used to render a highchart.
I am storing the outputs of these calls in a state object. When I am calling these API's, I am getting the data but unable to set it to "series" property of highcharts for rendering, as a result nothing is getting rendered.
Structure of the data I am fetching
"api2" : [
{
"name" : "Test1",
"value" : 12
},
{
"name" : "Test2",
"value" : 9
}
]
Can someone help me with this? Where am I going wrong?
I am using highcharts-react-official for this
Code
import * as React from 'react';
import Highcharts from 'highcharts'
import HighchartsReact from 'highcharts-react-official';
interface IState {
data1: [];
data2: [];
}
interface IProps {}
class Example extends React.Component<IProps,IState> {
constructor(props:any)
{
super(props);
this.state = {
data1: [],
data2: []
}
}
componentDidMount()
{
Promise.all([
fetch('http://localhost:3001/api1'),
fetch('http://localhost:3001/api2')
])
.then(([res1, res2]) => Promise.all([res1.json(), res2.json()]))
.then(([data1, data2]) => this.setState({
data1: data1,
data2: data2
}));
}
render() {
let options:any;
options = {
chart: {
type: 'column'
},
credits: false,
exporting: {enabled: false},
title: {
text: ''
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'bottom'
},
xAxis: {
visible:false
},
yAxis: {
visible:false
},
plotOptions: {
column: {
dataLabels: {
enabled: true }
}
},
series: this.state.data2
};
return(
<div className="an-content">
//some table rendering will happen here
<HighchartsReact
highcharts={Highcharts}
options={options}
/>
</div>
)
}
}
export default Example;
You need to provide the data format required by Highcharts:
this.setState({
data2: data2.map(x => ({ name: x.name, data: [x.value] }))
});
Live demo: https://codesandbox.io/s/7w2pw4p900
API Reference: https://api.highcharts.com/highcharts/series.column.data
I am trying to use use Cytoscape with ReactJS and some how nothing is getting displayed in the simple component i am trying.
Here is the code. I am returning an empty object in mapStateToProps as i am trying to display a static graph where i have hard coded the edges and nodes.
Cytoscape version i am using is from my package.json
"cytoscape": "^2.7.6",
"react": "^15.2.1",
Here is the Cyctoscape jsbin i am using for my sample.
enter link description here
Appreciate any help.
Thanks
import React,{Component} from 'react';
import cytoscape from 'cytoscape';
import {connect} from 'react-redux';
import { bindActionCreators } from 'redux';
class GraphContainer extends React.Component{
constructor(props){
super(props);
this.renderCytoscapeElement = this.renderCytoscapeElement.bind(this);
}
renderCytoscapeElement(){
console.log('* Cytoscape.js is rendering the graph..');
this.cy = cytoscape(
{
container: document.getElementById('cy'),
boxSelectionEnabled: false,
autounselectify: true,
style: cytoscape.stylesheet()
.selector('node')
.css({
'height': 80,
'width': 80,
'background-fit': 'cover',
'border-color': '#000',
'border-width': 3,
'border-opacity': 0.5,
'content': 'data(name)',
'text-valign': 'center',
})
.selector('edge')
.css({
'width': 6,
'target-arrow-shape': 'triangle',
'line-color': '#ffaaaa',
'target-arrow-color': '#ffaaaa',
'curve-style': 'bezier'
})
,
elements: {
nodes: [
{ data: { id: 'cat' } },
{ data: { id: 'bird' } },
{ data: { id: 'ladybug' } },
{ data: { id: 'aphid' } },
{ data: { id: 'rose' } },
{ data: { id: 'grasshopper' } },
{ data: { id: 'plant' } },
{ data: { id: 'wheat' } }
],
edges: [
{ data: { source: 'cat', target: 'bird' } },
{ data: { source: 'bird', target: 'ladybug' } },
{ data: { source: 'bird', target: 'grasshopper' } },
{ data: { source: 'grasshopper', target: 'plant' } },
{ data: { source: 'grasshopper', target: 'wheat' } },
{ data: { source: 'ladybug', target: 'aphid' } },
{ data: { source: 'aphid', target: 'rose' } }
]
},
layout: {
name: 'breadthfirst',
directed: true,
padding: 10
}
});
}
componentDidMount(){
this.renderCytoscapeElement();
}
render(){
return(
<div className="node_selected">
<div style="{height:'400px';width:'400px'}" id="cy"/>
</div>
)
}
}
function mapStateToProps(state){
return {};
}
export default connect(mapStateToProps,null)(GraphContainer);
For those still looking for how to get the code posted working - I was able to get it working by modifying the cy div, specifying its style with non-zero height and width.
render() {
let cyStyle = {
height: '1000px',
width: '1000px',
margin: '20px 0px'
};
return (
<div>
<div style={cyStyle} id="cy"/>
</div>
);
}
I had to integrate cytoscape.js with react as well, but no redux, so wrote a gist in case anybody else needs it.
code example
I am able to resolve the Issue. I missed the Styles for the Layer itself and hence it is defaulting to 0px height and 0px width.
Thanks
For a basic version of the above using the cytoscape "Getting Started" example and using React hooks you can do this:
import React, {Fragment, useEffect, useRef} from 'react';
import cytoscape from 'cytoscape'
const GraphTest = () => {
const graphRef = useRef(null)
const drawGraph = () => {
const cy = cytoscape({
container: graphRef.current,
elements: [
{ data: { id: 'a' } },
{ data: { id: 'b' } },
{
data: {
id: 'ab',
source: 'a',
target: 'b'
}
}]
})
}
useEffect(() => {
drawGraph()
}, [])
return (
<Fragment>
<h2>Graph Test</h2>
<div ref={graphRef} style={{width: '100%', height: '80vh'}}>
</div>
</Fragment>
)
}
export default GraphTest