I am new at combining the use of a Pinia store data and vue-chartjs to create reactive charts. I'm using this example as a guide but struggling to have the chart reactive to changes in the store.
I change the Pinia store data in another component using a reactive form, and can see the store data changing, but the chart not updating.
I am rendering a chart with the following component:
<script setup>
import { storeToRefs } from 'pinia'
import { useStore} from '#/store/pinia-store-file';
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend
} from 'chart.js';
import { Line } from 'vue-chartjs';
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend
);
const store = useStore();
const storeData= storeToRefs(store);
const labels = [...Array(storeData.arr.value.length).keys()];
const data = {
labels: labels,
datasets: [
{
label: 'Data One',
backgroundColor: '#f87979',
data: storeData.arr.value
}
]
}
const options = {
responsive: true,
maintainAspectRatio: false
}
</script>
<template>
<Line :data="data" :options="options" />
</template>
I've tried wrapping the store variable in ref() but I think I need to re-render the chart? I'm struggling to apply the above example to a Pinia store state and updating when the store is change.
You don't set data as response. Please use computed
This code can solve the problem:
<script setup>
import { storeToRefs } from 'pinia'
import { useStore} from '#/store/pinia-store-file';
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend
} from 'chart.js';
import { Line } from 'vue-chartjs';
import { computed } from "vue"
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend
);
const store = useStore();
const storeData= storeToRefs(store);
const data = computed(() => ({
labels: [...Array(storeData.arr.value.length).keys()],
datasets: [
{
label: 'Data One',
backgroundColor: '#f87979',
data: storeData.arr.value
}
]
}))
const options = {
responsive: true,
maintainAspectRatio: false
}
</script>
<template>
<Line :data="data" :options="options" />
</template>
Related
I attempted to add a chartJS line chart to my application and got 'Invalid Hook Call' errors. I figured I might be doing something wrong, so I started a fresh application and attempted to follow a tutorial. After following this VERY basic youtube tutorial for using ChartJS in React, I get a blank page.
If I go to inspect->console. I see errors for 'Invalid Hook Call'.
I have checked both versions of react-native and react-dom; versions do not seem to be the issue. This is my output from npm ls for reference.
My ./App.js code - its literally almost a copy of the tutorial . If i remove the <Bar /> from the return at the bottom, application runs fine. :
import './App.css';
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend,
} from 'chart.js'
import { Bar } from 'react-chartjs-2'
import React, {useState, useEffect} from 'react'
ChartJS.register(CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend);
function App() {
const [chartData, setChartData] = useState({
datasets: [],
});
const [chartOptions, setChartOptions] = useState({});
useEffect(() => {
setChartData({
labels: ["Greg", "Chuck", "Kevin", "Sam", "Seth"],
datasets: [
{
label: "Votes",
data: [50,1,1,0,1000],
borderColor: "rgb(53, 162, 235)",
backgroundColor: "rgba(53, 162, 235, 0.3)",
},
],
})
setChartOptions({
responsive: true,
plugins: {
legend: {
position: "top",
},
title: {
display: true,
text: "Who does the most work?",
},
},
});
}, []);
return (
<div className="App">
<h2>BarChart</h2>
<Bar options={chartOptions} data={chartData} />
</div>
);
}
export default App;
Does anyone see something I'm not as to why I could be getting this error?
I'm using chartJs to add a Doughnut chart on my app, but I need to setup it's color under <script> and I'd like to get the color from theme/variables.css .
In the code below, I have a hardcoded backgroundColor, but I'd like to get it from --ion-color-secondary and --ion-color-secondary-contrast instead. How can I achieve that?
Here is the code:
<template>
<Doughnut
:chart-data="chartData"
:chart-options="chartOptions"
/>
</template>
<script lang=ts>
import { defineComponent, PropType } from 'vue'
import { Doughnut } from 'vue-chartjs'
import {
Chart as ChartJS,
Title,
Tooltip,
Legend,
ArcElement,
CategoryScale,
Plugin
} from 'chart.js'
ChartJS.register(Title, Tooltip, Legend, ArcElement, CategoryScale)
export default defineComponent<{fastdata: any}>({
name: 'MrProgress',
components: {
Doughnut
},
inject: ["fastdata"],
setup() {
const chartOptions = {
responsive: true,
maintainAspectRatio: true,
cutout: "90%",
borderWidth: 0,
}
return {
chartOptions,
};
},
computed: {
chartData() {
const pts = this.fastdata.user.pts;
const missing = this.fastdata.user.proximo_nivel - pts;
return {
datasets: [
{
backgroundColor: ['#41B883', '#e4e0d8'],
data: [pts, missing]
}
]
}
}
}
})
</script>
Following the tip from #EstusFlask in the comment regarding userCssVar, I manged to solve it in the following way:
npm i #vueuse/core
...
import { useCssVar } from '#vueuse/core'
import { ref } from 'vue'
<script>
...
const color_pts = useCssVar(ref('--ion-color-secondary'), ref(null)).value;
const color_missing = useCssVar(ref('--ion-background-color'), ref(null)).value;
return {
datasets: [
{
backgroundColor: [color_pts, color_missing],
data: [pts, missing]
}
]
}
...
</script>
I was trying to implement a custom editor for a row in my react data grid which I wish to let user input from a calendar instead of typing.
I came up something which keeps returning invalid dates.
index.js
import React, { Component } from "react";
import ReactDOM from "react-dom";
import "semantic-ui-css/semantic.min.css";
import {
Icon,
Menu,
Checkbox,
Grid,
Dropdown,
Rail,
Segment,
MenuHeader,
Responsive
} from "semantic-ui-react";
import ReactDataGrid from "react-data-grid";
import autoBind from "react-autobind";
import { Editors, Formatters, Data, Filters } from "react-data-grid-addons";
import { connect } from "react-redux";
import moment from "moment";
import DateEditor from "./DateEditor";
import "./styles.css";
const columns = [
{ key: "id", name: "ID" },
{ key: "title", name: "Title" },
{ key: "date", name: "Date", editor: DateEditor }
];
const rows = [
{ id: 0, title: "Task 1", issueType: "Bug", labelColour: "#1D1D1F" },
{ id: 1, title: "Task 2", issueType: "Story", labelColour: "#1D1D1F" },
{ id: 2, title: "Task 3", issueType: "Epic", labelColour: "1D1D1F" }
];
class Example extends React.Component {
state = { rows };
onGridRowsUpdated = ({ fromRow, toRow, updated }) => {
this.setState(state => {
const rows = state.rows.slice();
for (let i = fromRow; i <= toRow; i++) {
rows[i] = { ...rows[i], ...updated };
}
return { rows };
});
};
render() {
return (
<div>
<ReactDataGrid
columns={columns}
rowGetter={i => this.state.rows[i]}
rowsCount={3}
onGridRowsUpdated={this.onGridRowsUpdated}
enableCellSelect={true}
/>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<Example />, rootElement);
DateEditor.js
import { DateInput } from "semantic-ui-calendar-react";
import React, { Component } from "react";
import ReactDOM from "react-dom";
import { Form } from "semantic-ui-react";
import autoBind from "react-autobind";
import moment, { isMoment } from "moment";
export default class DateEditor extends React.Component {
constructor(props) {
super(props);
this.state = { dateEditor: "" };
autoBind(this);
//moment(props.value).format('L')
}
getValue() {
//return { date: moment(this.state.dateEditor).format("L") };
return { date: this.state.dateEditor };
}
getInputNode() {
return ReactDOM.findDOMNode(this);
}
handleChange = (event, { name, value }) => {
this.setState({ [name]: value }, () => this.props.onCommit());
//if (this.state.hasOwnProperty(name)) {
// this.setState({ [name]: value }, () => this.props.onCommit()); //);
//}
};
render() {
return (
<Form>
<DateInput
name="dateEditor"
dateFormat={moment().format("L")}
placeholder="Date"
value={this.state.dateEditor}
//{moment(this.state.date).format('L')}
iconPosition="left"
onChange={this.handleChange}
/>
</Form>
);
}
}
If anyone has ideas I also have my piece of code experiment here React-Data-Grid Custom Editor at CodeSandBox
Some reference: Semantic UI Calendar and React-Data-Grid Custom Editor Many thanks to people may have some ideas where I did wrong, really appreciate.
Actually, it is working, if you double click on the date input, or start typing there, it will show you the calendar to select the date. The issue is with react-data-grid and it seems like the default behavior of react-data-grid. You can see the examples here. The issue is already been created on the reach-data-grid github, Hopefully they will fix this issue.
See here, you can see easily that DateEditor component is working well. I just showed the component down there outside the react-data-grid component.
For now, I think it would be good to avoid react-data-grid and instead use table from semantic-ui-react.
Hope it will help.
In my ReactJS app.js I defined a theme:
const theme = createMuiTheme({
palette: {
primary: {
main: "#54BD40",
},
},
});
I am using the React wrapper for Chart.js and I want to set-up a chart graph. But I am not sure how I can use the primary/main color from my theme:
import React, { Component } from 'react';
import { Line } from 'react-chartjs-2';
let data = []; //data here
const MONTHS = ['Jan', 'Feb', 'Mrt', ...];
const WEEK = ['Sun', 'Mon', 'Tue', ...];
let chart = {
labels: MONTHS,
datasets:[{
borderColor: ['#XXX'], //THEME COLOR HERE
}],
};
class LineChart extends Component{
constructor(props){
super(props);
this.state = {
chartData: chart,
usage: false,
generation: true,
}
}
render(){
return (
<div>
<Line data={ this.state.chartData } options={} />
</div>
)
}
}
export default LineChart;
For using theme palettes inside render(), I know I can import withTheme() and use this.props.theme. But how this work now outside the component? (I just started using ReactJS)
Well as I understand you can import constant into your main js file after doing
export in app.js. Example. -
export const theme = createMuiTheme({ palette: { primary: { main: "#54BD40", }, }, });
Then import
Import { theme } from "app"
And use it anywhere in your main js file.
I would like to use the vue-chartkick plugin, but want to register it within my single-file components rather than using it globally. Is there a way to achieve the same as
Vue.use(VueChartkick, { Chartkick })
in a single-file component? I've tried to import the plugin and then registered it as a component, but it keeps on telling me that the according component was not defined. This is my single-file component:
<template lang="pug" >
div
area-chart(:data="monthlyRevenue")
</template>
<script>
import Api from '../../../api';
import Chartkick from 'chartkick';
import VueChartkick from 'vue-chartkick'
import Chart from 'chart.js';
export default {
name: 'reporting',
components: {
'area-chart': AreaChart
},
data() {
return {
monthlyRevenue: {}
}
},
created() {
Api.get(window.location.pathname)
.then((response) => {
this.monthlyRevenue = response.body;
})
.catch((response) => {
this.handleErrors(response.body);
});
}
}
</script>
You would need to create a new Vue object and declare it as a component in your single file component. I'm not too familiar with VueChartKick. But this might work.
<template lang="pug" >
div
area-chart(:data="monthlyRevenue")
</template>
<script>
import Vue from 'vue';
import Api from '../../../api';
import Chartkick from 'chartkick';
import VueChartkick from 'vue-chartkick'
import Chart from 'chart.js';
// attach your other plugins in here as required
Vue.use(VueChartkick, {Chartkick});
const newCustomComponent = new Vue();
export default {
name: 'reporting',
components: {
'area-chart': AreaChart,
newCustomComponent: newCustomComponent,
},
data() {
return {
monthlyRevenue: {}
}
},
created() {
Api.get(window.location.pathname)
.then((response) => {
this.monthlyRevenue = response.body;
})
.catch((response) => {
this.handleErrors(response.body);
});
}
}
</script>
In you main.js file add the plugin initialisation:
import Chartkick from 'chartkick'
import VueChartkick from 'vue-chartkick'
import Chart from 'chart.js'
Vue.use(VueChartkick, { Chartkick })