I am using chartjs-2 in react functional component (please find the code here: https://codesandbox.io/s/elastic-brook-okkce?file=/src/Dashboard.jsx)
I have rendered 4 bars here and I want to have a specific handler function defined for onClick event on each bar.
Like there are 4 types in the bar labels and on clicking on each bar I want to display something specific to the type of the bar clicked.
How to implement this?
function Dashboard(props) {
const classes = useStyles();
const [data, setdata] = React.useState({
labels: ["type1", "type2", "type3", "type4"],
datasets: [
{
label: "text that comes on hover",
backgroundColor: [
//................................................colors of the bars............
"#3e95cd",
"#8e5ea2",
"#3cba9f",
"#e8c3b9",
"#c45850"
],
barThickness: 80,
data: [50, 100, 75, 20, 0] //......................values for each bar...........
}
]
});
const getChartData = canvas => {
return data;
};
return (
<React.Fragment>
<div
className={classes.chart}
style={{ position: "relative", width: 900, height: 450 }}
>
<Bar
options={{
responsive: true,
maintainAspectRatio: true,
legend: { display: false },
title: {
display: true,
text: "Title for the graph"
}
}}
data={getChartData}
/>
</div>
</React.Fragment>
);
}
export default Dashboard;
You can use onElementsClick. Please check the below code:
<Bar
options={{
responsive: true,
maintainAspectRatio: true,
legend: {display: false},
title: {
display: true,
text: "Title for the graph"
}
}}
onElementsClick={(e) => {
console.log(e, 'e')
}}
data={getChartData}
/>
Related
My scatter chart is rendered correctly. I have a problem with the custom tooltip function I have created to show the details of the data points on the chart. When I hover the tooltip, it shows an error as
"Uncaught TypeError: Cannot read properties of undefined "
I get the response data for the selected dates from my server using api call and my chart is rendered accordingly. From the received response I have created a dropdown with all employeeName as options to select. When selecting an employeeName I want to show the data point of that person in the scatter chart. My code is working fine for all these functions. But the problem is with the chart options configured. I have given the property type="numeric" for both the x-axis and y-axis in the options object.
If this type="numeric" property is specified, my chart is working fine when I select individual employees from the dropdown but the tooltip shows the error as I mentioned.
If the type="numeric" property is not specified, my chart does not show the data points correctly when I select the employee name, but the tooltip works fine. When I hover over the tooltip for the shown data points does not throw any error.
Below I have given sample data.
import React, { useState, useEffect } from "react";
import axios from "axios";
import ApexCharts from "react-apexcharts";
import "./styles.css";
const ScatterChart = () => {
const[chartData,setChartData]=useState([]);
const [employeeName, setEmployeeName] = useState("");
const [employeeNames, setEmployeeNames] = useState([]);
const [filteredData, setFilteredData] = useState([]);
const data = [
{
employeeName: "John Doe",
percentageOfTasksCompleted: 35,
percentageOfTasksCompletedInTime: 25
},
{
employeeName: "Jane Doe",
percentageOfTasksCompleted: 45,
percentageOfTasksCompletedInTime: 30
},
{
employeeName: "Bob Smith",
percentageOfTasksCompleted: 55,
percentageOfTasksCompletedInTime: 40
}
];
const newData = data.map((d) => {
return {
x: d.percentageOfTasksCompleted,
y: d.percentageOfTasksCompletedInTime,
employeeName: d.employeeName,
};
});
const employeeNames = [...new Set(newData.map((d) => d.employeeName))];
setEmployeeNames(employeeNames);
setChartData(newData);
};
useEffect(() => {
setFilteredData(
employeeName !== null && employeeName !== ""
? chartData.filter((d) => d.employeeName === employeeName)
: chartData
);
}, [employeeName, employeeNames, chartData]);
const options = {
chart: {
type: "scatter",
toolbar: {
show: true,
tools: {
download: true,
selection: false,
zoom: false,
zoomin: false,
zoomout: false,
pan: false,
reset: false | '<img src="/static/icons/reset.png" width="20">',
customIcons: [],
},
export: {
csv: {
filename: "Scatter plot by supervisor",
columnDelimiter: ",",
headerCategory: "category",
headerValue: "value",
dateFormatter(timestamp) {
return new Date(timestamp).toDateString();
},
},
svg: {
filename: "Scatter plot by supervisor",
},
png: {
filename: "Scatter plot by supervisor",
},
},
},
},
xaxis: {
title: {
text: "Percentage of Tasks Completed",
align: "center",
verticalAlign: "top",
floating: true,
offsetY: 100,
style: {
fontSize: "14px",
fontWeight: "bold",
color: "#666",
},
},
tickAmount: 6,
min: 0,
max: 100,
type: "numeric",
},
yaxis: {
title: {
text: "Percentage of Tasks Completed In Time",
align: "center",
verticalAlign: "top",
floating: true,
offsetX: -5,
style: {
fontSize: "14px",
fontWeight: "bold",
color: "#666",
},
},
tickAmount: 6,
min: 0,
max: 100,
type: "numeric",
},
tooltip: {
custom: function ({ dataPointIndex }) {
return (
'<div class="tooltip">' +
"<p class='employee-name'>Employee Name : " +
filteredData[dataPointIndex].employeeName +
"</p>" +
"<p class='percentage-complete'>Percentage of Tasks Completed : " +
filteredData[dataPointIndex].x +
"%</p>" +
"<p class='percentage-in-time'>Percentage of Tasks Completed In Time : " +
filteredData[dataPointIndex].y +
"%</p>" +
"</div>"
);
},
},
};
return (
<div>
<div style={{ display: "flex", alignItems: "center", padding: "10px" }}>
<input
type="date"
value={fromDate}
onChange={(e) => setFromDate(e.target.value)}
style={{ marginRight: "10px", padding: "5px" }}
/>
<input
type="date"
value={toDate}
onChange={(e) => setToDate(e.target.value)}
style={{ marginRight: "10px", padding: "5px" }}
/>
<select
id="employee-name"
value={employeeName}
onChange={(e) => setEmployeeName(e.target.value)}
style={{ marginRight: "10px", padding: "5px" }}
>
<option value="">All</option>
{employeeNames.map((name) => (
<option key={name} value={name}>
{name}
</option>
))}
</select>
<button
onClick={() => {
handleRefresh();
setEmployeeName("");
}}
style={{ padding: "5px 10px" }}
>
Refresh
</button>
</div>
{filteredData !== undefined && filteredData !== null ? (
<ApexCharts
options={options}
series={[{ data: filteredData }]}
type="scatter"
width="600"
height="500"
/>
) : null}
</div>
);
};
export default ScatterChart;
I am using fluent ui detailsList.
I have two columns one have no header name. but its have row data. If I hover my mouse its highlighted. I need to remove that header highlight color. If someone have an idea please suggest me.
{
key: "title",
name: "Title",
fieldName: "title",
minWidth: 150,
maxWidth: 350,
isRowHeader: true,
isResizable: true,
isSorted: false,
isSortedDescending: false,
onColumnClick: _onColumnClick,
data: "string",
isPadded: true,
},
{
key: "moreOptions",
ariaLabel: "TypeButtonColumn",
minWidth: 70,
maxWidth: 90,
onRender: (item) => {
return (
<IconButton
disabled={_setDisabled(item)}
menuProps={menuProps(item)}
menuIconProps={{ iconName: "More" }}
/>
);
},
},
<div id="searchGrid" style={gridStyle}>
<MarqueeSelection>
<DetailsList
items={tableItems}
compact={false}
columns={tableColumns}
selectionMode={SelectionMode.multiple}
getKey={getKey}
layoutMode={DetailsListLayoutMode.justified}
isHeaderVisible={true}
selection={selection}
selectionPreservedOnEmptyClick={true}
enterModalSelectionOnTouch={true}
ariaLabelForSelectionColumn="Toggle selection"
ariaLabelForSelectAllCheckbox="Toggle selection for all items"
checkButtonAriaLabel="select row"
visibility="false"
/>
</MarqueeSelection>
</div>
According to the examples shown in Fluent UI's wiki page, assign a custom styling object to the styles property of the column object you want to style.
const columnHeaderStyles = {
root: {
selectors: {
":hover": {
background: "white",
},
},
},
};
In your case, assign it as
{
key: "moreOptions",
ariaLabel: "TypeButtonColumn",
minWidth: 70,
maxWidth: 90,
onRender: (item) => {
return (
<IconButton
disabled={_setDisabled(item)}
menuProps={menuProps(item)}
menuIconProps={{ iconName: "More" }}
/>
);
},
styles: columnHeaderStyles,
},
I am running into a bit of a problem grabbing data from a Data Grid (or XGrid) to display in another component on the page.
From the code below you can see that I am grabbing data from a local database that I am displaying in a Data Grid. What I want to do now is add the ability to take the selected rows and display the data (product ID, description, price, etc.) and display it in another component. Right now, I will settle for just a single selection.
I have tried many suggestions found here to add a onSelectionModelChange, but the only thing I am able to grab is the row id value. Not that it would make that much difference, but I am using MySQL for the backend.
Any suggestions?
Here's my React file:
import * as React from 'react';
import Axios from 'axios';
import { Grid } from '#material-ui/core';
import { createTheme } from '#material-ui/core/styles';
import { makeStyles } from '#material-ui/styles';
import { GridToolbarDensitySelector, GridToolbarFilterButton, XGrid } from '#material-ui/x-grid';
const currencyFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
});
const usdPrice = {
type: 'number',
width: 180,
valueFormatter: ({ value }) => currencyFormatter.format(Number(value)),
cellClassName: 'font-tabular-nums',
};
const defaultTheme = createTheme();
const useStyles = makeStyles(
(theme) => ({
root: {
padding: theme.spacing(0.5, 0.5, 0),
justifyContent: 'space-between',
display: 'flex',
alignItems: 'flex-start',
flexWrap: 'wrap',
background: '#f3f5f6'
},
textField: {
[theme.breakpoints.down('xs')]: {
width: '100%',
},
margin: theme.spacing(1, 0.5, 1.5),
'& .MuiSvgIcon-root': {
marginRight: theme.spacing(0.5),
},
'& .MuiInput-underline:before': {
borderBottom: `1px solid ${theme.palette.divider}`,
},
},
}),
{ defaultTheme },
);
function FilteringToolbar() {
const classes = useStyles();
return (
<div className={classes.root}>
<div>
<GridToolbarFilterButton />
<GridToolbarDensitySelector />
</div>
</div>
);
}
const ProductTable = () => {
const [rowData, setRowData] = React.useState([]);
const [rows, setRows] = React.useState(rowData);
React.useEffect(() => {
const axios = require('axios').default;
Axios.get("http://localhost:3001/api/get").then((response) => {
setRows(response.data);
}).catch(e => {
window.alert(e);
});
}, [rowData]);
const columns = [
{ field: 'prodID', headerName: 'Product ID', width: 130, disableReorder: true } ,
{ field: 'desc', headerName: 'Description', width: 200, editable: true, disableReorder: true },
{ field: 'price', headerName: 'Price', editable: true, disableReorder: true, ...usdPrice },
{ field: 'inStock', headerName: 'In Stock', width: 110, editable: true, disableReorder: true, headerAlign: 'center', align: 'center', type: 'boolean'},
{ field: 'new', headerName: 'New', width: 110, editable: true, disableReorder: true, headerAlign: 'center', align: 'center', type: 'boolean' },
]
return (
<Grid container item xs={12}>
<Grid container item xs={12}>
<Grid container item xs={3} />
<Grid container item xs={6} justifyContent="center" alignItems="center">
<div style={{ height: 500, width: '100%', display: 'block', marginLeft: 'auto', marginRight: 'auto' }}>
<XGrid checkboxSelection {...rows}
components={{ Toolbar: FilteringToolbar }}
rows={rows}
columns={columns}
id="id"
/>
</div>
</Grid>
<Grid container item xs={3} />
</Grid>
</Grid>
);
}
export default ProductTable;
I would suggest that instead of trying to get the row data that you need to pass to any child/related components from the table, you get the data directly from your own component's state. Since you already have the ids returned from onSelectionModelChange, you can simply use them to filter the rows state to get the selected items. For example:
...
const [selected, setSelected] = React.useState([]);
const [rows, setRows] = React.useState([]);
const handleSelectionChange = React.useCallback(
(selected = []) => {
setSelected(rows.filter(({ prodID }) => selected.includes(prodID)));
},
[rows]
);
...
<XGrid
// Calls our handler function that filters the selected items from state
onSelectionModelChange={handleSelectionChange}
checkboxSelection
{...rows}
components={{ Toolbar: FilteringToolbar }}
rows={rows}
columns={columns}
// Re-wires the grid to use your `prodID` instead of it's default `id`
getRowId={({ prodID }) => prodID}
/>
Working Code Sandbox: https://codesandbox.io/s/datagrid-selected-items-rm3f1?file=/src/App.tsx
I am trying to have the color of the row change colors based on the priority number. For example, if the priority is 4 the color of the entire row should be blue. The problem is that I'm unsure of how to achieve this. I know Material Table assigns ID's to the rows, but I have no way of accessing them. Below is what I have come up with so far. I need options[backgroundColor] to be set based on the priority number. I have a codesandbox here as well https://codesandbox.io/s/notifications-material-ui-spq45
import React from "react";
import { Container } from "react-bootstrap";
import MaterialTable from "material-table";
import FilterListIcon from "#material-ui/icons/FilterList";
import SearchIcon from "#material-ui/icons/Search";
import FirstPage from "#material-ui/icons/FirstPage";
import LastPage from "#material-ui/icons/LastPage";
import ChevronLeft from "#material-ui/icons/ChevronLeft";
import ChevronRight from "#material-ui/icons/ChevronRight";
import CloseIcon from "#material-ui/icons/Close";
function App() {
//loop through the array of priority numbers, and display color based on number
function colors(num) {
for(let i = 0; i < num.length; i++) {
if (num[i] === 4) {
options.rowStyle.backgroundColor = "blue";
}
if (num[i] === 3) {
options.rowStyle.backgroundColor = "red";
}
console.log(num[i]);
}
}
let data = [
{
date: "06-29-2021",
subject: "CANBUS LOSS, Automatic Reboot!",
message:
"SCMs CANBUS LOSS for more than 15 min, Automatic System Reboot!",
category: "System",
priority: 4,
error: "SYS0080"
},
{
date: "06-28-2021",
subject: "Reboot!",
message: "Automatic System Reboot!",
category: "Alarm",
priority: 3,
error: "SYS0090"
},
{
date: "06-25-2021",
subject: "Testing!",
message: "Generator not running!",
category: "Generator",
priority: 2,
error: "SYS0050"
}
];
let columns = [
{ title: "Date", field: "date" },
{ title: "Subject", field: "subject" },
{ title: "Message", field: "message" },
{ title: "Category", field: "category" },
{ title: "Priority Level", field: "priority" },
{ title: "Error Code", field: "error" }
];
let options = {
filtering: false,
sorting: true,
rowStyle: {
fontFamily: "Mulish-Regular",
backgroundColor: ""
},
headerStyle: {
fontFamily: "Mulish-Regular",
fontSize: "1.1em",
fontWeight: "600",
backgroundColor: "#D1D1D8"
},
searchFieldStyle: {
fontFamily: "Mulish-Regular"
}
};
// Loop through all the data and find the priority number, and put it in an array
let map = data.map((x) => x.priority);
console.log(map);
colors(map);
return (
<>
<Container>
<MaterialTable
title=""
columns={columns}
data={data}
options={options}
icons={{
Filter: (props) => <FilterListIcon style={{ fill: "#2D3155 " }} />,
Search: (props) => <SearchIcon style={{ fill: "#2D3155 " }} />,
FirstPage: (props) => <FirstPage style={{ fill: "#2D3155 " }} />,
LastPage: (props) => <LastPage style={{ fill: "#2D3155 " }} />,
NextPage: (props) => <ChevronRight style={{ fill: "#2D3155 " }} />,
PreviousPage: (props) => (
<ChevronLeft style={{ fill: "#2D3155 " }} />
),
SortArrow: (props) => (
<FilterListIcon
style={{ fill: "#2D3155 ", fontSize: "1.4em", margin: ".4em" }}
/>
),
ResetSearch: (props) => <CloseIcon style={{ fill: "#2D3155 " }} />
}}
/>
</Container>
</>
);
}
export default App;
As you can read in the docs, rowStyle accepts an object or a function.
Hence, you can set rowStyle using a function that receives rowData as parameter, an example:
const rowBackgroundColors = {
"2": "yellow", // just for example, remove it if you don't need
"3": "orange",
"4": "red",
};
const options = {
// ...
rowStyle: (rowData) => {
return {
fontFamily: "Mulish-Regular",
backgroundColor: rowBackgroundColors[rowData.priority] ?? "#fff",
};
},
// ...
};
I have installed react-bar-chart using
npm i react-bar-chart --save
And I was using below code to display the bar chart, I can see the bar chart rendering on UI, but color is defaulted to black, I tried adding style={{color: 'blue'}}, but it's not working.
import React, { Component } from "react";
import BarChart from "react-bar-chart";
class Metrics extends Component {
render() {
const data = [
{ text: "DOB", value: 500 },
{ text: "Address", value: 300 },
{ text: "Email", value: 900 },
{ text: "Phone", value: 100 },
{ text: "Name", value: 700 }
];
const margin = { top: 20, right: 20, bottom: 30, left: 40 };
return (
<div>
<div style={{ width: "50%" }}>
<BarChart
ylabel="Quantity"
width={500}
height={500}
margin={margin}
data={data}
style={{ color: "blue" }}
/>
</div>
</div>
);
}
}
export default Metrics;
As it renders as svg, you need to use fill property instead of color:
.bar { fill: blue; }