How to export chart.js graph to svg in vue? - javascript

I have a graph in my application, which was created with Chart.js library. My graph.js file looks like this:
import { Line, mixins } from 'vue-chartjs';
const { reactiveProp } = mixins;
export default {
extends: Line,
mixins: [reactiveProp],
data() {
return {
options: {
maintainAspectRatio: false,
responsive: true,
legend: {
display: true,
position: 'bottom',
},
scales: {
yAxes: [
{
ticks: {
suggestedMin: 0,
callback(tick) {
return `${tick}%`;
},
},
},
],
},
tooltips: {
callbacks: {
label(tooltipItem, data) {
const dataset = data.datasets[tooltipItem.datasetIndex];
const currentValue = dataset.data[tooltipItem.index];
return ` ${dataset.label}: ${currentValue}%`;
},
},
},
},
};
},
mounted() {
this.renderChart(this.chartData, this.options);
},
};
And the component responsible for rendering it (i've cut some irreleveant details):
<template>
<div
class="container">
<b>
...
</b>
<div
class="graph">
<graph
:styles="graphStyle"
:chart-data=graphData">
</graph>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import Graph from './graph';
import {
...
} from '../../constants';
export default {
name: '...',
components: {
Graph,
},
data() {
return {
...
};
},
watch: {
...
},
methods: {
...
},
computed: {
...
},
};
</script>
I would like to export it to svg, and then post it to my api. I need to serialize it into a string and then send with post method, in json body. Do i have to use some another external library? How can i serialize it to svg? Thanks for any answers.

If png is acceptable for you, there might be a way to do it. Keep in mind that I haven't tested this, but it should work by the looks of it.
Looking at the documentation of vue-chartjs, here it says that you can access the chartjs object with:
this.$data._chart
From there, you should be able to use its method for saving the chart as a png - toBase64Image():
this.$data._chart.toBase64Image()

Related

Particles don't show up on my web page using tsparticles

I'm trying to use tsparticles, and I followed the following steps:
I first installed the package using npm install react-tsparticles.
Then I created a component including two files, the particles component:
import React from 'react';
import Particles from 'react-tsparticles';
import ParticlesOptions from './ParticlesOptions';
const ParticlesBackground = () => {
return (
<div>
<Particles params={ParticlesOptions}>
</Particles>
</div>
)
}
export default ParticlesBackground;
And the particles options:
const ParticlesOptions = {
fps_limit: 60,
interactivity: {
detectsOn: "canvas",
events: {
onClick: {
enable: true,
mode: "push"
},
onHover: {
enable: true,
mode: "repulse"
},
resize: true
},
modes: {
push: {
particles_nb: 4
},
repulse: {
distance: 200,
duration: 0.4
}
}
},
particles: {
color: {
value: "#ffffff"
},
links: {
color: "#ffffff",
distance: 150,
enable: true,
opacity: 0.4,
width: 1
},
move: {
bounce: false,
direction: "none",
enable: true,
outMode: "out",
random: false,
speed: 2,
straight: false
},
number: {
density: {
enable: true,
area: 800
},
value: 80
},
opacity: {
value: 0.5
},
shape: {
type: "circle"
},
size: {
random: true,
value: 5
}
},
detectRetina: true
}
export default ParticlesOptions
I imported the component into my App.js properly as I see no errors, but I still see no particles on my website. Again as I mentioned, no errors are displayed! Here's my App.js:
import React, {Component} from 'react';
import ParticlesBackground from './components/particles/ParticlesBackground';
import Clarifai from 'clarifai';
import Navigation from './components/navigation/Navigation';
import Logo from './components/logo/Logo';
import ImageLinkForm from './components/imageLinkForm/ImageLinkForm';
import Rank from './components/rank//Rank';
import './App.css';
class App extends Component {
render() {
return (
<div className="App">
<ParticlesBackground />
<Navigation />
<Rank />
<Logo />
<ImageLinkForm />
</div>
);
}
}
export default App;
The whole App is displayed properly, and my background isn't white as I found people who have the same problem and turns out that because of the background color they just couldn't see the particles.
I fixed my vulnerabilities and reinstalled my packages properly, but it's still not working!
I also tried to use react-particles-js package instead, but it gives me 'module not found' errors.
Any other suggestions? Hope u could help!
I think you are using version 2.0.6 or similar version, that has some additional steps.
You can find everything in the official documentation: https://github.com/matteobruni/tsparticles/tree/main/components/react#how-to-use
This is what you are missing
const particlesInit = async (main) => {
// you can initialize the tsParticles instance (main) here, adding custom shapes or presets
// this loads the tsparticles package bundle, it's the easiest method for getting everything ready
// starting from v2 you can add only the features you need reducing the bundle size
await loadFull(tsParticles);
};
And you have to use it in the init attribute like this:
<Particles id="tsparticles" options={options} init={particlesInit} />

Vue-Chartjs not rendering graph

I am buiding a website with laravel and using the vuejs to manage the front-end. I want to display several charts through vue-chartjs but the vue-chartjs is not showing the graph even though the data is successfully passed. I have been following their website guide but the graph never displays.
My Vue Component
<teplate>
<div>
...
<line-chart :chart-data="datacollection"></line-chart>
<button #click="fillData()">Randomize</button>
</div>
</template>
<script>
import Table from '../equipments/table.vue'
import LineChart from '../equipments/LineChart.js'
import DropDownList from '../equipments/dropdownlist.vue'
export default {
data () {
return {
datacollection: null
}
},
components: {
LineChart,
Table,
DropDownList
},
mounted () {
this.fillData()
},
methods: {
fillData () {
this.datacollection = {
labels: ['weqw','wewq'],
datasets: [
{
label: 'Data One',
backgroundColor: '#f87979',
data: [this.getRandomInt(), this.getRandomInt()]
},
{
label: 'Data One',
backgroundColor: '#f87979',
data: [this.getRandomInt(), this.getRandomInt()]
}
]
}
},
getRandomInt () {
return Math.floor(Math.random() * (50 - 5 + 1)) + 5
}
}
}
</script>
<style>
.small {
max-width: 600px;
margin: 150px auto;
}
</style>
my Chart.js
import { Line, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins
export default {
extends: Line,
mixins: [reactiveProp],
props: ['options'],
mounted () {
// this.chartData is created in the mixin.
// If you want to pass options please create a local options object
this.renderChart(this.chartData, this.options)
}
}
Hope could receive some hints here, thanks in advance
Vue-chartjs only works with v2 of chart.js. So you will need to downgrade chart.js to version 2.9.4 if you want to use it.
npm i chart.js#2.9.4

How to access Highcharts stock tooltip data in Vue?

I'm using Highcharts stock in Vue, what I want to implement is when I hover one stock point, the tooltip shows up, and at the same time, at other places may be top of the stock chart, as same as data in tooltip in other styles. My way is to export data in the tooltip formatter function, but in the formatter function this doesn't refer to Vue instance. I wonder if there any way I can access hovering tooltip data, or if there any other way can realize the effect.
the effect i want to realize
<template>
<div>
<div class="outerTooltip">open: xxx</div>
<highcharts :constructor-type="'stockChart'" :options="stockOptions"></highcharts>
</div>
</template>
<script>
import { Chart } from "highcharts-vue";
import Highcharts from "highcharts";
import stockInit from "highcharts/modules/stock";
import { data } from "./stockData";
stockInit(Highcharts);
export default {
name: "StockVue",
computed: {
stockOptions() {
return {
...,
tooltip: {
shared: true,
formatter(){
console.log(this)
// how can i export data in this to Vue, so i can show it in outerTooltip dynamically
retuen `
open: ${this.points[0].point.open}
`
}
}
}
}
}
}
codesandbox example
I think that you only need to assign the reference of the Vue instance to a variable and then use it in formatter function. Remember also to add a reference to the computed property.
Demo: https://codesandbox.io/s/highcharts-vue-test-forked-c7pvw?file=/src/components/StockVue.vue
Assign the reference of the Vue instance to a variable that worked for me.
export default {
name: "StockVue",
method: {
exportTooltipData(data){
console.log(data)
}
},
computed: {
stockOptions() {
const exportFn = this.exportTooltipData;
return {
...,
tooltip: {
shared: true,
formatter(){
exportFn(this);
retuen `
open: ${this.points[0].point.open}
`
}
}
}
}
}
}

vuex state inside export default property data... is it possible?

I would like to set properties to buttons that I use in various parts of my project, and therefore I cannot insert static text in each button, but I have tried to use the state of vuex so that if I have to change the name it I change only in the state for all buttons, instead of going to change it by looking for it in every single button.
This solution does not work for me because nothing appears in the buttons, instead the words "Foo" and "Bar" should appear (indeed I would like them to appear to me). In practice it does not take the btnType property.
This is one of my components:
<template>
<div>
<b-button
v-for="(btn, idx) in buttons"
:key="idx"
:class="btn.class"
variant="info"
:name="btn.btnType"
>{{ btn.btnType }}</b-button
>
</div>
</template>
<script>
import { mapState, mapMutations } from "vuex";
export default {
computed: {
...mapState({
buttonFoo: "buttonFoo",
buttonBar: "buttonBar",
}),
},
data() {
return {
buttons: [
{
btnType: this.buttonFoo,
state: true,
class: "button-class1",
},
{
btnType: this.buttonBar,
state: false,
class: "button-class2",
},
],
};
},
};
</script>
And this is my index file:
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
buttonFoo: "Foo",
buttonBar: "Bar"
},
mutations: {},
etc...
});
data evaluates before computed property, hence can not access computed property in data.
better to do it in mounted
export default {
computed: {
...mapState({
buttonFoo: "buttonFoo",
buttonBar: "buttonBar",
}),
},
data() {
return {
buttons: []
};
},
mounted(){
this.buttons=[
{
btnType: this.buttonFoo,
state: true,
class: "button-class1",
},
{
btnType: this.buttonBar,
state: false,
class: "button-class2",
},
],
}
};

Reload chart on api call

I'm trying to reload the data on a bar chart from chart.js, but im not able to.
This is the chart:
<script>
import { Bar } from 'vue-chartjs'
export default {
extends: Bar,
props: ["chartdata"],
data: () => ({
options: {
responsive: true,
maintainAspectRatio: false
}
}),
computed: {
chartData: function() {
return this.data;
}
},
watch: {
data: function() {
this._chart.destroy();
this.renderChart(this.data, this.options);
}
},
mounted () {
this.renderChart(this.chartdata, this.options)
}
}
</script>
This is how I implement it:
<chart
:chartdata="chartdata"
:options="options"/>
After getting the data from the api and form the chartdata I try to trigger the watch by updating the container data that I'm sending like this:
const cd = {
labels: labels,
datasets: [{
label: '# of Votes',
data: data
}]}
this.chartdata = cd
}
But It's not working and I don't know why.
Neither familiar with the library or vue.js in general, but the documentation says the following about updating the chart...
Chart.js does not provide a live update if you change the datasets.
However, vue-chartjs provides two mixins to achieve this.
reactiveProp reactiveData Both mixins do actually achieve the same.
Most of the time you will use reactiveProp. It extends the logic of
your chart component and automatically creates a prop named chartData
and adds a vue watch on this prop. On data change, it will either call
update() if only the data inside the datasets has changed or
renderChart() if new datasets were added.
You're not using the mentioned props in the documentation. You can read more it on the official documentation
If you are using vue-chartjs, the library has its own way to handle reactive data in charts:
// ChartBar.js
import { Bar, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins
export default {
extends: Bar,
mixins: [reactiveProp],
props: ['options'], // passed from the parent
mounted () {
// this.chartData is created in the mixin (pass it as any prop with :chart-data="data").
this.renderChart(this.chartData, this.options)
}
}
Now use the component
<chart
:chart-data="chartdata"
:options="options"
/>
You can read more about it here: https://vue-chartjs.org/guide/#updating-charts,
there are some caveats

Categories

Resources