How to access or get value of specific graph on chart plot by click event? - vue.js

I use vue-chartjs to draw some chart like line, bar, etc.
In my project, there are many cases using specific value or lable of data in chart.
Using tooltip option of vue-chartjs, I can check that value or label of data item when hovered.
I want to know how to access or get information of specific data matched with point on graph when clicked(not hovered).
Here is my code about chart options.
chartOptions: {
responsive: false,
onClick: function(evt){
//Some logic to get value of label of specific data...(type, label, value, ...)
}
In my case, I use 'onclick' option to access specific data on point triggered 'click' event. In 'onClick' callback, I checked all of chart elements and dataset, etc.
How can I get value of label specific dataItem on point of graph(like line) or bar of graph(like bar) when triggered click event?

I was not able to find a solution that worked for me, but I dug a little bit and this is what I came up with.
onClick: function(evt, array) {
if (array.length != 0) {
var position = array[0]._index;
var activeElement = this.tooltip._data.datasets[0].data[position]
console.log(activeElement);
} else {
console.log("You selected the background!");
}
}
This will get the position in the array that you clicked and grab the data from what position you clicked. This may not be the prettiest or best example, but it worked for me.

This solution use the getElementAtEvent method of chartjs, but to use that you need reference to the Chart itself, not the Vue component. We can get that from the $data._chart property. To use this in a parent Vue component, we use the $refs as seen below`.
So parent defines the chart options
{
...
options: {
onClick: this.handleChartClick
}
...
}
and then parent method, using $refs with $data._chart to get the chart. We get the datasetIndex and value and also the tooltip
handleChartClick(evt, elements) {
var chart = this.$refs.periodChart.$data._chart;
const chartIndex = chart.getElementAtEvent(evt);
if (chartIndex.length !== 0) {
const datasetIndex = chartIndex[0]._datasetIndex;
const position = chartIndex[0]._index;
const info = {
datasetIndex: datasetIndex,
valueIndex: position,
label: chart.tooltip._data.labels[position],
value: chart.tooltip._data.datasets[datasetIndex].data[position]
};
console.log(info);
} else {
console.log("Background clicked");
}

Related

How to check a Specific Properties of a Shape in BPMNjs and update them dynamically

In the bpmnjs I wanted to access or change the right panel properties dynamically on Selection of a Shape or shape type
Below snippet I am trying to use to updated the properties:
updateProperties(e) {
try {
let canvas = this.bpmnModeler.get("canvas");
let rootElement = canvas.getRootElement();
var modeling = this.bpmnModeler.get("modeling");
this.$nextTick(() => {
modeling.updateProperties(e.element, {
id: "ABC",
name: "ABCD",
isExecutable: true,
});
});
} catch (e) {}
}
Please help me to find how to get a specific property of selected shape and update the property in the right panel. Or I have to know how the right panel properties of the bpmnjs is actually configured and loading . I am very much new for the BPMNjs. appreciate for the reply.
I have tried bpmnjs above vuejs framework. I wanted to know how the properties on the right panel of each Task or Shape on the COMUNDA bpmnjs

element not updated when data changes

I have a vaadin-checkbox:
<vaadin-checkbox id=[[item.id]] disabled="true" checked="[[item.checked]]">[[item.description]]</vaadin-checkbox>
I defined my properties:
static get properties() {
return {
items: {
type: Array,
notify: true,
value: function() {
return [];
}
}
};
}
When I now change the data by pressing some button:
_selectItem(event) {
const item = event.model.item;
if (item.checked === true) {
this.$.grid.deselectItem(item);
} else {
this.$.grid.selectItem(item);
}
item.checked = !item.checked;
}
The state of the checkbox is still checked="true". Why isnt the checkbox getting updated? The same thing when I change the description of the item:
_selectItem(event) {
event.model.item.description = 'test';
}
The test description is never appearing. The checkbox is never getting updated.
The reason why the checkbox does not get updated by the button click handler is in the Polymer 2 data system. Polymer does not detect the change and does not update the template accordingly.
In order to make the change in a way that Polymer would detect it you have two options:
Use this.set(`items.${event.model.index}.checked`, !item.checked) if you can reliably assume that the index used by dom-repeat always matches that elements's index in the items array (it is not the case if you use sorting or filtering features of dom-repeat). See an example here https://jsfiddle.net/vlukashov/epd0dn2j/
If you do not know the index of the updated item in the items array, you can also use the Polymer.MutableData mixin and notify Polymer that something has changed inside the items array without specifying the index of the changed item. This is done by calling this.notifyPath('items') after making a change. However, this requires that your element extends the Polymer.MutableData mixin, and that dom-repeat has the mutable-data attribute set. See an example here: https://jsfiddle.net/vlukashov/epd0dn2j/24/
More information on this in the Polymer 2 docs.

Dojo - How to set "label" of togglebutton inside a grid from row.data.SOMEFIELD value?

i'm new to Dojo.
I have a "FullEditable" grid, with many columns, and one of them is a widget, it's a ToggleButton. This grid is used to show details of a purchase, so every line represents a product sold. When i click a button inside one of the columns it launches the product (dialog) browser and then the data of that product is passed to the grid. After some work i managed to display the button and being able to set it's label accordingly to the row.data.FIELD value received from that dialog.
But now i am editing that purchase and i need to be able to do the same, to be able to load the data from the preloaded array with data ("detalle") (as it's label) into the togglebutton, but nothing seems to work, not even the direct assignment of the widget or the row data or anything.
Here's a fragment of my code:
var grid = this;
var selectedRow = grid.row(i);
var cell = grid.cell(selectedRow, 'Moneda');
selectedRow.Moneda = detalle.MonedaItem; //didn't work
if(cell.row !== null && cell.row !== undefined && cell.row.data !== null && cell.row.data !== undefined)
cell.row.data.Moneda = detalle.MonedaItem; //didn't work
if(cell.element !== null && cell.element !== undefined){
cell.element.innerText = detalle.MonedaItem; //didn't work
cell.element.textContent = detalle.MonedaItem; //didn't work
if(detalle.MonedaItem === 'UF')
cell.element.widget.set('checked', true);
if(detalle.MonedaItem === 'CLP')
cell.element.widget.set('checked', false);
cell.element.widget.set('label', detalle.MonedaItem); //didn't work
cell.element.widget.set('value', detalle.MonedaItem); //didn't work
}
}
Whenever i set the value through the change event with "cell.element.widget.set('checked', boolean);" i get an error message from the editor, when it tries to get a cell but the variable is null, so it crashes.
The values of "label" and "value" of the widget, row.data en cell are perfectly set, BUT the grid DISPLAYS the "emptyValue" value of the widget and not the one that is actually set.
AFAIK, best way to change the grid data is to update the store/ collection that is associated with the grid and just invoke grid.refresh(). The new data will be loaded automatically.
The statement cell.row.data.Moneda = detalle.MonedaItem is actually changing the data in your store. Just refresh the grid after this and you are done!
Never try to set something in grid DOM element directly. Always work with store, renderCell and renderColumn. This will ensure consistency in store and grid attributes that reference the store.
I finally managed to get what i need through renderCell like this:
,{
id: 'Moneda',
field: 'Moneda',
label: "Moneda",
renderCell: function (object, value, node, options) {
try {
var button = new ToggleButton({
node: node,
isWidgetInGrid: true,
parameterName: 'codigoMoneda',
label: object.Moneda,
showLabel: true,
onChange: function(newValue){
var grid = this.getParent();
var row = grid.row(this.node);
var data = row.data;
if(this.get('label') === 'CLP')
{
data.Moneda = 'UF';
this.set('label','UF');
this.set('value', 'UF');
}
else
{
data.Moneda = 'CLP';
this.set('label','CLP');
this.set('value', 'CLP');
}
grid.getParent().getParent()._calcularTotales();
}
});
node.appendChild(button.domNode);
}
catch (ex) {
Debug.log(this.declaredClass, arguments, ex);
}
},
emptyValue: 'CLP',
autoSave: true
}

Chartist.js and events

I am trying to add click events on the graphs that I am rendering. From chart.click to chart.on('click', function (e){ }).
What I am trying to do is allow the user to select points on the graph and for me to now what selections the user made. Is that at all possible using chartist.js?
I read through the documentation: CHARTIST.JS
My code:
if (item.GraphType.Description == "Line") {
var chart = new Chartist.Line(
container[0],
{
labels: d.Labels,
series: d.SeriesData
},
{
axisY: {
offset: 60
}
}
);
chart.click(function (e) {
console.log(e);
});
}
It is entirely possible, yes. Chartist renders SVG nodes to the page, so using a library like jQuery you can easily find all nodes that you want and attach events to them. You can be as specific or broad in the nodes you're looking for to only attach events to very specific nodes or elements on the chart.
For completeness sake, here is a short example of how to attach events that log the value of a data point when clicked upon to the console using jQuery:
$('.ct-chart-line .ct-point').click(function () {
var val = $(this).attr("ct:value");
console.log(val);
});
You should, however, make sure that the events attach only when the chart is created or drawn if you want to ensure the data points are on the page, which can be triggered by the "created" or "draw" events:
var chart = new Chartist.Line(...);
// attach an event handler to the "created" event of the chart:
chart.on("created", function () {
// attach the necessary events to the nodes:
$('.ct-chart-line .ct-point').click(function () {
var val = $(this).attr("ct:value");
console.log(val);
});
});

Hiding a series by default in a spider plot

I have a spider plot in using the graphing library of Dojo defined like this:
require([
"dojox/charting/Chart",
"dojox/charting/themes/Claro",
"dojox/charting/plot2d/Spider",
"dojox/charting/action2d/Tooltip",
"dojox/charting/widget/SelectableLegend",
"dojox/charting/axis2d/Default"
], function (Chart, theme, Spider, Tooltip, Legend, Default) {
var chart = new Chart(element).setTheme(theme).addPlot("default", {
type: Spider,
radius: 200,
fontColor: "black",
labelOffset: "-20"
});
var colors = ["blue", "red", "green", "yellow", "purple", "orange", "teal",
"maroon", "olive", "lime", "aqua", "fuchsia"];
$.each(factors, function (index, factor) {
chart.addAxis(factor.name, {
type: Default,
min: factor.min,
max: factor.max
});
});
$.each(presets, function (pIndex, preset) {
var data = [];
$.each(factors, function (fIndex, factor) {
data[factor.name] = preset.values[fIndex];
});
chart.addSeries(preset.short, data, {
fill: colors[pIndex % colors.length]
});
});
new Tooltip(chart, "default");
chart.render();
new Legend({
chart: chart,
horizontal: false
}, $(element).next(".legend")[0]);
});
I add a series for every member of an array called presets and I use a selectable legend that lets the user turn them on or off as they want. However, what I can't seem to find in the docs is how to start a series in the unselected, not visible state? What I ideally want to do is cap the number of series visible when the page loads because in some cases I have up to 14 presets and it just looks a mess until the user deselects a bunch. So I'd like to have, say, every preset above the first 5 be hidden at the start.
Here's a crude fiddle I've knocked to demonstrate. What I want is to have some of the series unselected when the plot is first displayed.
Update: I tried adding this after adding my series:
var checkboxes = $(".dijitCheckBoxInput").each((index, elem) => {
if (index > 4) {
elem.click();
}
});
Which works, but seems very fragile. If they change the class assigned to checkboxes, it'll break. Also, it prohibits me using more than one set of dojo checkboxes because I don't have a good way to tell the difference. (Note, the IDs of the checkboxes added by the SelectableLegend are dijit_form_CheckBox_0, dijit_form_CheckBox_1, etc, which also gives no useful information as to what they are related to). I thought I might be able to use the legend placeholder div as a way to select the descendant checkboxes, but it appears that Dojo replaces the placeholder entirely with a table.
i looked into the dojo code and found the area in which the shapes are toggled on & off whitin the SelectableLegend.js :
var legendCheckBox = query(".dijitCheckBox", legend)[0];
hub.connect(legendCheckBox, "onclick", this, function(e){
this._toggle(shapes, i, legend.vanished, originalDyn, seriesName, plotName);
legend.vanished = !legend.vanished;
e.stopPropagation();
});
The toggling process is very complex and is based on many local attributes:
_toggle: function(shapes, index, isOff, dyn, seriesName, plotName){
arrayUtil.forEach(shapes, function(shape, i){
var startFill = dyn.fills[i],
endFill = this._getTransitionFill(plotName),
startStroke = dyn.strokes[i],
endStroke = this.transitionStroke;
if(startFill){
if(endFill && (typeof startFill == "string" || startFill instanceof Color)){
fx.animateFill({
shape: shape,
color: {
start: isOff ? endFill : startFill,
end: isOff ? startFill : endFill
}
}).play();
}else{
shape.setFill(isOff ? startFill : endFill);
}
}
if(startStroke && !this.outline){
shape.setStroke(isOff ? startStroke : endStroke);
}
}, this);
}
I tried also checking & unchecking the dijit/form/Checkbox in a legend manually, but that does not trigger the _toggle function in any case, even if you do a render() / fullrender() on the chart.
With that in mind it seems that there is no other possibilty to toggle the series on and off than by firing the onclick events manually.
To make your code less fragile, you could access the Checkbox widgets within the legend manually using:
query(".dijitCheckBox", legend); // Should deliver an array containing
the widgets.
and triggering the onclick event on them. Their keynumber in the array should correspond to the order the series where added...
Dojo is a fine piece of work, please dont stop working with it !
dojox/charting/Series has an attribute called dirty which according to the API docs is a "flag indicating whether or not this element needs to be rendered".
Alternately, if you are limiting the display of some series you can write a separate interface for adding them. For example, loop over the first 5. Then create a select box or list of check boxes with all entries and an onchange event that calls chart.addSeries.
Keeping a reference to each series you create will allow you to later call destroy() or destroyRecursive() on it if the user no longer wishes it displayed.
So while ideally you could toggle the display of these series, the worst case senerio is that you just add, destroy, and read based on some user input.
Using a templated widget will allow you to keep this interface and the chart tightly linked and support reuse.
BTW, consider using "dojo/_base/array" and "dojo/query" in place of the jquery
I think i've got it !
I found another way to access the checkboxes ! It's the same way dojo uses internally to connect the "toggle code" to the onclick event. First take a look at this from SelectableLegend.js (Lines 150 - 156):
// toggle action
var legendCheckBox = query(".dijitCheckBox", legend)[0];
hub.connect(legendCheckBox, "onclick", this, function(e){
this._toggle(shapes, i, legend.vanished, originalDyn, seriesName, plotName);
legend.vanished = !legend.vanished;
e.stopPropagation();
});
It looks like they use the ".dijitCheckBox" class to find the checkbox dom element and connect to it using dojo/connect. Now based on that, i made this function:
function toggleSeries (legend,num) {
dojo.query("*",legend.legends[num])[0].click();
dijit.findWidgets(legend.legends[num])[0]._onClick(); }
It doesn't use any class definition (because of the *) and it accesses the areas where the checkboxes are from within the SelectableLegend. It needs the SelectableLegend and the number of the series you want to deactivate as parameters. Here the jsfiddle example with this function & hiding all 4 of your series with it:
http://jsfiddle.net/luciancd/92Dzv/17/
Also please notice the "onDomReady" Option in jsfiddle, without it: doesnt work in IE.
And the ready function within the code !
Lucian
I have updated your code http://jsfiddle.net/92Dzv/18/
Here is the key to toogle.
dom.byId(le._cbs[0].id).click();
dom.byId(le._cbs[2].id).click();
Choose the index of your legend and set to _cbs.
By this way le._cbs[0].id you will get the real id of checkbox (that inside in the widget) and then just use click()
Note : le is came from here.
var le = new Legend({
chart: chart,
horizontal: false
}, legend);