canvas in canvas not displayed when requirejs structure used - javascript

I have a problem that is driving me insane.
I have something that works perfectly fine in one javascript file, but completely fails when using it with requirejs.
(function(){
define([], function (){
var Sprite = function(){
return {
spritesheet: null,
canvas: null,
context: null,
init: function(src, ctx){
this.canvas = document.createElement('canvas');
this.context = this.canvas.getContext('2d');
this.context.drawImage(src, 0, 0, 10, 20, 0, 0, 10, 20);
ctx.drawImage(this.canvas, 100, 100);
}
};
};
return Sprite;
});
}
)();
And in other file I have:
(function(){
define(["r", "sprite", "player"], function (Ra, Sprite, Player){
var Game = function()
{
return {
...SOME STUFF HERE...
canvas: null,
context: null,
something: function() {
this.canvas = document.getElementById("game");
this.canvas.width = 500;
this.canvas.height = 500;
this.context = this.canvas.getContext("2d");
var sprite = new Sprite();
sprite.init("image.gif", this.context);
};
};
return Game;
});
}
)();
I tried to compact the code as much as I can, I hope I didn't cut out anything important, but that is basically the part that is not working. I am also fairy new to requirejs so if I am doing something incredibly wrong, please tell me.
No matter what I do, everything seems to be fine, both canvases are created, all have the right properties, but the second one I am putting on the first one is not displayed. If I put plain image instead of canvas it works just fine, but canvas on canvas does not.
This drives me nuts, I tried so many possibilities, the code works just fine without all the requirejs stuff, but fails when I structure it that way. Does it have something to do with global scopes? How to make this work? I need canvas inside canvas.
Thank you for your time!
EDIT:
I have only <script data-main="main" src="libs/require/require.js"></script> loaded in my html file and <canvas id="game"></canvas> in body.
Then in main.js I have:
require.config({
baseUrl: "./modules",
waitSeconds: 10,
packages: [
{
name: "something not used yet",
location: "something not used yet",
main: "something not used yet"
}
]
});
require(['game'], function (Game)
{
var game = new Game();
game.begin();
});
Rest I already showed in the beginning.
I have main.html and main.js together in the build folder and all the others in build/modules folder.

Problem was the most ridiculous thing ever and I wasted way to much time to figure out something this obvious...
For some reason I completely forgot to wait for the image to load and kept using it before it is even loaded, and the complicated (for me at least) structure when using requirejs made it hard to pinpoint that mistake.
Also without requirejs the code worked because image loaded so fast, it was ready before the next function started even without onload, however when I switched to requirejs I guess it either slowed down, or the asynchronous nature of it created the problem.
Anyway, solved by simple onload handler.

Related

Using Processing's loadImage in JavaScript

I am using the Processing API to draw an image to my HTML canvas, which I can use later in the code. The JavaScript code that I have is:
var sketchProc = function(processingInstance) {
with (processingInstance) {
/* #pjs preload="images/hot-air.png" */
size(innerWidth, innerHeight);
var testImage = loadImage("images/hot-air.png");
draw = function() {
image(testImage, 0, 0, 500, 500);
}
}
}
var canvas = document.getElementById("canvas");
var processingInstance = new Processing(canvas, sketchProc);
The console says that the image has dimensions 0x0. I tried loading with Processing's directives, but I am still getting an image dimensions of 0x0. However, when I call loadImage() inside the draw loop, the program recognizes the image's dimensions of 512x512.
I do not want to continuously call loadImage() inside the draw loop. What should I do to make sure that the image loads properly outside the draw loop?
You can find a minimal working example here.
First off, thanks for posting an MCVE for us to play with.
I believe the problem is that, for some reason, the preload directive, and maybe the loadImage() function itself, doesn't work when you're writing JavaScript-only Processing.js code. I've tested this in various editors and versions of Processing.js.
So it appears that to use the loadImage() function, you should use pure Processing code. Here is a CodePen that shows how you'd do that:
<script type="application/processing">
/* #pjs preload="https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg"; */
PImage testImage;
void setup(){
size(500, 500);
testImage = loadImage("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg");
println(testImage.height);
}
void draw() {
background(100);
image(testImage, 0, 0, 250, 250);
}
</script>
<canvas> </canvas>
Just for comparison, here is the same code using JavaScript-only syntax. This doesn't work.
But taking a step back: if you're comfortable using JavaScript, then why are you using Processing.js? Processing.js is designed for Processing (Java) developers who want to write Java syntax that's automagically converted to JavaScript. At this point Processing.js is pretty old and no longer maintained.
Instead, I'd recommend using P5.js. P5.js allows you to write JavaScript syntax to create web-first Processing sketches. P5.js is much newer and is still being actively developed.
Here is the same code in P5.js:
var testImage;
function preload(){
testImage = loadImage("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg");
}
function setup() {
createCanvas(400, 400);
}
function draw() {
background(100);
image(testImage, 0, 0, 250, 250);
}
Shameless self-promotion: I wrote a tutorial on the differences between Processing, Processing.js, and P5.js available here.

Save Empscripten webGL canvas as image in JS

I have an Emscripten-driven webGL canvas that I need to save as an image from a Javascript handler. Let's say there's a simple JS "Save" button.
<script type="text/javascript">
var Exporter = {
preRun: [],
postRun: [],
save: function() {
var c=Module.canvas;
var d=c.toDataURL("image/png");
var w=window.open('about:blank','image from canvas');
w.document.write("<img src='"+d+"' alt='from canvas'/>");
}
};
</script>
<input type="button" value="Save" onclick="Exporter.save()" />
By default, the webGL context has preserveDrawingBuffer set to false, so the resulting image is blank.
For the image to show the rendered webGL scene, I need to add preserveDrawingBuffer: true to the attributes passed in the getContext call inside my compiled Empscripten code. I can do this by hand editing the compiled empscripten js code; the resulting image is then correct, but I'd like to avoid this hack - I'd have to do it after each recompile.
Is there and easier and cleaner way to add preserveDrawingBuffer to the webGLContextAttributes from outside? i.e. as a compile option for emcc, some SDL parameter inside the C code or from Javascript in the hosting page?
UPDATE
See below for the solution; unrelated issue I encountered was that the saved image had lower bit depth and anti-aliased lines looked pretty bad. Using c.toDataURL( "image/jpeg" ) solved that.
Well, first off, all of emscripten and all of it's libraries are open source so you can just go change them.
In particular copy library_gl.js to your project folder and then remove -lGL and add --js-library library_gl.js to your build script, you can then hack your local library_gl.js to do whatever you want.
Otherwise I don't know SDL at all but you can just get the context yourself before your call the emscripten code. A canvas can only have one context, if you call getContext again for the same type of context you'll get the same context. In other words if your JavaScript creates the context first the emscripten code will get the same context
so this should work
theCanvasElement.getContext("webgl", {preserveDrawingBuffer: true});
... now execute emscripten and have it use `theCanvasElement`
If you can't even do that you can override getContext
HTMLCanvasElement.prototype.getContext = (function(oldGetContextFn) {
return function(type, attrs) {
attrs = attrs || {};
if (type === "webgl") {
attrs.preserveDrawingBuffer = true;
}
return oldGetContextFn.call(this, type, attrs);
};
}(HTMLCanvasElement.prototype.getContext));

Store/Import variables & functions Processing(JS)

Stack Overflow! I wanted to store variables in another file so that I would load the variables in file 1, and draw the scene in file 2, ex.
closet.js
var message = "Hello there";
drawer.js
draw = function() { text(message, 100, 100); };
So I would do something like that, but instead of importing the files like this;
<canvas data-processing-sources="closet.js drawer.js"></canvas>
I wanted to be able to include them in file 2, sort of like this;
closet.js
var message = "Hello there";
drawer.js
import("closet.js");
draw = function() {
text(message, 100, 100);
};
Is there a way to do this without including them in the HTML file itself?
Thanks in advance :)
Check out this question, which yours might even be a duplicate of. It lists several ways to do this in JavaScript, including using JQuery or dynamically adding the <script> tags to the <head> of your page.
But if you're using the Processing editor, you have another option: use classes by creating a new tab in the Processing editor. For all your purposes, you can treat this as a separate file. So lets say you created a separate Closet tab with a message variable. Your main sketch code might look like this:
Closet c = new Closet();
draw = function() {
text(c.message, 100, 100);
};
I think this is probably the way to go. It seems like you're trying to over-engineer a solution: either include the files in the html (this is what 99% of all JavaScript code does) or use a class (this is what 99% of all Processing code does).

Rendering bug coffeescript to js in Rails 4.1?

i have just build a normal RoR 4.1 app, nothing added, to test some coffee script code.
This is the start of the coffee script code
->
canvas
ctx
code
point
style
drag = null
dPoint
# define initial points
Init (quadratic) ->
point =
p1:
x: 100
y: 250
p2:
x: 400
y: 250
if quadratic
point.cp1 =
x: 250
y: 100
else
point.cp1 =
x: 150
y: 100
point.cp2 =
x: 350
y: 100
when rendering in Javascript via the coffee script site it give me that, which seems right
(function() {
canvas;
ctx;
code;
var canvas, code, ctx, drag;
drag = null;
Init(function(quadratic) {
var point, style;
point = {
...
But when i watch the code generate by rails i see this (and nothing work)
(function() {
(function() {
canvas;
ctx;
code;
var canvas, code, ctx, drag;
drag = null;
dPoint;
Init(function(quadratic) {
.....
do you have any idea what's happened, why is it encapsulated in another function ?
do you need more code ?
best regards
Rails wraps any coffee script in an anonymous function when compiling it, so this is actually valid.
So even something as simple as:
x = 1
in coffeescript, gets compiled to:
(function() {
var x;
x = 1;
}).call(this);
In rails javascript. Hence why your sample is compiling to an anonymous function within an anonymous function. Here's the sprockets code that does it:
https://github.com/sstephenson/sprockets/blob/master/lib/sprockets/jst_processor.rb
You could use global variables to get around this, but I wouldn't recommend it, instead, look to create a module system.
Thanks for the answer,
i removed the '->' on top and it works now, it's javascript in an anonymous function.
i wonder what will appends if i write a 'jQuery ->' in top of the script when calling a Jquery plugin, but it seems it as changed since the introduction of turbo-links. but this is another question.
thanks you my current code work now

Fabric.js loadSVGFromUrl not displaying multiple imported SVGS

I'm using fabric.js and loading a number of SVG files into it. I have no problem displaying one of these imported files using this code;
fabric.loadSVGFromURL('ico-svg/drink.svg', function(objects, options) {
var drink = fabric.util.groupSVGElements(objects, options);
drink.set({left: 80,
top: 175,
width: 32,
height: 32 });
canvas.add(drink);
canvas.calcOffset();
canvas.renderAll();
});
However, when I repeat this code, the page only shows one of the two SVGs, and they actually change upon page refresh - only one icon will show one time, one icon will show the other, on the odd occasion they will both show but one of the SVGs won't display completely.
To load the other SVG, i'm simply copying the above code and changing the required variables;
fabric.loadSVGFromURL('exporttest.svg', function(objects, options) {
var dollars = fabric.util.groupSVGElements(objects, options);
dollars.set({left: 80,
top: 90,
width: 350,
height: 342 });
canvas.add(dollars);
canvas.calcOffset();
canvas.renderAll();
});
fabric.loadSVGFromURL('ico-svg/drink.svg', function(objects, options) {
var drink = fabric.util.groupSVGElements(objects, options);
drink.set({left: 80,
top: 175,
width: 32,
height: 32 });
canvas.add(drink);
canvas.calcOffset();
canvas.renderAll();
});
Is this something i'm doing wrong? I've read that the library support for loading SVGs from URLs isn't that fantastic - could it be that? Ideally, loading the SVGs from an URL this way or in a similar way is my best option as there are so many, and they are each quite complex and require different positioning.
I think this was a bug that has been fixed in the library.
Current fabricjs.com offer a kitchensink demo where you can try code.
http://fabricjs.com/kitchensink/
copy paste the code below in the execute tab to load 3 svg togheter without any strange issue or taking any precaution.
// clear canvas
canvas.clear();
// remove currently selected object
canvas.remove(canvas.getActiveObject());
fabric.loadSVGFromURL('../assets/1.svg', function(objects, options) {
var dollars = fabric.util.groupSVGElements(objects, options);
canvas.add(dollars);
canvas.calcOffset();
canvas.renderAll();
});
fabric.loadSVGFromURL('../assets/2.svg', function(objects, options) {
var drink = fabric.util.groupSVGElements(objects, options);
canvas.add(drink);
canvas.calcOffset();
canvas.renderAll();
});
fabric.loadSVGFromURL('../assets/3.svg', function(objects, options) {
var drink = fabric.util.groupSVGElements(objects, options);
canvas.add(drink);
canvas.calcOffset();
canvas.renderAll();
});
I actually do this as well, where a user can select any number of SVG files to load and later come back to edit their work. When they come back, I had the same issue while trying to reload the multiple files. In my case, I am actually building an array of objects that hold the svg url along with other useful pieces of information. This allowed me to load them into a stack (most suiting for my loading order, though you could easily implement it with a queue) and then pop them off one at a time.
var loadingLayerStack = [url1, url2, url3];
function ProcessLayerLoading()
{
var layerUrl = loadingLayerStack.pop();
DrawSvgToCanvas(layerUrl);
}
function DrawSvgToCanvas(url)
{
fabric.loadSVGFromURL(url, function(objects, options) {
var obj = fabric.util.groupSVGElements(objects, options);
// ...any code for special handling of the loaded object
// put object on the canvas
canvas.add(obj);
// get the next image
ProcessLayerLoading();
});
}
It is noteworthy to point out that I have the setting to enable Rendering when an object is added. So that canvas.add call also takes care of the initial rendering for me.
Hope this helps you somehow. :)
I just ran into this same problem, after seeing your post I decided to dig in to it a bit further myself. It turns out to be due to a scope issue in the onComplete callback within loadSVGFromURL. The problem stems from not isolating the url to a single scope; making multiple back-to-back calls results in the last url always being used when onComplete fires. As a workaround you could either chain your SVG loads or just make an ajax request yourself and load it using loadSVGFromString instead.
I'm learning fabric seems to be full of these bugs, errr, gotchas :(
Edit
I spoke too soon, loadSVGFromString suffers from the same weakness, it does not work asynchronously. That being said chaining is the most obvious work-around.
fabric.loadSVGFromURL() fetches the SVG via XmlHttpRequest. If you wait for each request to complete you can load multiple. Which means you need a tool for making and composing asynchronous promises in JavaScript. Check out q. https://github.com/kriskowal/q

Categories

Resources