Why p5js skethch integrated with Vaadin won't start? - javascript

I'm trying to integrate a p5js with the Vaadin. The goal is to plug p5js library and my p5js Sketch as well into the Vaadin's view component. So I would be able to launch and render my a p5js Sketch on client side and refer to some logic on the server side.
As I am figuring out once p5js library loaded it would start automaticaly (The p5js library is a script file with a main function inside round brakets) and catch my "setup()" and "draw()" functions from sketch. And this is exactly how it works if I make an empty html page and plug scripts there with tags.
In Vaadin I used #JavaScript annotation for both scripts and start localhost but hothing happens. Sketch won't start. There is test "console.log()" inside "setup()" function it won't works off too.
Also somehow I can't reach the sketch's functions from browser's console (Neither just "setup()", nor "window.setup()", nor "p5.setup() fit) but with tiny code modification I can. If I place my sketch code inside "window.ns={// my code}" I can refer to it via "window.ns..." in the console. So I'm pretty sure sketches are loaded with page.
What am I missing?
Here is Vaadin's view class I've made (Java):
#Route(value = "/MyView")
#JavaScript("p5.js")
#JavaScript("sketch.js")
public class MyView extends VerticalLayout {
public MyView() {
}
}
Here is the Sketch's code (JavaScript):
function setup () {
console.log(`test message`);
createCanvas(400, 400);
}
function draw () {
background(220);
}
There is no any error message relevant to the issue. The console is silent.
Update:
Also it might be useful if someone experienced look at the high-levevel library code to figure out how it starts:
high-levevel library code

The content of the JavaScript is not automatically executed. You need to add JavaScript call in your view, something like.
#Route(value = "/MyView")
#JavaScript("./p5.js")
#JavaScript("./sketch.js")
public class MyView extends VerticalLayout {
public MyView() {
getElement().executeJs("setup();draw();");
}
}

Related

How to include plain JavaScript in a React app?

I'm trying to create a React page which includes a p5 sketch, but doing so seems to require me to rewrite standard JavaScript I would normally run in a browser to make it work as a react component.
For example, I'd like to have React serve this code to the client:
function setup() {
createCanvas(600, 600);
}
function draw() {
background(0);
}
But I can't find a way to just have React give the client a JavaScript file. Instead I have to create a component like this:
export default function(p: p5) {
p.setup = function setup() {
p.createCanvas(600, 600);
};
p.draw = function draw() {
p.background(0);
};
}
This might seem trivial but if my team and I can include code that we've already written which works outside of react without having to rewrite everything would make things much easier.
One way to solve the problem is to just place the file in the public directory of React and just serve it statically along with index.html, but I'd prefer to only give the client the file when it needs it instead of just serving every file at once. If I could just have a component import the JavaScript file and send it like it can do with images, that would be exactly what I'm looking for.
Edit: Sorry, to clarify what I meant, Node is what's actually serving things, what I want is when React renders a page it will also run JavaScript code as if it were written in a <script> tag in the HTML page.
I've solved it. Essentially I put all of the code I want to run in a file like sketch.js but surround it in a function which is exported:
export default function Sketch() {
function setup() {
createCanvas(600, 600);
}
function draw() {
background(0);
}
}
Then in app.js you can do something like:
import Sketch from './sketch';
Sketch();
That will run all of the code in that function in the client's browser.
So just an option, we do this for optionally loading certain scripts on our app. In your component on the constructor (or maybe the willMount, play around with it) create a new script tag and append that script tag to the head of you app. This will cause the script to only be run when this component is rendered (Depending on where you called the function to add the script tag). You might also have to think about removing the script tag depending on what your doing, but you get the idea.
The function would look something like this:
addScriptTag = () => {
script = document.createElement('script');
script.src = [url/path of the javascript you want to server from your node server];
// Or just set the javascript on the script tag by adding innerText and type arts
document.head.appendChild(script)
}
then do something like:
constructor() {
this.addScriptTag();
}

How to do client-side UI events in Blazor

I just started playing around with Blazor and I can already see the great potential of this new framework.
I'm wondering, though, how it will handle doing simple things like setting focus on an input control? For instance, after I handle a click event, I want to set the focus to a text input control. Do I have to use JQuery for something like that, or will Blazor have some built-in methods for that sort of thing?
Thanks
Update: I posted an answer below with an example of how to set the focus to a control by invoking a JavaScript function from the .Net code.
As of right now (Blazor 0.9.0) you create your JavaScript functions in the Index.html (or reference them from Index.html) and then in your Blazor page or component you call JsRuntime.InvokeAsync("functionName", parms);
https://learn.microsoft.com/en-us/aspnet/core/razor-components/javascript-interop
Blazor is just the replacement (to be more precise "value addition") to JavaScript. It is a client-side only solution (but it might add some easy binding to ASP.NET in the future).
Still, it's completely based on HTML and CSS. C# is replacing the JS part using web assembly. So nothing has changed on how you access / modify HTML controls.
As of now (version 0.1.0) you have to rely on HTML DOM focus() Method to do what you intend to do (yes you have to use JavaScript as of now :( ).
// Not tested code
// This is JavaScript.
// Put this inside the index.html. Just below <script type="blazor-boot"></script>
<script>
Blazor.registerFunction('Focus', (controlId) => {
return document.getElementById(controlId).focus();
});
</script>
//and then wrap it for calls from .NET:
// This is C#
public static object Focus(string controlId)
{
return RegisteredFunction.Invoke<object>("Focus", controlId);
//object type is used since Invoke does not have a overload for void methods. Don't know why.
//this will return undefined according to js specs
}
For more information, you can refer to below.
If you want to improve the packaging of JS neatly, you can do something like this:
https://stackoverflow.com/a/49521216/476609
public class BlazorExtensionScripts : Microsoft.AspNetCore.Blazor.Components.BlazorComponent
{
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
{
builder.OpenElement(0, "script");
builder.AddContent(1, "Blazor.registerFunction('Focus', (controlId) => { document.getElementById(controlId).focus(); });");
builder.CloseElement();
}
public static void Focus(string controlId)
{
RegisteredFunction.Invoke<object>("Focus", controlId);
}
}
then add this component to the root: (App.cshtml):
<BlazorExtensionScripts></BlazorExtensionScripts>
<Router AppAssembly=typeof(Program).Assembly />
I want to add a more up-to-date (as of 0.9.0) example of calling a JavaScript function to set the focus to another control after some event, like clicking on a button. This might be helpful for someone just starting out with Blazor (like me).
This example builds on the example code in the Blazor documentation "Build Your First Blazor Components App" at https://learn.microsoft.com/en-us/aspnet/core/tutorials/build-your-first-razor-components-app?view=aspnetcore-3.0
First, follow all the instructions in the documentation. When you have a working To-Do List page, then add the following:
At the bottom of Index.html, under wwwroot, and below the script tag that loads the webassembly.js, add the following script:
<script>
window.MySetFocus = (ctrl) => {
document.getElementById(ctrl).focus();
return true;
}
</script>
At the top of your todo.cshtml page, add the following using statement:
#inject IJSRuntime JsRuntime;
In the #functions section of your todo.cshtml page, add the following function:
async void Focus(string controlId)
{
var obj = JsRuntime.InvokeAsync<string>(
"MySetFocus", controlId);
}
In the AddToDo() function, just below the line where you set the "newToDo" variable to an empty string, add a call to the Focus function, passing in the string id of the input control. (The example in the docs does not assign an ID to the input control, so just add one yourself. I named mine "todoItem").
void AddTodo()
{
if (!string.IsNullOrWhiteSpace(newTodo))
{
todos.Add(new TodoItem { Title = newTodo });
newTodo = string.Empty;
Focus("todoItem"); // this is the new code
}
}
Build and run your app. When you click the add new item button, the new item should be added to the list, the input control blanked out, and the focus should be back in the input control, ready for another item to be added.
From .NET 5 Preview 8
Set UI focus in Blazor apps
Blazor now has a FocusAsync convenience method on ElementReference for setting the UI focus on that element.
<button #onclick="() => textInput.FocusAsync()">Set focus</button>
<input #ref="textInput"/>
You can't directly call JavaScript function. You are required to first register your functions like,
<script>
Blazor.registerFunction('ShowControl', (item) => {
var txtInput = document.getElementById("txtValue");
txtInput.style.display = "";
txtInput.value = item;
txtInput.focus();
});
return true;
</script>
Then you need to declare a method in C# which calls this JavaScript function. Like,
private void CallJavaScript()
{
RegisteredFunction.Invoke<bool>("ShowControl", itemName);
}
You can call this C# method on click of button. Like,
<button id="btnShow" class="btn btn-primary" #onclick(CallJavaScript)>Show</button>
This post Create a CRUD App using Blazor and ASP.NET Core
shows a working demo of calling JavaScript from Blazor.

unity webgl and browser javascript communication

So i have this problem with communicating between browser and unity webgl,
basically what i want to do is generate objects in unity's scene with javascript code from the view the webgl is being played. In other words, view will have javascript code to create game objects after the scene loaded, not sure if this is possible yet.
i've read the unity documentation but i haven't found an example of how to implement the code shown there or if it's what i'm looking for.
https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html this is what i have been reading, specially the code visibility part, but since i've never worked with frontend that much i'm a bit clueless.
What you can do is to send messages to Unity inside your Javascript code but you'll let Unity do the dirty work about instantiating objects.
This is an example that I just made:
First you create a C# script that spawns your object/prefab, like this:
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class MyObjectSpawner : MonoBehaviour {
public Transform Prefab;
public void Spawn(string data) {
var instance = Instantiate(Prefab);
// do what you like with your instantiated object and the data from the javascript here
}
}
Now you create an object inside the scene and attach this script to it. Keep attention about the name you give to the Game Object you just created, this will be important in the next step. For now, let's say we named it "MyGameObject".
The last step is your javascript inside the game page container. For this example, I've created a button and when it's clicked, the spawnUnityObject() method is called. Like this:
HTML:
<button type="button" onclick="spawnUnityObject()">Press me</button>
Javascript:
function spawnUnityObject() {
// game object in the scene, method name, method parameter
SendMessage('MyGameObject', 'Spawn', 'Super string');
}
The result will be: when you click the "Press me" button inside the html, the game will spawn an object and you can use the "Super string" as a data inside the Spawn() method.
I hope this helps you. Let me know if you need more details.

Can you execute contained JavaScript in browsers?

I want to be able to run JavaScript on my webpage and guarantee that it can be stopped cleanly without causing problems. You could think of it as running JavaScript as if it was contained in an iFrame but allow it to modify and interact with the root DOM. That way if I remove the iFrame, the JS dies.
Use Case/Justification
I want to turn any webpage into a weird mutant SPA. That means taking the traditional HTML, CSS, and JavaScript and then handling page switching myself. To propperly switch pages avoiding artifacts from previously executing JS I'd need to make sure one page's JS doesn't interact with the next page's JS. Ideally, to switch a page it would follow this general formula:
Load HTML and CSS with a framework like Ember.js
Load all linked JavaScript in a contained environment but with the ability to modify the root DOM
When the user clicks a link, stop all running JavaScript and return to step 1.
My Thoughts
I've run tests actually loading a webpage in a full-screen iframe (like this) which achieves the level of containment that I want when executing the JavaScript, but it has serious performance penalties. I want the contained JavaScript, with a minimal performance penalty.
One thought I had was after downloading JavaScript, replacing the actual code dynamically. I would change the code to instead of referencing the Window, referencing the Window.parent.
I'm not attached to the idea of using iFrames, but it just seems like it is the closest thing to a "container" that you can get in JavaScript/the browser. I'd love alternatives.
Related?
github.com/codeschool/javascript-sandbox
instantclick.io/
shadow DOM?
Mini-Followup:
Would it be feasible to build an app like this which would allow for proper handling of both JS life cycles and page switches?
You can't unload a script once it has been loaded. But you can encapsulate some script in an object, and create or destroy this object.
For instance:
var Robot = function(){
return{
sayHello : function(){
alert("Hello!");
},
doSomethingElse : function(){
alert("I'm doing something else");
}
}
}
robot = new Robot();
robot.sayHello(); // Actually alerts "Hello!"
robot = null; // the robot is destroyed.
In your case, if you load a script via ajax, say this piece of script in an object :
{
sayHello : function(){
alert("Hello!");
},
doSomethingElse : function(){
alert("I'm doing something else");
}
}
you can then encapsulate this script in a function :
var Robot = null,
robot = null;
$.get('scriptURL', function(ajaxedScriptObject){
Robot = function(){ return ajaxedScriptObject; };
createRobot();
})
function createRobot(){
robot = new Robot();
sayHello();
destroyRobot();
}
function sayHello(){
robot.sayHello(); // Should alert "Hello!" :)
}
function destroyRobot(){
robot = null;
}

Use Javascript to call method within a flash (.swf) file?

I have a flash file that contains a package "game" which has a class "Scores" and a method setValue(). I want to write some lines of Javascript that allow me to call that method. Someone directed me to this tutorial, but I am still a bit confused.
Javascript: alert("start"); var so; so = document.embeds[0];
so.addParam("allowScriptAccess","always"); import flash.external.ExternalInterface;
ExternalInterface.call("setValue[2600]");
displays an alert to tell me that it has indeed began to execute
saves the embedded flash file into a variable and sets access
imports that class
calls the method
I am not sure about how this class thing works? This is just the bits and pieces I was able to come up with from that site, but I don't really understand how it all works (but certainly hope to eventually). This is the site: http://bytes.com/topic/flash/answers/694359-how-do-i-access-flash-function-using-javascript. When I execute the code with the importation nothing happens, but the alert does come up when I don't have that statement?
If someone could elaborate on how I might call that method, I would be very thankful! :)
The code you have there is a mix of JavaScript and ActionScript.
In ActionScript, you need to register the setValue function for external use, so it can be called from JavaScript. Code for it could look something like this:
package game
{
import flash.display.Sprite;
import flash.external.ExternalInterface;
import flash.text.TextField;
public class Scores extends Sprite
{
public var txtScore:TextField; // A textfield in the sprite
public function Scores()
{
// Register the function for external use.
ExternalInterface.addCallback("setValue", setValue);
}
private function setValue(value:Number):void
{
txtScore.text = String(value);
}
}
}
And the JavaScript could look something like this:
var so = document.embeds[0];
so.setValue(2600);
Adobe has the documentation with a lengthy but useful example here. They show the ActionScript as well as the JavaScript, and how they can interact in both ways.

Categories