Importing p5 into a Vue app - javascript

I added the p5 library into the dom like so...
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>App</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.10/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.10/addons/p5.dom.js"></script>
</head>
<body>
<div id="app"></div>
<script src="/dist/build.js"></script>
</body>
</html>
So technically I should be able to grab it via window variable within my Vue code...
<template>
<div id="app">
<h1>Hey my app!</h1>
</div>
</template>
<script>
export default {
name: 'app',
mounted() {
console.log(window.p5) // it's found
window.p5.createCanvas(640, 480);
},
}
</script>
Yet error logs show:
TypeError: window.p5.createCanvas is not a function. After logging window.p5, I can see that it's there. Just not createCanvas(). Which makes me think it's not fully there to begin with. Has anyone experienced this problem? How can I successfully import p5 and make use of it in my Vue app?

You can't just randomly call the createCanvas() function. You have to do it after the setup() function is called.
More info here: Why can't I assign variables using p5 functions and variables before setup()?
To fix your problem, you either need to put your call inside the setup() function, or you need to use on-demand instance mode (as explained in the above link) or instance mode (as explained here).

Related

How to import a blazor custom element in another JS application?

I have a blazor server app, with a registered custom element as below code:
builder.Services.AddServerSideBlazor(options =>
{
options.RootComponents.RegisterAsCustomElement<Counter>("my-blazor-counter");
});
I want to import this blazor custom element in another node.js application to convert it into a lit element(web component).
I have added below scripts in my node.js app
<script src="https://localhost:7075/_framework/blazor.server.js"></script>
<script src="https://localhost:7075/_content/Microsoft.AspNetCore.Components.CustomElements/BlazorCustomElements.js"></script>
but while initializing the Blazor it still using node app port and failing while initialization.
I am not sure I am missing anything here or if there is any other way to do it.
The following describes how I resolved an issue similar to yours: trying to register a custom element, the client not rendering the component and no error message anywhere.
I followed the instructions but the there was nothing happening client-side. After inspecting the websocket's traffic using Firefox I ran into the following message from the client to the server (slightly edited for readability):
ùÀµEndInvokeJSFromDotNetÂÚÙ[
2,
false,
"Could not find 'registerBlazorCustomElement' ('registerBlazorCustomElement' was undefined).
findFunction/<#https://localhost:5001/_framework/blazor.server.js:1:497
findFunction#https://localhost:5001/_framework/blazor.server.js:1:465
E#https://localhost:5001/_framework/blazor.server.js:1:2606
attachWebRendererInterop/<#https://localhost:5001/_framework/blazor.server.js:1:33097
attachWebRendererInterop#https://localhost:5001/_framework/blazor.server.js:1:33145
beginInvokeJSFromDotNet/s<#https://localhost:5001/_framework/blazor.server.js:1:3501
beginInvokeJSFromDotNet#https://localhost:5001/_framework/blazor.server.js:1:3475
_invokeClientMethod/<#https://localhost:5001/_framework/blazor.server.js:1:71894
_invokeClientMethod#https://localhost:5001/_framework/blazor.server.js:1:71880
_processIncomingData#https://localhost:5001/_framework/blazor.server.js:1:69922
kt/this.connection.onreceive#https://localhost:5001/_framework/blazor.server.js:1:64322
connect/</o.onmessage#https://localhost:5001/_framework/blazor.server.js:1:48638
EventHandlerNonNull*connect/<#https://localhost:5001/_framework/blazor.server.js:1:48489
connect#https://localhost:5001/_framework/blazor.server.js:1:48005
_startTransport#https://localhost:5001/_framework/blazor.server.js:1:57626
_createTransport#https://localhost:5001/_framework/blazor.server.js:1:56195
_startInternal#https://localhost:5001/_framework/blazor.server.js:1:54044
async*start#https://localhost:5001/_framework/blazor.server.js:1:51309
_startInternal#https://localhost:5001/_framework/blazor.server.js:1:66198
_startWithStateTransitions#https://localhost:5001/_framework/blazor.server.js:1:65598
start#https://localhost:5001/_framework/blazor.server.js:1:65262
Gn#https://localhost:5001/_framework/blazor.server.js:1:129904
Yn#https://localhost:5001/_framework/blazor.server.js:1:127771
async*#https://localhost:5001/_framework/blazor.server.js:1:131523
#https://localhost:5001/_framework/blazor.server.js:1:131529
"
]
In my case it was that I hadn't added <script src="/_content/Microsoft.AspNetCore.Components.CustomElements/BlazorCustomElements.js"></script> to the html.
I was struggling to get this working for a Blazor serverside app. I created a test.html page in the wwwroot of the blazor project.
The fix for me was to specify the base url.
My html looks like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- my component is here -->
<blazor-counter></blazor-counter>
<base href="http://localhost:5144">
</head>
<body>
<script src="_framework/blazor.server.js"></script>
</body>
</html>

How to add the GoogleChromeLabs input-first-delay polyfill to a React app

I must be missing something simple, but can't seem to get the polyfill working for measuring the first input delay on my firebase project.
I have included the minified file as suggested here, and then in the body of my HTML I have run the code as suggested also.
So it looks like:
<head>
<title>My website</title>
<!--first-input-delay-->
!function(n,e){var t,o,i,c=[],f={passive:!0,capture:!0},r=new Date,a="pointerup",u="pointercancel";function p(n,c){t||(t=c,o=n,i=new Date,w(e),s())}function s(){o>=0&&o<i-r&&(c.forEach(function(n){n(o,t)}),c=[])}function l(t){if(t.cancelable){var o=(t.timeStamp>1e12?new Date:performance.now())-t.timeStamp;"pointerdown"==t.type?function(t,o){function i(){p(t,o),r()}function c(){r()}function r(){e(a,i,f),e(u,c,f)}n(a,i,f),n(u,c,f)}(o,t):p(o,t)}}function w(n){["click","mousedown","keydown","touchstart","pointerdown"].forEach(function(e){n(e,l,f)})}w(n),self.perfMetrics=self.perfMetrics||{},self.perfMetrics.onFirstInputDelay=function(n){c.push(n),s()}}(addEventListener,removeEventListener);
</head>
<body>
<!-- my react app -->
<div id="root"></div>
<script>
perfMetrics.onFirstInputDelay((delay, evt) => {
console.log("First Input Delay", delay)
console.log("Event details", evt)
})
</script>
</body>
When I include the console logs, the script runs as expected and console logs the data, but it never sends it to firebase. If I take out the console logs (perfMetrics.onFirstInputDelay()), the script fails with TypeError: n is not a function.
How should I be adding this to my app? Should I be sending the trace to Firebase somehow? I use performance tracing at the moment, but unsure how to send this specific event as it doesn't have a start and stop time.
Is the solution something like the below?
const performance = firebase.performance()
performance.trace(onFirstInputDelay)
So I was doing something silly. I only needed to include the polyfill and let the Firebase SDK handle the onFirstInputDelay event.
So just having this works.
<head>
<title>My website</title>
<!--first-input-delay-->
!function(n,e){var t,o,i,c=[],f={passive:!0,capture:!0},r=new Date,a="pointerup",u="pointercancel";function p(n,c){t||(t=c,o=n,i=new Date,w(e),s())}function s(){o>=0&&o<i-r&&(c.forEach(function(n){n(o,t)}),c=[])}function l(t){if(t.cancelable){var o=(t.timeStamp>1e12?new Date:performance.now())-t.timeStamp;"pointerdown"==t.type?function(t,o){function i(){p(t,o),r()}function c(){r()}function r(){e(a,i,f),e(u,c,f)}n(a,i,f),n(u,c,f)}(o,t):p(o,t)}}function w(n){["click","mousedown","keydown","touchstart","pointerdown"].forEach(function(e){n(e,l,f)})}w(n),self.perfMetrics=self.perfMetrics||{},self.perfMetrics.onFirstInputDelay=function(n){c.push(n),s()}}(addEventListener,removeEventListener);
</head>
<body>
<!-- my react app -->
<div id="root"></div>
</body>

Hassle with Javascript imports

Most of the things I read online are either outdated or not precise enough.
I'm gonna try to expose my problem.
I was writing a d3 project comprise of 2 files, whose structure is like following
main.html :
<!DOCTYPE html>
<html>
<head>
<script src="./d3/d3.js"></script>
<script src="./KMeans.js"></script>
</head>
<body>
<script type="text/javascript">
<!--Some code -->
var kmeans = new KMeans();
</script>
</body>
</html>
KMeans.js :
class KMeans {
//class related stuff
}
Everything was working super fine, until I decided to add a new class named "Clustering" in a new file to be inherited by KMeans. The code became like this one :
main.html :
<!DOCTYPE html>
<html>
<head>
<script src="./d3/d3.js"></script>
<script type="module" src="./KMeans.js"></script>
</head>
<body>
<script type="text/javascript">
<!--Some code -->
var kmeans = new KMeans();
</script>
</body>
</html>
KMeans.js :
import {Clustering} from './Clustering.js';
export class KMeans extends Clustering {
//class related stuff
}
Clustering.js :
export class Clustering {
}
And I keep getting this error :
ReferenceError: KMeans is not defined
For info, I'm not using Babel or any transpiler.
For the life of me, I can't understand a thing concerning the module management in JS. Could someone help me shed the light on what's wrong, please ?
After a script is defined as a module the variables defined in it are no longer made public. So, you have two options.
Option 1
You can make both Clustering and KMeans regular, non-module files, and remove all import and export statements. This will solve your issue.
Option 2
You can move the final script tag to its own file and make it a module itself (maybe you can keep in inline and still make it a module but I'm not sure about this), and remember to import KMeans if you want to use it.

Unable to access global variable in javascript?

I am trying to access a var one file from another file. Here is what I have:
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<button id="btn">Global</button>
<script src="/test.js"></script>
<script src="/testpass.js"></script>
</body>
</html>
test.js:
export var globalVariable = {
output: "test this"
};
testpass.js:
import { globalVariable } from './test.js'
document.getElementById("btn").addEventListener("click", function(){
alert(globalVariable.output);
});
Nothing happens. I also tried doing
var globalVariable = {
output: "test this"
};
and then simply accessing it from another file as demonstrated in this answer:
Call variables from one javascript file to another but it did not work. Tried exporting it as mentioned in this answer: Can I access variables from another file? as well but no success. I am using sublime text and vue.js and it does not work for both of them.
In addition if I do something like this:
import { globalVariable } from '.test.js'
document.getElementById("btn").addEventListener("click", function(){
alert("Not printing the globalVariable here");
});
the entire javascript file seems to fail and doesn't work at all when called in the HTML file.
You should be getting an error from the browser's JavaScript engine in the web console. To use import and export, you have to treat your code as a module. Your script tags don't, they treat the code as just script. To treat testpass.js as a module, you must use type="module":
<script src="/testpass.js" type="module"></script>
No need to list test.js, testpass.js will load it. So:
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<button id="btn">Global</button>
<script src="/testpass.js" type="module"></script>
</body>
</html>
Sadly, we can't show modules in SO's Stack Snippets, but if you make those changes, this codesandbox example is what you end up with (except I changed src="/testpass.js" to src="./testpass.js").
Note that globalVariable isn't a global variable (which is a Good Thing™). It's a local variable within test.js that it exports. Any other module can import it, but it's not a global.

Meteor - Ckeditor Integration

I'm not sure if there has been a change in the way Meteor loads items, or the way it handles jquery, but I'm having an awful lot of trouble getting ckeditor to come up.
Main Template (Iron-router):
<template name="layout">
<head>
<script type="text/javascript" src="js/ckeditor/ckeditor.js"></script>
<script type="text/javascript" src="js/ckeditor/adapters/jquery.js"></script>
</head>
.....
</template>
Independent Editor Template:
<template name="editor">
<div class="editor_container">
<textarea class="editor"></textarea>
</div>
</template>
Ckeditor located at public/js/ckeditor, any time I try to do the Template.editor.rendered() technique, or even just trying to type $('.editor').ckeditor(); into the console, I get an error of:
$('.editor').ckeditor();
VM48825:2 Uncaught TypeError: undefined is not a function
Any ideas?
Try taking the <head> section out of the layout template. Reading here I believe the <head> section is treated specially be meteor (see: http://docs.meteor.com/#/full/structuringyourapp) and that it being inside a template may be causing the JS to actually not be loaded. Just a guess though.
<head>
<script type="text/javascript" src="js/ckeditor/ckeditor.js"></script>
<script type="text/javascript" src="js/ckeditor/adapters/jquery.js"></script>
</head>
<template name="layout">
.....
</template>
You can use IRLibLoader from iron:router into the onBeforeAction like this.
Router.route('/editor', {
name: 'editor',
template: 'layout',
onBeforeAction: function () {
var ckEditor = IRLibLoader.load('/js/ckeditor/ckeditor.js');
var adapter = IRLibLoader.load('/js/ckeditor/adapters/jquery.js');
if(ckEditor.ready() && adapter.ready()){
console.log('The 2 JS just finish load');
this.next(); // Render the editor page
if(Meteor.isClient){
Template.editor.rendered = function(){
$('.editor').ckeditor();
console.log("loading coeditor when template fully rendered");
}
}
}
}
});
Alternative on the main layout you can use this.
<head>
<script type="text/javascript" src="js/ckeditor/ckeditor.js"></script>
<script type="text/javascript" src="js/ckeditor/adapters/jquery.js"></script>
</head>
<template name="layout">
{{> yield}}
</template>
<template name="editor">
<div class="editor_container">
<textarea class="editor"></textarea>
</div>
</template>
And do the same rendered function
Template.editor.rendered = function(){
$('.editor').ckeditor();
//or make a little delay (1sec)
Meteor.setTiemout(function(){
$('.editor').ckeditor();
},100)
}
There are several problems with your code :
You can't put <head> sections inside another template, it must be done outside all templates.
The path to your JS files are broken, you must prepend a slash to them to reference files in the public directory.
Loading scripts in <head> sections is not a good idea because they will be loaded when your app first loads for every user, even if they never use the editor.
Here is a solution where we load every scripts asynchronously using jQuery promises when the editor template is rendered, and only then initialize the CKEditor.
Template.editor.rendered=function(){
var template=this;
$.when(
$.getScript("/js/ckeditor/ckeditor.js"),
$.getScript("/js/ckeditor/adapters/jquery.js")
).done(function(){
template.$(".editor").ckeditor();
});
};

Categories

Resources