Change color of labels vue-chartjs - vue-chartjs

How can I change the default colour of the labels?
Here is default chart implementation, hope someone can help me
<script>
import { Pie} from 'vue-chartjs'
export default Pie.extend({
props: ['one', 'two', 'three'],
mounted () {
// Overwriting base render method with actual data.
this.renderChart({
labels: ['One', 'Two', 'Three'],
datasets: [
{
label: 'Stuff',
backgroundColor: ['#C28535', '#8AAE56', '#B66C46'],
data: [this.one, this.two, this.three]
}
]
})
}
})
</script>
Cheers

Check the Chart.js docs http://www.chartjs.org/docs/#chart-configuration-tooltip-configuration
I guess you mean the labels in the legend ? Or Toolip?
Either way, you have to pass the object as options.

Related

How to pass DOM elements for libraries (eg. ChartJS, Hightcharts) in Virtual DOMs (such as Qwik)?

Background
I have personally used React, Vue and Angular extensively in the past. And a lot of times I need to create applications with charts generated within them from selective data. I'm recently trying out Qwik due to its promise of speed and attempted to create charts within it using ChartJs. But while ChartJs has separate libraries available for React, Vue, Angular, Svelte, etc. it does not have one for Qwik understandably.
Issue
Many plugins such as Highcharts and ChartJs often require a DOM element to be sent to its functions to identify where to render their output. But when we are dealing with virtual DOMs, I can't run JS selector scripts to fetch DOM elements and pass them into a function within a component. Therefore, as of now, I have not been able to use ChartJs in my Qwik project.
Attempts
I have only looked for solutions for this issue and not found any workable approaches. From ChartJs docs the following code is their raw JS way of implementing charts:
new Chart(
document.getElementById('acquisitions'),
{
type: 'bar',
data: {
labels: data.map(row => row.year),
datasets: [
{
label: 'Acquisitions by year',
data: data.map(row => row.count)
}
]
}
}
);
As expected document.getElementById does not work inside a component and that is where I'm stuck. I've only created the useMount$() function where I expect to place the logic for generating my chart and also looked around for React solutions by perhaps using references and what not. But, other than that, I have been unable to find anything more.
I understand that looking at the source code of the React library for ChartJs would provide me clues but while I investigate a library (which I find difficult at my current level) I was hoping for a pointer to the solution from the Stack Overflow community.
Searching "ref" on the Qwik docs does not return any search results but I had found the git project from another developer online and tried to replicate the use of references from his approach:
Child component code:
import { component$, useMount$, Ref, useStylesScoped$ } from "#builder.io/qwik";
import { Chart } from 'chart.js/auto';
interface GraphProps {
data: object[];
reference: Ref<Element>;
}
export default component$((props: GraphProps) => {
useStylesScoped$(styles);
useMount$(() => {
new Chart(
props.reference.value,
{
<... options here ...>
}
);
});
return (
<div id="chartContent">
</div>
);
});
Parent component code:
import { component$, useRef } from "#builder.io/qwik";
import ContentCard from "../components/contentCard/contentCard";
import ChartJSGraph from "../components/chartJSGraph/chartJSGraph";
...
export default component$(() => {
const leftChartContainer = useRef();
return (
<div>
<div className="row">
<ContentCard>
<div className="graph-container">
<ChartJSGraph
data={[
{ year: 2010, count: 10 },
...
]}
reference={leftChartContainer}
/>
</div>
</ContentCard>
</div>
</div>
)
});
As these are just findings from a YouTuber's code it could be outdated so is certainly not necessarily a reliable source. But so far searching the official docs have not led me to any official approach for references.
The DOM element that is passed to the charting library can only be accessed once it has been mounted to the page. Qwik/Vue/React all provide component mounted hooks.
https://qwik.builder.io/docs/components/lifecycle/#usemount
https://vuejs.org/api/composition-api-lifecycle.html#onmounted
https://reactjs.org/docs/react-component.html#componentdidmount
Inside these mounted hooks you can reference your DOM element via id or querySelector or using the internal DOM reference feature of Qwuik/Vue/React and then use that when initialising the chart. The latter is the cleaner approach.
For example, in Vue:
<template>
<div id="acquisitions" ref="chartEl"></div>
</template>
<script setup>
import Chart from 'chart.js/auto';
import { ref, onMounted } from 'vue';
const chartEl = ref(null)
onMounted(() => {
const chartOpts = {
type: 'bar',
data: {
labels: data.map(row => row.year),
datasets: [
{
label: 'Acquisitions by year',
data: data.map(row => row.count)
}
]
}
}
new Chart(
chartEl.value,
chartOpts
);
})
</script>
Solution
Sadly this was a silly issue of perhaps on my network side or god knows what why the search engine on the Qwik doc never suggested anything for me when I looked up "Ref" in their docs. But my problem has been solved after finding the following link:
https://qwik.builder.io/tutorial/hooks/use-signal/#example
For future reference for myself or any beginners facing the similar issue, I'm writing down my implementation below:
// Root component
import { component$, useSignal } from "#builder.io/qwik";
...
import ChartJSGraph from "../components/chartJSGraph/chartJSGraph";
export default component$(() => {
const chartData1 = useSignal({
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [{
label: 'Inventory Value per Outlet',
data: [65, 59, 80, 81, 56, 55, 40],
fill: false,
borderColor: 'rgb(75, 192, 192)',
tension: 0.1
}]
});
return (
<div class="w-100 h-100">
...
<ChartJSGraph
width={'100%'}
height={'25px'}
chartData={chartData1.value}
/>
</div>
);
});
And here's the code for my ChartJSGraph component that uses the data supplied to generate the chart while using the reference of the canvas element to point to ChartJS where to create the chart.
// ChartJSGraph component
import { component$, useClientEffect$, useSignal } from "#builder.io/qwik";
import { Chart } from 'chart.js/auto';
...
interface GraphProps {
height: string;
width: string;
chartData: object;
}
export default component$((props: GraphProps) => {
const outputRef = useSignal<Element>();
useClientEffect$(() => {
new Chart(
outputRef.value,
{
type: 'line',
data: props.chartData
}
);
});
return (
<>
<canvas ref={outputRef} width={props.width} height={props.height}>
</canvas>
</>
);
});

ApexCharts: Hide every nth label in chart

I would like to hide some of the labels from my chart made with ApexCharts.js. I am coming from Frappé Charts, which has a feature called "continuity." It allows you to hide labels if they do not comfortably fit, because the chart is a timeseries chart.
My ApexChart looks like this:
I would like to remove many of the dates, but still have them appear in the tooltip. I was able to do this in Frappé Charts and it looked like this:
Here's my code for the Apex chart:
var options = {
chart: {
animations: { enabled: false },
toolbar: { show: false },
zoom: { enabled: false },
type: 'line',
height: 400,
fontFamily: 'PT Sans'
},
stroke: {
width: 2
},
theme: {
monochrome: {
enabled: true,
color: '#800000',
shadeTo: 'light',
shadeIntensity: 0.65
}
},
series: [{
name: 'New Daily Cases',
data: [2,0,0,0,0,0,0,1,0,1,0,7,1,1,1,8,0,11,2,9,8,21,17,28,24,20,38,39,36,21,10,49,45,44,52,74,31,29,43,28,39,58,30,47,50,31,28,79,39,54,55,33,42,39,41,52,25,30,37,26,30,35,42,64,46,25,35,45,56,45,64,34,34,32,40,65,56,64,55,37,61,51,70,81,76,64,71,61,56,52,106,108,104,33,57,82,71,67,68,63,71,32,70,65,98,52,72,87,66,85,90,47,164,123,180,119,85,66,122,65,155,191,129,144,175,224,234,240,128,99,141,131,215,228,198,152,126,201,92,137,286,139,236,238,153,170,106,61]
}],
labels: ['February 28','February 29','March 1','March 2','March 3','March 4','March 5','March 6','March 7','March 8','March 9','March 10','March 11','March 12','March 13','March 14','March 15','March 16','March 17','March 18','March 19','March 20','March 21','March 22','March 23','March 24','March 25','March 26','March 27','March 28','March 29','March 30','March 31','April 1','April 2','April 3','April 4','April 5','April 6','April 7','April 8','April 9','April 10','April 11','April 12','April 13','April 14','April 15','April 16','April 17','April 18','April 19','April 20','April 21','April 22','April 23','April 24','April 25','April 26','April 27','April 28','April 29','April 30','May 1','May 2','May 3','May 4','May 5','May 6','May 7','May 8','May 9','May 10','May 11','May 12','May 13','May 14','May 15','May 16','May 17','May 18','May 19','May 20','May 21','May 22','May 23','May 24','May 25','May 26','May 27','May 28','May 29','May 30','May 31','June 1','June 2','June 3','June 4','June 5','June 6','June 7','June 8','June 9','June 10','June 11','June 12','June 13','June 14','June 15','June 16','June 17','June 18','June 19','June 20','June 21','June 22','June 23','June 24','June 25','June 26','June 27','June 28','June 29','June 30','July 1','July 2','July 3','July 4','July 5','July 6','July 7','July 8','July 9','July 10','July 11','July 12','July 13','July 14','July 15','July 16','July 17','July 18','July 19','July 20','July 21','July 22','July 23','July 24'],
xaxis: {
tooltip: { enabled: false }
},
}
var chart = new ApexCharts(document.querySelector("#chart"), options);
chart.render();
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
<div id="chart"></div>
And here's my code for the Frappé Chart if it helps:
const data = {
labels: ['February 28','February 29','March 1','March 2','March 3','March 4','March 5','March 6','March 7','March 8','March 9','March 10','March 11','March 12','March 13','March 14','March 15','March 16','March 17','March 18','March 19','March 20','March 21','March 22','March 23','March 24','March 25','March 26','March 27','March 28','March 29','March 30','March 31','April 1','April 2','April 3','April 4','April 5','April 6','April 7','April 8','April 9','April 10','April 11','April 12','April 13','April 14','April 15','April 16','April 17','April 18','April 19','April 20','April 21','April 22','April 23','April 24','April 25','April 26','April 27','April 28','April 29','April 30','May 1','May 2','May 3','May 4','May 5','May 6','May 7','May 8','May 9','May 10','May 11','May 12','May 13','May 14','May 15','May 16','May 17','May 18','May 19','May 20','May 21','May 22','May 23','May 24','May 25','May 26','May 27','May 28','May 29','May 30','May 31','June 1','June 2','June 3','June 4','June 5','June 6','June 7','June 8','June 9','June 10','June 11','June 12','June 13','June 14','June 15','June 16','June 17','June 18','June 19','June 20','June 21','June 22','June 23','June 24','June 25','June 26','June 27','June 28','June 29','June 30','July 1','July 2','July 3','July 4','July 5','July 6','July 7','July 8','July 9','July 10','July 11','July 12','July 13','July 14','July 15','July 16','July 17','July 18','July 19','July 20','July 21','July 22','July 23','July 24'],
datasets: [{
name: 'Cumulative Cases',
values: [2,0,0,0,0,0,0,1,0,1,0,7,1,1,1,8,0,11,2,9,8,21,17,28,24,20,38,39,36,21,10,49,45,44,52,74,31,29,43,28,39,58,30,47,50,31,28,79,39,54,55,33,42,39,41,52,25,30,37,26,30,35,42,64,46,25,35,45,56,45,64,34,34,32,40,65,56,64,55,37,61,51,70,81,76,64,71,61,56,52,106,108,104,33,57,82,71,67,68,63,71,32,70,65,98,52,72,87,66,85,90,47,164,123,180,119,85,66,122,65,155,191,129,144,175,224,234,240,128,99,141,131,215,228,198,152,126,201,92,137,286,139,236,238,153,170,106,61],
chartType: 'line'
}]
}
const chart = new frappe.Chart('#chart', {
data: data,
type: 'line',
height: 250,
animate: false,
barOptions: {
spaceRatio: 0.25
},
colors: ['#800000'],
tooltipOptions: {
formatTooltipY: d => d.toLocaleString()
},
axisOptions: {
xAxisMode: 'tick',
xIsSeries: true
},
lineOptions: {
hideDots: true,
regionFill: true
}
})
<script src="https://cdn.jsdelivr.net/npm/frappe-charts#1.5.2/dist/frappe-charts.min.iife.min.js"></script>
<div id="chart"></div>
I've tried using the formatter callback function to return only every 10th value, but things get all out of position and the tooltips don't work. I get similar problems returning an empty string or a space for the values I wish to exclude (but still include in the tooltip).
What I do is calculate the ratio between the area's width and the number of ticks, and if that ratio is above a certain number, I add a classname to the chart or it's wrapper and there I write:
.apexcharts-xaxis-label{
display: none;
&:nth-child(5n){ display:revert; }
}
So every 5th label is shown and the rest are hidden.
You can also set up a resizeObserver to add/remove the special class.
This require the below config to be given to the chart:
xaxis: {
labels: {
rotate: 0, // no need to rotate since hiding labels gives plenty of room
hideOverlappingLabels: false // all labels must be rendered
}
}
You can try 2 things.
xaxis: {
type: 'datetime',
}
You can convert the x-axis to datetime and labels will align as shown below
Or
You can stop rotation of the x-axis labels using
xaxis: {
labels: {
rotate: 0
}
}
which produces the following result.
Vsync answer have not worked for me. It needed a little modification:
.apexcharts-xaxis-texts-g text[id^='SvgjsText'] {
display: none;
}
.apexcharts-xaxis-texts-g text[id^='SvgjsText']:nth-of-type(5n) {
display: revert;
}
labels: ['',this.props.itemNames], //"(labels: [the label , the label below])"

Can't change the pagination 'next' and 'prev' labels to my language in grid.js

There is no such option as change the prev and next button label in the documentation, and when i try to use string replacement or change the button innerHTML via Javascript, it doesn't work, is there any way that I can safely change the label?
You can use the language config (added since v1.5.0) to customize this:
new Grid({
columns: ['Name', 'Email', 'Title'],
sort: true,
search: true,
pagination: {
limit: 5
},
data: Array(50).fill().map(x => [
faker.name.findName(),
faker.internet.email(),
faker.name.title(),
]),
language: {
'search': {
'placeholder': '🔍 Search...'
},
'pagination': {
'previous': '⬅️',
'next': '➡️',
'showing': '😃 Displaying'
}
}
});
Also see this example: https://gridjs.io/docs/examples/i18n/

How do you enable rendering of attributes in Cycle.js/dom?

I have the following snippet:
button('.textbutton', {
type: "button",
onclick: `toggleVisibility('#abs-${submission.submission_id}');`
},
'Abstract'
),
a( {href: "https://localhost:8080"}, 'View Article'),
div(`#abs-${submission.submission_id}`,
{style: 'display:none'}, submission.abstract
),
This seems to render as just:
<button class="textbutton">Abstract</button>
<a>View Article</a>
<div id="abs-1405603">Text not shown on SO...</div>
Note that none of the attributes are being rendered. My cycle.js imports in this file are simply:
import {VNode, div, a, button, h3, img, hr, b, p, span} from "#cycle/dom";
It's snabbdom.
It should be
a({
attrs: {
href: '#'
}
}, ['link'])
And events go under on, like
button('.textbutton', {
attrs: {
type: 'button'
},
on: {
click: () => {} // here goes function
},
}, ['Abstract'])
You have to create object with key attrs and then attributes.
The only case when something like this will work are modules class and style. class takes CSS class as key and condition as value, e.g.
div({
class: {
'block': true,
'hidden': isVisible === false
}
}, [/**/])
When condition is falsy then class will not be present.
style is just like CSS styles key - value:
div({
style: {
'display': 'none'
}
}, [/**/])
Also with Cycle you should not attach events directly to DOM by yourself but call source driver DOM to do that, e.g. sources.DOM.select('a').events('click') and then you have clicks stream.

Sencha ExtJS RESTful grid example confusion

I am very confused by the Sencha documentation for ExtJS. The documentation begins with a Getting Started guide which highlights and illustrates the importance on a suitable structure for the classes and source code of your application. But the provided examples then break all the conventions laid down by the Getting Started guide. Instead of code being broken down into appropriate Model, Store, View, etc. class files the examples are provided as a single file with example source code which is not easily re-usable in separate source files.
I started by following the Portal example (http://docs.sencha.com/ext-js/4-1/#!/example/portal/portal.html) as this is the sort of application I want to create. I wanted to enhance the Portal example and add in a screen which would display a grid and use a RESTful web service as the data backend. I have created the backend I just want to create the front-end. So I looked at the RESTful example (http://docs.sencha.com/ext-js/4-1/#!/example/restful/restful.html)
I have tried to copy the RESTful example into the recommended pattern of seperate classes e.g. Model, Store, View:
Model:
Ext.define('MyLodge.model.Member', {
extend: 'Ext.data.Model',
fields: [
{name: 'name', type: 'string'},
{name: 'email', type: 'string'},
{name: 'href', type: 'string'}
]
});
Store:
Ext.require('MyLodge.model.Member');
Ext.define('MyLodge.store.Members', {
autoLoad: true,
autoSync: true,
model: 'MyLodge.model.Member',
proxy: {
type: 'rest',
url: 'http://localhost:8888/rest/memberapi/members' ,
reader: {
type: 'json',
root: 'data'
},
writer: {
type: 'json'
}
},
listeners: {
write: function(store, operation){
var record = operation.getRecords()[0],
name = Ext.String.capitalize(operation.action),
verb;
if (name == 'Destroy' ) {
record = operation.records[0];
verb = 'Destroyed';
} else {
verb = name + 'd';
}
Ext.example.msg(name, Ext.String.format( "{0} member: {1}", verb, record.getId()));
}
}
});
View:
Ext.define('MyLodge.view.content.MemberGrid', {
extend: 'Ext.grid.Panel',
alias: 'widget.membergrid',
initComponent: function(){
var store = Ext.create('MyLodge.store.Members' );
Ext.apply( this, {
height: this.height,
store: store,
stripeRows: true,
columnLines: true,
columns: [{
id : 'name',
text : 'Name',
flex: 1,
sortable : true,
dataIndex: 'name'
},{
text : 'E-Mail',
width : 150,
sortable : true,
dataIndex: 'email'
},{
text : 'Href',
width : 200,
sortable : true,
dataIndex: 'href'
}],
dockedItems: [{
xtype: 'toolbar',
items: [{
text: 'Add',
iconCls: 'icon-add',
handler: function(){
// empty record
store.insert(0, new MyLodge.model.Member());
rowEditing.startEdit(0, 0);
}
}, '-', {
itemId: 'delete',
text: 'Delete',
iconCls: 'icon-delete',
disabled: true,
handler: function(){
var selection = grid.getView().getSelectionModel().getSelection()[0];
if (selection) {
store.remove(selection);
}
}
}]
}]
});
this.callParent(arguments);
}
});
But I am not sure where to put the code to control the grid row selection and enable the Delete button:
grid.getSelectionModel().on('selectionchange', function(selModel, selections){
grid.down('#delete').setDisabled(selections.length === 0);
});
Also when I press the Add button I get the following error:
Uncaught TypeError: Object [object Object] has no method 'insert'.
Any help would be appreciated.
You are having scoping issues. Basically the variable store is defined only in the initComponent function and therefore of local function scope.
Your handler function has it's own scope. It is firing in the scope of the toolbar button. So if you say this in the handler it would refer to the button. Hence you can say this.up('panel').store - and that gives you the correct reference to the store backing your grid panel.
Another advice is not to implement everything at once. Write a little bit to see if it works and then add to it little by little.
RE: the docs examples, I agree that it's frustrating, but there's not many options. Having a fully-MVC-style implementation of each example would not only be onerous to produce, but would also probably make point of the example get lost in the structure.
RE: your question about the where to "put" the code to control the grid, I would recommend setting up a controller with listeners for the events on the grid in the control() section. This will let you decouple the handling of the events that are fired by your grid from the view itself.