Customize Images on Amcharts 5 force directed graph - reactjs

I am trying to make a force directed graph with amcharts 5 where the nodes are images.
I was able to make images as nodes but was not really able to customize it. I want it to be rounded and has an onClick handler, which returns the node which is being clicked.
import React, { useLayoutEffect } from "react";
import "./App.css";
import * as am5 from "#amcharts/amcharts5";
import * as am5hierarchy from "#amcharts/amcharts5/hierarchy";
import am5themes_Animated from "#amcharts/amcharts5/themes/Animated";
function App(props) {
useLayoutEffect(() => {
let root = am5.Root.new("chartdiv");
root.setThemes([am5themes_Animated.new(root)]);
let chart = root.container.children.push(
am5.Container.new(root, {
width: am5.percent(100),
height: am5.percent(100),
layout: root.verticalLayout,
})
);
let series = chart.children.push(
am5hierarchy.ForceDirected.new(root, {
downDepth: 1,
initialDepth: 1,
topDepth: 0,
valueField: "value",
categoryField: "name",
childDataField: "children",
xField: "x",
yField: "y",
minRadius: 30,
manyBodyStrength: -40,
})
);
// series.circles.template.set("forceHidden", true);
// series.outerCircles.template.set("forceHidden", true);
series.circles.template.events.on("click", function (ev) {
console.log(ev);
console.log("Clicked on");
});
// Use template.setup function to prep up node with an image
series.nodes.template.setup = function (target) {
target.events.on("dataitemchanged", function (ev) {
target.children.push(
am5.Picture.new(root, {
width: 90,
height: 90,
centerX: am5.percent(50),
centerY: am5.percent(50),
src: ev.target.dataItem.dataContext.image,
})
);
});
};
series.bullets.push(function (root) {
return am5.Bullet.new(root, {
sprite: am5.Picture.new(root, {
radius: 4,
fill: series.get("fill"),
}),
});
});
series.data.setAll([
{
name: "Chrome",
value: 1,
image: "https://picsum.photos/202",
children: [
{ name: "Google", value: 1, image: "https://picsum.photos/203" },
{
name: "Firefox",
value: 1,
image: "https://picsum.photos/204",
},
{
name: "IE",
value: 1,
image: "https://picsum.photos/203",
},
{
name: "Safari",
value: 1,
image: "https://picsum.photos/205",
},
{
name: "Opera",
value: 1,
image: "https://picsum.photos/206",
},
],
},
]);
series.set("selectedDataItem", series.dataItems[0]);
return () => {
root.dispose();
};
}, []);
return <div id="chartdiv" style={{ width: "100%", height: "500px" }}></div>;
}
export default App;
I was able to find some workaround using pinBullets in amhcarts 4 but I'm trying to get it working on amcharts 5.

Related

How to make a realtime chart with Highcharts, Firebase, ReactJS with Typescript?

I need to create a graph in real time getting data from Firebase. I'm using ReactJs with typescript along with Highcharts.
I've already managed to simulate Highcharts in real time, but now I'm wondering how I can connect it to get the data that will be added to Firebase.
Global Graph Component:
import * as Highcharts from 'highcharts';
import HighchartsReact from 'highcharts-react-official';
import HighchartsMore from 'highcharts/highcharts-more';
import HighchartsAccessibility from 'highcharts/modules/accessibility';
import HighchartsData from 'highcharts/modules/data';
import HighchartsExporting from 'highcharts/modules/exporting';
import HighchartsHeatmap from 'highcharts/modules/heatmap';
import HighchartsTreeChart from 'highcharts/modules/treemap';
import { defaultTheme } from '../../../styles/themes';
HighchartsAccessibility(Highcharts);
HighchartsMore(Highcharts);
HighchartsData(Highcharts);
HighchartsHeatmap(Highcharts);
HighchartsTreeChart(Highcharts);
HighchartsExporting(Highcharts);
interface IChartProps {
options: Highcharts.Options;
}
export const labelsStyle = (
fontSize = 20,
color = defaultTheme.palette.grey[900]
) => ({
color,
fontSize: `${fontSize / 16}rem`,
fontFamily: 'Poppins',
margin: '0px',
fontWeight: 400,
lineHeight: `${(fontSize + 10) / 16}rem`,
});
export const Chart: React.FC<IChartProps> = ({ options }) => {
Highcharts.setOptions({
// rangeSelector: {
// enabled: false,
// },
// navigator: {
// enabled: false,
// },
xAxis: {
labels: {
style: labelsStyle(),
},
},
yAxis: {
labels: {
style: labelsStyle(18, defaultTheme.palette.grey[200]),
},
},
credits: {
enabled: false,
},
exporting: {
enabled: false,
},
});
return <HighchartsReact highcharts={Highcharts} options={options} />;
};
Realtime Graph Component:
import { TooltipFormatterContextObject } from 'highcharts';
import {
Chart,
labelsStyle,
} from '../../../../shared/components/DataDisplay/Chart';
import { defaultTheme } from '../../../../shared/styles/themes';
import { formatDate } from '../../../../shared/utils/date';
import { getRandomIntInclusive } from '../../../../shared/utils/math';
export const GraphHeartRateMonitor: React.FC = () => {
const analyticsDataState = {
dates: [],
data: [],
};
const options: Highcharts.Options = {
chart: {
borderWidth: 0,
height: '176px',
plotBackgroundColor: defaultTheme.palette.background.default,
type: 'line',
marginRight: 10,
events: {
load() {
const series = this.series[0];
setInterval(function () {
const x = new Date().getTime(), // current time
y = getRandomIntInclusive(80, 120);
series.addPoint([x, y], true, true);
}, 1000);
},
},
},
title: {
text: '',
},
xAxis: {
type: 'datetime',
tickPixelInterval: 300,
labels: {
enabled: false,
},
},
yAxis: {
title: {
text: '',
},
gridLineColor: defaultTheme.palette.background.default,
tickInterval: 10,
labels: {
enabled: false,
},
plotLines: [
{
value: 120,
color: defaultTheme.palette.red[300],
width: 2,
label: {
text: '120',
useHTML: true,
verticalAlign: 'middle',
align: 'left',
style: {
background: defaultTheme.palette.red[300],
borderRadius: '24px',
height: '18px',
padding: '2px 12px',
color: defaultTheme.palette.common.white,
fontFamily: 'Roboto Mono',
fontSize: '12px',
fontWeight: '400',
},
},
},
],
// lineColor: defaultTheme.palette.background.default,
},
legend: {
enabled: false,
},
exporting: {
enabled: false,
},
series: [
{
name: 'Random data',
color: defaultTheme.palette.grey[900],
data: (function () {
// generate an array of random data
let data = [],
time = new Date().getTime(),
i;
for (i = -19; i <= 0; i++) {
data.push({
x: time + i * 1000,
y: getRandomIntInclusive(80, 120),
});
}
return data;
})(),
},
],
tooltip: {
useHTML: true,
backgroundColor: defaultTheme.palette.background.paper,
borderRadius: 4,
shadow: {
color: defaultTheme.palette.common.black,
},
padding: 12,
style: labelsStyle(20, defaultTheme.palette.grey[300]),
formatter() {
const self: TooltipFormatterContextObject = this;
return `
<span> Time:</span>
<strong>${formatDate(new Date(self.x), 'HH:mm:ss')}</strong>
</br>
<span>Heart Rate:</span>
<strong >${self.y} bpm</strong>
`;
},
},
};
return <Chart options={options} />;
};
To call the component just call as a normal component <GraphHeartRateMonitor /> .

How do we solve the width change problem caused by resizing in apexchart?

Screen Ratio 100%
enter image description here
Screen Ratio 70%
enter image description here
const chartData = {
type: 'area',
height: 95,
options: {
chart: {
id: 'rental-Chart',
sparkline: {
enabled: true,
},
},
dataLabels: {
enabled: false,
},
stroke: {
curve: 'smooth',
width: 1.3,
},
tooltip: {
fixed: {
enabled: false,
},
x: {
show: true,
},
y: {
title: 'Ticket ',
},
marker: {
show: false,
},
},
},
series: [
{
name: 'Number of Rentals : ',
data: [0, 5, 3, 15, 20, 10, 22],
},
],
};
export default chartData;
import React, { useEffect, useState } from 'react';
import { Card, Grid, Typography } from '#mui/material';
import ApexCharts from 'apexcharts';
import Chart from 'react-apexcharts';
import chartData from './Product-Stock-Chart';
function BajajAreaChartCard() {
useEffect(() => {
const newSupportChart = {
...chartData.options,
chart: {
width: '100%',
},
};
ApexCharts.exec(`rental-Chart`, 'updateOptions', newSupportChart, true);
}, []);
return (
<Chart {...chartData} />
);
}
export default BajajAreaChartCard;
It works normally when it is the default size, but if reduce the size, the size of the chart changes as shown in the picture.
I don`t know what to do to solve this problem..
please help me..

react-graph-vis - Grapg is not re rendering even ofter state changes

When I try to update the state on the hover event, the actual state value is getting changed but the graph is not re-rendering.
in the console, I am able to see the node label is changed to sample. but the graph is not rerendering.
Here is my react function based component.
import React, { useEffect, useState } from 'react';
import Graph from 'react-graph-vis';
import './vis-network.css';
function RelationGraph1() {
const [graph, setGraph] = useState({
nodes: [
{
id: 1,
label: 'Node 1',
title: '',
},
{ id: 2, label: 'Node 2', title: '' },
{ id: 3, label: 'Node 3', title: '' },
{ id: 4, label: 'Node 4', title: '' },
{ id: 5, label: 'Node 5', title: '' },
],
edges: [
{ from: 1, to: 2 },
{ from: 1, to: 3 },
{ from: 2, to: 4 },
{ from: 2, to: 5 },
],
});
const options = {
layout: {
hierarchical: false,
},
edges: {
color: '#1D1D1D',
},
interaction: {
hover: true,
navigationButtons: true,
tooltipDelay: 0,
},
nodes: {
borderWidth: 0,
borderWidthSelected: 0,
color: '#0262C4',
shape: 'circle',
size: 1,
shadow: {
enabled: true,
color: 'rgba(0,0,0,0.5)',
size: 10,
x: 5,
y: 5,
},
font: {
color: '#fff',
size: 13,
bold: {
mod: 'bold',
},
},
},
};
const events = {
select: function (event) {
var { nodes, edges } = event;
console.log('Selected nodes:');
console.log(nodes);
console.log('Selected edges:');
console.log(edges);
},
showPopup: (id) => { // node id
const data = graph.nodes.map((el) => {
if (el.id === id) {
el.label = `sample node name`;
}
return el;
});
setGraph({ ...graph, nodes: data });
},
};
return (
<Graph
graph={graph}
options={options}
events={events}
style={{ height: '450px' }}
/>
);
}
export default RelationGraph1;
Really Appriciate for the help. Thanks !
I was able to update the label in hoverNode event like this:
hoverNode: (e) => {
const data = graph.nodes.map((el) => {
if (el.id === e.node) return { ...el, label: "sample node name" };
else return el;
});
const temp = { ...graph };
temp.nodes = data;
setGraph(temp);
},
Sample: https://codesandbox.io/s/long-bird-4h444?file=/src/App.js:1235-1501

React, ApexCharts, Radial Bar series value from data

I'm new to React and trying to learn. My personal project is homebrewing display site.
I want to show some of the details in radial bar. I followed tutorial and made array data file, and index file where details show. Now I'm stuck getting single values to display in radial bar.
Also values need to be calculated from percent to numeric. I got that working. I tried some push functions but did not get it to work way I wanted. My coding skills are beginner level.
display example
data.js
import product1 from '../../images/product-1.png';
import product2 from '../../images/product-1.png';
export const productData = [
{
id: 1,
img: product1,
alt: 'Beer',
name: 'Lager',
desc: 'Saaz',
ibu: '35',
ebc: '40',
abv: '8.5',
},
{
id: 2,
img: product2,
alt: 'Beer',
name: 'IPA',
desc: 'Mango, Citrus',
ibu: '85',
ebc: '25',
abv: '5.5',
},
];
index.js
import React, { Component } from 'react';
import Chart from 'react-apexcharts';
import {
ProductsContainer,
ProductWrapper,
ProductsHeading,
ProductTitle,
ProductCard,
ProductImg,
ProductInfo,
ProductDesc,
ProductIbu,
ProductEbc,
ProductAbv,
} from './ProductsElements';
const max = 119;
function valueToPercent(value) {
return (value * 100) / max;
}
class IBU extends Component {
constructor(props) {
super(props);
this.state = {
series: [valueToPercent(15)],
options: {
plotOptions: {
radialBar: {
startAngle: -90,
endAngle: 90,
hollow: {
margin: 10,
size: '70%',
background: '#222222',
image: undefined,
imageOffsetX: 0,
imageOffsetY: 0,
position: 'front',
dropShadow: {
enabled: true,
top: 5,
left: 0,
blur: 4,
opacity: 0.9,
},
},
track: {
background: '#d42d2d',
strokeWidth: '67%',
margin: 0, // margin is in pixels
dropShadow: {
enabled: true,
top: 0,
left: 0,
blur: 4,
color: '#000',
opacity: 0.6,
},
},
dataLabels: {
show: true,
name: {
offsetY: -10,
show: true,
color: '#fff',
fontSize: '17px',
},
value: {
formatter: function (value) {
return (parseFloat(value) * max) / 100;
},
color: '#dadada',
fontSize: '36px',
show: true,
},
},
},
},
fill: {
colors: [
function ({ value, seriesIndex, w }) {
if (value < 55) {
return '#7E36AF';
} else if (value >= 55 && value < 80) {
return '#164666';
} else {
return '#D9534F';
}
},
],
},
stroke: {
lineCap: 'round',
},
labels: ['IBU'],
},
};
}
render() {
return <Chart options={this.state.options} series={this.state.series} type="radialBar" height={250} />;
}
}
const Products = ({ data }) => {
return (
<ProductsContainer>
<ProductsHeading>heading</ProductsHeading>
<ProductWrapper>
{data.map((product, index) => {
return (
<ProductCard key={index}>
<ProductImg src={product.img} alt={product.alt} />
<ProductInfo>
<ProductTitle>{product.name}</ProductTitle>
<ProductDesc>{product.desc}</ProductDesc>
<ProductIbu>{product.ibu}</ProductIbu>
<IBU></IBU>
<ProductEbc>{product.ebc}</ProductEbc>
<ProductAbv>{product.abv}</ProductAbv>
</ProductInfo>
</ProductCard>
);
})}
</ProductWrapper>
</ProductsContainer>
);
};
export default Products;

Unable to convert timestamp to hours minutes and secondes in React apex-chart

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.

Resources