Attach onAnimationComplete for Chart.js after creation - chart.js

I'm creating a Blazor component as a facade of ChartJs. I opened a question on the Microsoft forum to understand how I can call a JavaScript function for the component.
My problem is how to add some events to the chart before the creation. So, from the Blazor page, I pass a model called config that contains all the configuration for the chart.
Then, I create the chart in JavaScript like
var ctx = document.getElementById(id).getContext('2d');
var chart = new Chart(ctx, eval(config));
Now, I want to add an event and send to Blazor an event. For example, I added the following code for the event onHover and it works.
chart.options.onHover = function () {
DotNet.invokeMethodAsync('PSC.Blazor.Components.Chartjs', 'ChartHover');
}
With onClick is working too.
chart.options.onClick = function (event, array) {
var rtn = 0;
if (array !== undefined && array.length > 0)
rtn = array[0].index;
DotNet.invokeMethodAsync('PSC.Blazor.Components.Chartjs', 'ChartClick', rtn);
};
Now, I want to do the same with onAnimationComplete.
chart.onAnimationComplete = window["AnimationComplete1"];
In this cases, the function is not being called. Some if I write this code
chart.onAnimationComplete = function () {
console.log('onAnimationComplete animation completed');
};
How can I fix the code?

there is no onAnimationComplete event you can configure directly on the chart. This has to be done in the options like you did for the onHover and the name has to be different:
chart.options.animation.onComplete = function () {}

Related

Livewire #entangle

I am new to Livewire and have a question.
In my Livewire blade I have a JS function that calls a component method which updates $this->questions.
function QuestionBatchRequest() {
Livewire.emit('moreQuestions');
this.dispatchEvent(new Event('moreQuestions'));
}
This works as I can output to an input box and see the data change.
I then have
document.addEventListener('livewire:load', () => {
window.livewire.on('QuestionBatchListener', () => {
let data = #entangle('questions');
myUnityInstance.SendMessage("JS-Unity", "InjectQuizData", data);
});
});
How can I get the updated $this->questions to my JS variable directly?
This is in my method in my component
$this->questions = json_encode($data, JSON_UNESCAPED_SLASHES);
$this->emit('QuestionBatchListener');
This function is called from my Unity game on the same page. The initial set of questions is received on page load and works fine.
OK, so I changed
let data = #entangle('questions');
with
let data = #this.get('questions');
...

How to use puppeteer to hook into powerbi report loaded event

I am embedding a power bi report using pupeteer/chromium quite happily and then save that as a screenshot/pdf. However, a late breaking requirement requires me to be able to hook the report's onloaded event.
I have the following code snippet which is the template I use to hook up the event; the report is embedding, but the 'report.on' event is not firing, (In reality I'm trying to set some visuals and other stuff, not just log text.)
await page.evaluate((configdata) => {
const models = window['powerbi-client'].models;
const config = {
...
};
const report = powerbi.embed(reportContainer, config)
report.on('loaded', function () {
console.log('loaded report')
});
},
configdata);
I've looked at "exposeFunction()" but couldn't get it hooked to this event (or others).
Would some please tell me what I'm missing; there must be way to do this, but I'm missing how to tie the report object (instantiated from within the IFrame, to it's event from withing the puppeteer function. However, JS/Node is not my primary discipline, hell it's not even my second!
PS: I know (and have got working) passing filters into to the configuration; but that is not quite good enough from the aethetics point of view (on screen visuals are not set!)
Any help/pointers - very greatly appreciated
We've kept with passing the filters into the configuration whne embedding the report.
short and simple.
To answer the question, you can use page.evaluate and create a Promise which will be resolved when the embed loaded event will be triggered. Then you can await for your loadEmbed function:
async function loadEmbed(page, config) {
return page.evaluate(async (config) => {
await new Promise((resolve, reject) => {
try {
var embedContainer = $('#embedContainer')[0];
var embed = powerbi.embed(embedContainer, config);
embed.off("loaded");
embed.on("loaded", function () {
resolve(true);
});
} catch (err) {
resolve(false);
}
});
}, config);
}

powerbi global object not found in typescript

I am trying to use this power bi below code where powerbi object not found error is getting in my typescript code:
// Read embed application token from textbox
var txtAccessToken = $('#txtAccessToken').val();
// Read embed URL from textbox
var txtEmbedUrl = $('#txtReportEmbed').val();
// Read report Id from textbox
var txtEmbedReportId = $('#txtEmbedReportId').val();
// Read embed type from radio
var tokenType = $('input:radio[name=tokenType]:checked').val();
// Get models. models contains enums that can be used.
var models = window['powerbi-client'].models;
// We give All permissions to demonstrate switching between View and Edit mode and saving report.
var permissions = models.Permissions.All;
// Embed configuration used to describe the what and how to embed.
// This object is used when calling powerbi.embed.
// This also includes settings and options such as filters.
// You can find more information at https://github.com/Microsoft/PowerBI-JavaScript/wiki/Embed-Configuration-Details.
var config= {
type: 'report',
tokenType: tokenType == '0' ? models.TokenType.Aad : models.TokenType.Embed,
accessToken: txtAccessToken,
embedUrl: txtEmbedUrl,
id: txtEmbedReportId,
permissions: permissions,
settings: {
filterPaneEnabled: true,
navContentPaneEnabled: true
}
};
// Get a reference to the embedded report HTML element
var embedContainer = $('#embedContainer')[0];
// Embed the report and display it within the div container.
var report = powerbi.embed(embedContainer, config);
// Report.off removes a given event handler if it exists.
report.off("loaded");
// Report.on will add an event handler which prints to Log window.
report.on("loaded", function() {
Log.logText("Loaded");
});
report.on("error", function(event) {
Log.log(event.detail);
report.off("error");
});
report.off("saved");
report.on("saved", function(event) {
Log.log(event.detail);
if(event.detail.saveAs) {
Log.logText('In order to interact with the new report, create a new token and load the new report');
}
});
in the above code the powerbi object shows not found in my typescript code: powerbi.embed(embedContainer, config);
I tried to use window['powerbi'] or window.powerbi but doesn't work. What should be the solution then?
I faced a similar issue a few weeks back (probably exactly the same). For me it seems that what works is using window.powerbi.embed() for the embed action, whereas the import import * as powerbi from "powerbi-client"; is used for all other Power BI objects.
I had the same problem, found this question through a google search. I wasn't able to figure out why it wasn't on the window, but as a work around you can initialize it yourself like this:
import * as pbi from "powerbi-client";
const powerbi = new pbi.service.Service(
pbi.factories.hpmFactory,
pbi.factories.wpmpFactory,
pbi.factories.routerFactory
);
const container = document.getElementById("report-container");
powerbi.embed(container, embedConfiguration);

How to remove events from nicEditor + emberjs

I am working on an Ember.js - based platform, where I use nicEdit. Here is my code
RichHTMLView = Ember.TextArea.extend({
id: null,
editor: null,
didInsertElement: function(){
var view = this;
view.id = this.get("elementId");
view.editor = new nicEditor({
buttonList : ['bold','italic','underline','right','center','justify', 'link', 'ul', 'ol']
}).panelInstance(view.id);
//When the editor looses focus the content of the editor is passed to descr
view.editor.addEvent('blur',function(){
view.get('controller').set('descr',view.getViewContent());
});
//So the editor looks nice
$('.nicEdit-panelContain').parent().width('100%');
$('.nicEdit-panelContain').parent().next().width('100%');
},
getViewContent: function(){
var view = this,
inlineEditor = view.editor.instanceById(view.id);
return inlineEditor.getContent();
},
willClearRender: function(){
var view = this;
}
});
So this works nicely as long as I am on the page which hosts the view, but if I transition to another route, the view has some leftovers, namely the editor is destroyed, but I assume that nicEdit keeps track of event bindings, so I end up with the blur event being bound to editor, which is undefined in the new context, as the view does not exist.
My best guess is that I need to somehow unbind the editor in the willClearRender, but I don't know how.
as I got no reply and nicEdit is abandoned I made some changes to the source-code in order to deal with this issue by adding removeEvent to bkEvent:
removeEvent: function(A, B){
if (B){
this.eventList = this.eventList || {};
this.eventList[A] = this.eventList[A] || [];
this.eventList[A].splice(this.eventList[A].indexOf(B),1);
}
Then I can remove the event in willClearRender:
view.editor.removeEvent('blur',view.onBlur);
Be aware that I've not tested it with multiple editors, as my needs do not require, but if you have multiple editors with the same callback the behavior is not defined.

How to live update jqPlot graph with ember.js?

I know how to update and redraw a jqPlot object without using ember...
I created the following fiddle to show the "problem": http://jsfiddle.net/QNGWU/
Here, the function load() of App.graphStateController is called every second and updates the series data in the controller's content.
First problem: The updates of the series seem not to propagate to the view.
Second problem: Even if they would, where can i place a call to update the plot (i.e. plotObj.drawSeries())?
I already tried to register an observer in the view's didInsertElement function:
didInsertElement : function() {
var me = this;
me._super();
me.plotObj = $.jqplot('theegraph', this.series, this.options);
me.plotObj.draw();
me.addObserver('series', me.seriesChanged);
},
seriesChanged: function() {
var me = this;
if (me.plotObj != null) {
me.plotObj.drawSeries({});
}
}
But that didn't work...
Well, figured it out, see updated fiddle.
The secret sauce was to update the whole graphState object (not just it's properties) in App.graphStateController:
var newState = App.GraphState.create();
newState.set('series', series);
me.set('content', newState);
And then attach an observer to it in the App.graphStateView:
updateGraph : function() {
[...]
}.observes('graphState')
The updateGraph function then isn't pretty, since jqPlot's data series are stored as [x,y] pairs.
The whole problem, i guess, was that the properties series and options in the App.graphState object itself are not derived from Ember.object and therefore no events are fired for them. Another solution may be to change that to Ember.objects, too.