I am trying to integrate highcarts inside the react component.
Here is my code for the react component
import * as Highcharts from 'highcharts/highmaps'
class RealTime extends Component {
componentDidMount() {
$.getJSON( 'https://cdn.jsdelivr.net/gh/highcharts/highcharts#v7.0.0/samples/data/world-population-density.json',
function(data) {
$.each(data, function() {
this.value = this.value < 1 ? 1 : this.value
})
Highcharts.mapChart('world_map', {
chart: {
map: 'custom/world'
},
title: {
text: 'Fixed tooltip with HTML'
},
legend: {
title: {
text: 'Population density per kmĀ²',
style: {
color:
(Highcharts.theme && Highcharts.theme.textColor) || 'black'
}
}
},
mapNavigation: {
enabled: true,
buttonOptions: {
verticalAlign: 'bottom'
}
},
series: [
{
data: data,
mapData: Highcharts.maps['custom/world'],
joinBy: ['iso-a3', 'code3'],
name: 'Population density',
states: {
hover: {
color: '#a4edba'
}
}
}
]
})
}
)
}
render() {
return (
<div>
<div className="map_bg" id="world_map"/>
</div>
)
}
}
But the above code does not show either the map or any error in my react component . Can Anyone please help me
What i am missing here?
Thank you!!!
You need to add and import the word.js script:
import Highcharts from "highcharts/highmaps";
import customWord from "./word.js";
Live demo: https://codesandbox.io/s/v0x5zx6q05
Also, I can recommend you to use highcharts-react-official wrapper: https://www.npmjs.com/package/highcharts-react-official
Related
I'm using Vue Chart JS v3.5.1 in my Nuxt JS/Vue project, and I've noticed that when trying to use options and pass them as a prop, nothing happens, the chart defaults back to the chart's default settings despite me overwriting settings.
I've got several files:
plugins/LineChart.js
components/LineChart.vue
plugins/LineChart.js
import { Line, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins
export default {
extends: Line,
mixins: [reactiveProp],
computed: {
localOptions: function() {
return this.chartOptions
},
localData: function() {
console.log(`data: ${this.chartData}`)
return this.chartData
}
},
mounted () {
this.renderLineChart()
},
methods: {
/*
** Render a line chart
*/
renderLineChart () {
// this.chartdata is created in the mixin.
// If you want to pass options please create a local options object
this.renderChart(this.localData, this.localOptions)
}
},
watch: {
chartData: {
handler: function (val, oldVal) {
this._data._chart.destroy()
this.renderLineChart()
},
deep: true
},
chartOptions: {
handler: function (val, oldVal) {
this.localOptions = val
},
deep: true
}
}
}
components/LineChart.vue
<template>
<div>
<line-chart :chart-data="customChartData" :chart-options="customChartOptions" class="data-chart"></line-chart>
</div>
</template>
<style>
.data-chart canvas {
width: 100% !important;
height: auto !important;
}
</style>
<script>
import LineChart from '~/plugins/LineChart.js'
export default {
components: {
LineChart
},
props: {
labels: {
type: Array,
default: null
},
datasets: {
type: Array,
default: null
},
options: {
type: Object,
default: () => ({})
}
},
data () {
return {
customChartData: {},
customChartOptions: {}
}
},
mounted () {
this.fillData()
},
methods: {
fillData () {
this.customChartData = {
labels: this.labels,
datasets: this.datasets
}
this.customChartOptions = {
options: this.options
}
}
}
}
</script>
My usage, is then reasonably simple, yet I'm not getting my options to show?
<LineChart
:options="{
responsive: true,
maintainAspectRatio: false,
legend: {
display: false
},
scales: {
xAxes: [{
gridLines: {
display: false
},
ticks: {
autoSkip: true,
maxTicksLimit: 3,
maxRotation: 0,
minRotation: 0
}
}],
yAxes: [{
display: true,
gridLines: {
display: true,
color: '#f3f5f6'
}
}]
},
elements: {
point: {
radius: 0,
hitRadius: 35
}
}
}"
:labels="['test']"
:datasets="[{
fill: false,
borderWidth: 2.5,
pointBackgroundColor: '#fff',
borderColor: '#5046e5',
data: [500,
}]"
/>
What am I doing wrong?
UPDATE
In addition, I seem to only have the first chart out of many charts on the page show data, why would only one chart in a series of charts show data, I've got a key on each one.
in your fillData it looks like you assign the options wrong. Vue Chartjs expects an object with the options in it and not an object with an field options with the options.
If you change: this.customChartOptions = {options: this.options} to: this.customChartOptions = this.options it should work
I want to have three LineCharts below each other. They are sharing same x-axis (time). I was able to create this:
However, it is very useless to have x-axis on the top and middle chart. I would prefer not to display the x-axis for the top and middle. When I tried it, I got this:
But as you can see, the last grid for 12AM is not visible for the top and middle chart, and the grids are not aligned (it looks weird). Each chart is rendered as a separate component using React.
Here are my TimelinePlot component which is rendering each LineChart (sorry for the mess, but I did not yet refactor it):
import React from 'react';
import { Line } from 'react-chartjs-2';
import { GetColors } from '../../utils/PlotDescriptionHelper';
class TimelinePlot extends React.Component {
MapPropsToData(props) {
const colors = GetColors(props.series.length);
return props.series.map((dataset, index) => {
return {
label: dataset.name,
data: dataset.data,
borderWidth: 1,
fill: false,
borderColor: colors[index],
//pointBackgroundColor: 'rgb(255,255,255)',
};
});
}
MapPropsToOptions(props) {
return {
elements: {
point: {
radius: 0,
},
},
legend: {
// display: props.showLegend,
position: 'top',
align: 'end',
},
scales: {
yAxes: [
{
ticks: props.yAxisTicks,
scaleLabel: {
display: true,
labelString: props.yAxisName + props.yAxisUnit,
},
},
],
xAxes: [
{
type: 'time',
// position: props.xAxisPosition,
time: {
parser: 'YYYY-MM-DD HH:mm',
tooltipFormat: 'll HH:mm',
},
// scaleLabel: {
// display: true,
// //labelString: 'Date',
// },
ticks: {
min: props.xAxisStart,
max: props.xAxisEnd,
//display: true,
display: props.xAxisDisplay,
},
},
],
},
};
}
render() {
const dataset = { datasets: this.MapPropsToData(this.props) };
return (
<div className='measurement-row'>
<Line
data={dataset}
options={this.MapPropsToOptions(this.props)}
position='absolute'
height='15%'
width='80%'
/>
</div>
);
}
}
And here is the render method of the parent using TimelinePlot component:
render() {
var plots = Object.keys(this.state.timeSeries).map((key, index) => {
return (
<TimelinePlot
key={key + index}
series={this.state.timeSeries[key]}
yAxisName={FirstLetterToUpper(key)}
yAxisUnit={MapKeyToUnit(key)}
xAxisDisplay={index === Object.keys(this.state.timeSeries).length - 1}
xAxisPosition={index === 0 ? 'top' : 'bottom'}
xAxisStart={this.state.startTime}
xAxisEnd={this.state.endTime}
showLegend={index === 0}
yAxisTicks={MapYAxisTicks(key)}
/>
);
});
return (
<div className='width-90'>
<TimelineDashboardHeader />
<div className='dashboard__column'>{plots}</div>
</div>
);
}
For the past couple days, I was struggling to use this highchart map type in my react project
https://jsfiddle.net/26tbkjov//
Can some one please help me out?
Please check what I achieved until now:
https://codesandbox.io/s/highcharts-react-demo-0m5ux
I am using those highcharts npm packages
"highcharts": "^7.1.2",
"highcharts-react-official": "^2.2.2",
I have tried many things and ended up in a dead path.. the following is the last thing i have tried:
import React from "react";
import mapData from '../../api/mapData';
import Highcharts from 'highcharts';
import HighchartsReact from 'highcharts-react-official';
require('highcharts/modules/map')(Highcharts);
class MyMap extends React.Component {
constructor(props) {
super(props);
this.state = {
mapValues: [],
modalClassic: false,
};
this.mapData = new mapData();
// preparing the config of map with empty data
this.options = {
title: {
text: 'Widget click by location',
style: {
color: '#fff'
},
},
chart:{
backgroundColor: 'transparent',
type: 'map',
map: null,
},
mapNavigation: {
enabled: true,
enableButtons: false
},
credits: {
enabled: false
},
colorAxis: {
dataClasses: [
{
from: 1,
color: '#C40401',
name: 'widget name one'
}, {
from: 2,
color: '#0200D0',
name: 'widget name two'
}
]
},
tooltip: {
pointFormatter: function() {
return this.name;
}
},
legend: {
align: 'right',
verticalAlign: 'top',
x: -100,
y: 70,
floating: true,
layout: 'vertical',
valueDecimals: 0,
backgroundColor: ( // theme
Highcharts.defaultOptions &&
Highcharts.defaultOptions.legend &&
Highcharts.defaultOptions.legend.backgroundColor
) || 'rgba(255, 255, 255, 0.85)'
},
series: [{
name: 'world map',
dataLabels: {
enabled: true,
color: '#FFFFFF',
format: '{point.postal-code}',
style: {
textTransform: 'uppercase'
}
},
tooltip: {
ySuffix: ' %'
},
cursor: 'pointer',
joinBy: 'postal-code',
data: [],
point: {
events: {
click: function(r){
console.log('click - to open popup as 2nd step');
console.log(r);
}
}
}
}]
};
}
/*
* Before mounting the component,
* update the highchart map options with the needed map data and series data
* */
componentWillMount = () => {
this.mapData.getWorld().then((r)=>{
this.setState({'mapData': r.data}, ()=>{
this.options.series[0].data = []; //make sure data is empty before fill
this.options['chart']['map'] = this.state.mapData; // set the map data of the graph (using the world graph)
// filling up some dummy data with values 1 and 2
for(let i in this.state.mapData['features']){
let mapInfo = this.state.mapData['features'][i];
if (mapInfo['id']) {
var postalCode = mapInfo['id'];
var name = mapInfo['properties']['name'];
var value = i%2 + 1;
var type = (value === 1)? "widget name one" : "widget name two";
var row = i;
this.options.series[0].data.push({
value: value,
name: name,
'postal-code': postalCode,
row: row
});
}
}
// updating the map options
this.setState({mapOptions: this.options});
});
});
}
render() {
return (
<div>
{(this.state.mapData)?
<HighchartsReact
highcharts={Highcharts}
constructorType={'mapChart'}
options={(this.state.mapOptions)? this.state.mapOptions: this.options}
/>
: ''}
</div>
);
}
}
export default MyMap;
If you want to use the USA map, you need to change the url to: "https://code.highcharts.com/mapdata/countries/us/us-all.geo.json" and the postal-code from US.MA to MA:
this.mapData.getWorld().then(r => {
...
for (let i in this.state.mapData["features"]) {
...
var postalCode = mapInfo.properties["postal-code"];
...
}
...
});
Live demo: https://codesandbox.io/s/highcharts-react-demo-jmu5h
To use the word map, you need to also change the part related with the postal-code and joinBy property:
series: [{
joinBy: ['iso-a2', 'code'],
...
}]
this.mapData.getWorld().then(r => {
...
for (let i in this.state.mapData["features"]) {
let mapInfo = this.state.mapData["features"][i];
if (mapInfo["id"]) {
var code = mapInfo["id"];
...
this.options.series[0].data.push({
"code": code,
...
});
}
}
...
});
Live demo: https://codesandbox.io/s/highcharts-react-demo-sxfr2
API Reference: https://api.highcharts.com/highmaps/series.map.joinBy
Building with React... Trying to use outside method called on button click
Attempting to set mappoints to invisible. I have tried using:
.hide()
.setVisible
and using .update() to set 'visible' to false
I am able to reference the chart and the mappoint using the included definition in the package markdown:
let chart = this.refs.chart.getChart();
and in my render:
<ReactHighmaps config={config} ref="chart" />
Attempted:
chart.series[2].event.update({visible: false}) >> Error: Highchart.js:27 Uncaught TypeError: Cannot read property 'update' of
undefined
chart.plotOptions.mappoint.events.hide() >> TypeError: Cannot read property 'mappoint' of undefined
chart.series[2].setVisible(false, true) >> No Error in Console but nothing happens
chart.series[2].hide() >> No Error in Console but nothing happens And a few other variations.
ReactHighmaps.Highcharts.hide(chart.series[0]) >> Error that this isn't a function
There is a lot going on for me to make a JSbin...
Testing in Chrome
When I am inspecting the console.log of the mappoints I see that the method .setVisible() project path is:
.proto.proto.proto.setVisible
chart configuration (options):
const config = {
title: {
text: 'ZCTA with Metric Data'
},
chart: {
height: '600 px',
borderWidth: 1,
borderColor: 'silver',
borderRadius: 3,
shadow: true
},
mapNavigation: {
enabled: true
},
tooltip: {
enabled: false
},
plotOptions: {
map: {
showInLegend: false
},
mappoint: {
showInLegend: false,
},
mapline: {
enabledMouseTracking: false,
showInLegend: false
}
},
series: [{
mapData: MapData,
name: 'test',
data: County,
joinBy: ['fips', 'code'],
animation: true,
tooltip: {
pointFormat: '<b>{point.name}</b>'
},
borderColor: 'black',
borderWidth: 0.2,
states: {
hover: {
borderWidth: 0.5
},
select: {
color: 'yellow'
}
},
allowPointSelect: true,
cursor: 'pointer'
},
{
type: 'mapline',
name: 'State borders',
data: lines,
color: 'black',
states: {
hover: {
borderWidth: 0.5
}
},
allowPointSelect: false
},
{
type: 'mappoint',
name: 'zcta',
color: Highcharts.getOptions().colors[1],
data: Data,
boostThreshold: 500,
}]
For component render:
<ReactHighmaps config={config} ref="chart" />
Any suggestions?
Using React, Highcharts, and React-Highcharts (npm)
I was unable to get any Highcharts(Highmaps) API methods to work, but was able to drill down to update the state object.
This led me to Redux as a state management tool because I realize it would be better to have this controlled in an application state versus React component.
Here is my action and reducer:
export const SHOW_POINTS = 'SHOW_POINTS'
export function showPoints(configuration){
return {
type: SHOW_POINTS,
payload: configuration
};
}
const PointsMapConfig = (state = initialState, action) => {
switch (action.type){
case SHOW_POINTS:
return console.log(state.mapConfig.series[2]), { ...state,
mapConfig: {
series: [
...state.mapConfig.series.filter((el, index) => index !== 2), {
...state.mapConfig.series[2],
visible: true
}
]
}
}
default:
return state;
}
}
export default PointsMapConfig
onClick access with mapDispatchToProps:
function mapDispatchToProps(dispatch){
return bindActionCreators({
showPoints: showPoints
}, dispatch);
}
<Buttons style="success" classN="btn btn-secondary" text="test" onButtonClick={()=> this.props.showPoints( )} />
I am a newbie to React, Highcharts and UI developing in general.
I would like to render multiple charts from an array of data. Currently, the page displays only the last chart - from the last data in the array.
function chartToRender(seriesArr){
//console.log(JSON.stringify(application));
var Chart = React.createClass({
// When the DOM is ready, create the chart.
componentDidMount: function() {
// Extend Highcharts with modules
if (this.props.modules) {
this.props.modules.forEach(function(module) {
module(Highcharts);
});
}
// Set container which the chart should render to.
this.chart = new Highcharts[this.props.type || "Chart"](
this.props.container,
this.props.options
);
},
//Destroy chart before unmount.
componentWillUnmount: function() {
this.chart.destroy();
},
//Create the div which the chart will be rendered to.
render: function() {
return React.createElement('div', {
id: this.props.container
});
}
}), element2;
return seriesArr.map(application =>
element2 = React.createElement(Chart, {
container: 'stockChart',
type: 'stockChart',
options: {
rangeSelector: {
selected: 0
},
title: {
text: application.app_name + ' application Free Memory'
},
tooltip: {
style: {
width: '200px'
},
valueDecimals: 4,
shared: true
},
xAxis:{
type:'datetime',
//categories : timeSeries,
dateTimeLabelFormats : {
millisecond: '%Y-%m-%dT%H:%M:%S.%L'
}
},
yAxis: {
title: {
text: 'Free Memory'
}
},
series: application.series
}
})
)
}
Currently, I am calling this function through the render function on the class
render() {
var seriesArr = getSeriesArr(this.props)
return(
<div>
<div className="row">
<ul>
{chartToRender(seriesArr)}
</ul>
</div>
</div>
)
}
How can I display all the charts on the page one below the other? the "seriesArr" variable has all the data required to render the charts.
Try pushing your dynamically created Chart components into an array and then render the array. That should get you going in the right direction.
let charts =[];
charts = seriesArr.map(application =>
element2 = React.createElement(Chart, {
container: 'stockChart',
type: 'stockChart',
options: {
rangeSelector: {
selected: 0
},
title: {
text: application.app_name + ' application Free Memory'
},
tooltip: {
style: {
width: '200px'
},
valueDecimals: 4,
shared: true
},
xAxis:{
type:'datetime',
//categories : timeSeries,
dateTimeLabelFormats : {
millisecond: '%Y-%m-%dT%H:%M:%S.%L'
}
},
yAxis: {
title: {
text: 'Free Memory'
}
},
series: application.series
}
})
)
render() {
return(
<div>
<div className="row">
<ul>
{charts}
</ul>
</div>
</div>
)
}