Draw2D Set Position - javascript

I am new to this library and cannot seem to find anything that gives good detail on how to size and position the canvas. Hopefully someone here can direct me in the best way of positioning the canvas
$(window).load(function () {
// create the canvas for the user interaction
//
var canvas = new draw2d.Canvas("gfx_holder");
// unmarshal the JSON document into the canvas
// (load)
var reader = new draw2d.io.json.Reader();
reader.unmarshal(canvas, jsonDocument);
// display the JSON document in the preview DIV
//
displayJSON(canvas);
// add an event listener to the Canvas for change notifications.
// We just dump the current canvas document into the DIV
//
canvas.getCommandStack().addEventListener(function (e) {
if (e.isPostChangeEvent()) {
displayJSON(canvas);
}
});
});
function displayJSON(canvas) {
var writer = new draw2d.io.json.Writer();
writer.marshal(canvas, function (json) {
$("#json").text(JSON.stringify(json, null, 2));
});
}

"gfx_holder" is the id of your HTML element. You can set the width and height using regular JavaScript.

Related

Dom doesn't update right away when using convertToBlob on an Offscreen canvas

I have an application that needs to generate a couple thousand images. The way that I'm doing that is with a set of preloaded pngs (acting as transparent layers) and an offscreen canvas. I draw the images onto the canvas, convert it to a blob, and then write the image to a div using a custom class called Images.
I want to show a loading bar and clear old images, first, but there is a 3-5 second delay before the dom updates even though the "empty()" and "show()" code is at the beginning of the click request.
Is there something I'm doing wrong with regard to the asynchrony or promises that is causing the dom to not update immediately?
Here's some of the code:
// Generate Images
$("#generate_images").click(function(){
// Show loading bar
$("#progress_bar .progress-bar").css("width", "0%");
$("#progress_bar").show(0);
// Show loading spinner
$("#loading").show(0);
$("#images").empty();
console.log("Generating Images");
$.each(images, function(id, image){
// Sort traits (png layers)
var traits = Object.values(image.traits).sort((a, b) => {
return a.z_index - b.z_index;
});
images[id].layers = [];
$.each(traits, function(trait_idx, trait){
images[id].layers.push(preloaded_images[trait.variant_id])
});
});
// Create canvas
var canvas = new OffscreenCanvas(1200, 1200);
var context = canvas.getContext("2d");
console.log("Generating canvases.");
$.each(images, function(id, image){
// Clear the canvas
context.clearRect(0, 0, canvas.width, canvas.height);
// Draw each image layer
$.each(images.layers, function(src, layer){
context.drawImage(layer, 0, 0);
});
// Add imageData to screen
canvas.convertToBlob().then(function(blob) {
// Do something with the blob like render to the screen
});
});
});
Any thoughts on making this more efficient would also be appreciated.
Generating a thousand images is not something a browser is necessarily meant to do, but you need to give the DOM a chance to update so add a timeout
Collect what you want to do in an array
Do not loop, but instead do
function generate() {
if (arrayCounter >= array.length) return
canvas.convertToBlob().then(function(blob) {
if (success) {
arrayCounter++
generate()
}
}
}
collect()
generate()

Canvas Element In Closure Is Being Changed Unexpectedly

I am working on creating a webpage that will allow users to add color filters to images they upload. In order to do this I wish to keep an original copy of the image stored in a canvas. Then whenever a user changes one of the color values, using a range slider I want to copy the original image into a new canvas edit it and then plot the new image.
The reason I don't want to apply changes directly to the original image is that they can be difficult to reverse. For example if the user set the blue channel of an image to 0 then unless I have the original image the user would not be able to undo that effect.
My current solution was to create a closure holding a canvas element. This closure is initialized when the user uploads their photo. The code for my closure is below
var scaleCanvas = (function() {
var scaledCvs = document.createElement('canvas'); //Creates a canvas object
var scaledCtx = scaledCvs.getContext("2d"); //Gets canvas context
// All the functions in this section can access scaledCanvas
return {
init: function(cvs) {
scaledCvs = cvs;
console.log("Image Stored")
}, //close init
getImg: function() {
return (scaledCvs);
} //Close getImg
}; //close return
})();
Once the canvas is initialized it can be accessed using the scaleCanvas.getImg() function. An example of this would be during my function adjustFilters() which is called by a range slider element as below
<div class="slidecontainer">
<label>Blue Channel</label>
<input type="range" min="0" max="150" value="100" class="slider" id="blue" onchange="adjustFilters();"/>
</div>
Once the blue slider is changed I load the canvas that I want to use to display the image. Then I load my original image using scaleCanvas.getImg(). Then I apply the effects I am interested in. Then I draw the image. What is strange though is that it appears the scaledCvs variable in my closure is being changed. I say this because if I select a value for "blue" as 0 then it is impossible for me to recover the original blue channel. This should not happen unless the scaledCvs in my closure is being altered somehow.
function adjustFilters() {
var canvas = document.getElementById("dispImg"); //gets the canvas element
canvas.style.display = "block"; //Makes the canvas visible
var context = canvas.getContext("2d"); //Using 2D context
// look up the size the canvas is being displayed at
const width = canvas.clientWidth;
const height = canvas.clientHeight;
var imgCV = scaleCanvas.getImg(); //Gets the original canvas image
var imgCtx = imgCV.getContext('2d');
var blue = document.getElementById("blue").value / 100; //Gets value of the blue slider
// Adjusts blue channel
adjustColor(imgCtx, imgCV.height, imgCV.width, "blue", blue)
// Draws the Image
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(imgCV, 0, 0);
}
I am looking for suggestions on how to get my code to operate as expected. i.e I need the variable scaledCvs in my closure to not be adjusted except for when the init function is called.
Thank You
The reason for the observed behavior is that canvas elements are passed by reference therefore
init: function(cvs) {
scaledCvs = cvs;
console.log("Image Stored")
}, //close init
Does not create a copy of cvs it just creates a reference to it. In order to create a copy of the actual canvas you would need to follow the protocol below
init: function(cvs) {
//Create a Copy of the provided canvas (cvs)
scaledCvs.width=cvs.width;
scaledCvs.height=cvs.height;
scaledCtx.drawImage(cvs,0,0);
}, //close init
For the entire code to work properly you would also need to modify getImage() so that it is not passed a reference of scaledCvs. The final closure definition would be
var scaleCanvas = (function() {
var scaledCvs=document.createElement('canvas'); //Creates a canvas object
var scaledCtx=scaledCvs.getContext("2d"); //Gets canvas context
// All the functions in this section can access scaledCanvas
return {
init: function(cvs) {
//Create a Copy of the provided canvas (cvs)
scaledCvs.width=cvs.width;
scaledCvs.height=cvs.height;
scaledCtx.drawImage(cvs,0,0);
}, //close init
getImg: function() {
//Since canvas are passed by reference in order to protect the saved canvas I have to create a copy before passing it out
var cpCanvas = document.createElement('canvas');
var context = cpCanvas.getContext("2d");
cpCanvas.height = scaledCvs.height;
cpCanvas.width = scaledCvs.width;
context.drawImage(scaledCvs,0,0);
return(cpCanvas);
} //Close getImg
}; //close return
})();
All other code can remain the same.

how to find the mouse position x/y using phaser

I'm having problems, trying to display the mouse position x/y when they click on an image, im using one of the click on and image example that phaser provides.
here is the code
var game = new Phaser.Game(800, 500, Phaser.AUTO, 'phaser-example', { preload: preload, create: create });
var text;
var counter = 0;
function preload () {
// You can fill the preloader with as many assets as your game requires
// Here we are loading an image. The first parameter is the unique
// string by which we'll identify the image later in our code.
// The second parameter is the URL of the image (relative)
game.load.image('Happy-face', 'happy.png');
}
function create() {
// This creates a simple sprite that is using our loaded image and
// displays it on-screen and assign it to a variable
var image = game.add.sprite(game.world.centerX, game.world.centerY, 'Happy-face');
// Moves the image anchor to the middle, so it centers inside the game properly
image.anchor.set(0.5);
// Enables all kind of input actions on this image (click, etc)
image.inputEnabled = true;
this.position = new Phaser.Point();
text = game.add.text(250, 16, '', { fill: '#ffffff' });
image.events.onInputDown.add(listener, this);
}
function listener () {
counter++;
text.text = "Position x/y " + counter + "!";
}
if you want x and y position o f input
game.input.x;
game.input.y;
if you want for mouse specifically
game.input.mousePointer.x;
game.input.mousePointer.y;
the listener function will be like
function listener () {
counter++;
text.text = game.input.mousePointer.x +"/"+game.input.mousePointer.y + counter + "!";
}
Just to add that the listener function will be sent 2 parameters: sprite and pointer. So you can do:
function listener (sprite, pointer) {
var x = pointer.x;
var y = pointer.y;
...
}
This will be the most accurate method to use as it accounts for multi-touch devices, where-as accessing input.x/y directly doesn't, it only contains the most recent touch event coordinates (which in a mouse only environment is fine, but not anywhere else).

jQuery and Canvas loading behaviour

After being a long time lurker, this is my first post here! I've been RTFMing and searching everywhere for an answer to this question to no avail. I will try to be as informative as I can, hope you could help me.
This code is for my personal webpage.
I am trying to implement some sort of a modern click-map using HTML5 and jQuery.
In the website you would see the main image and a hidden canvas with the same size at the same coordinates with this picture drawn into it.
When the mouse hovers the main picture, it read the mouse pixel data (array of r,g,b,alpha) from the image drawn onto the canvas. When it sees the pixel color is black (in my case I only check the RED value, which in a black pixel would be 0) it knows the activate the relevant button.
(Originally, I got the idea from this article)
The reason I chose this method, is for the page to be responsive and dynamically change to fit different monitors and mobile devices. To achieve this, I call the DrawCanvas function every time the screen is re-sized, to redraw the canvas with the new dimensions.
Generally, this works OK. The thing is ,there seems to be an inconsistent behavior in Chrome and IE(9). When I initially open the page, I sometimes get no pixel data (0,0,0,0), until i re-size the browser. At first I figured there's some loading issues that are making this happen so I tried to hack it with setTimeout, it still doesn't work. I also tried to trigger the re-size event and call the drawCanvas function at document.ready, still didn't work.
What's bothering me is most, are the inconsistencies. Sometimes it works, sometimes is doesn't. Generally, it is more stable in chrome than in IE(9).
Here is the deprecated code:
<script type="text/javascript">
$(document).ready(function(){setTimeout(function() {
// Get main image object
var mapWrapper = document.getElementById('map_wrapper').getElementsByTagName('img').item(0);
// Create a hidden canvas the same size as the main image and append it to main div
var canvas = document.createElement('canvas');
canvas.height = mapWrapper.clientHeight;
canvas.width = mapWrapper.clientWidth;
canvas.fillStyle = 'rgb(255,255,255)';
canvas.style.display = 'none';
canvas.id = 'hiddencvs';
$('#map_wrapper').append(canvas);
// Draw the buttons image into the canvas
drawCanvas(null);
$("#map_wrapper").mousemove(function(e){
var canvas = document.getElementById('hiddencvs');
var context = canvas.getContext('2d');
var pos = findPos(this);
var x = e.pageX - pos.x;
var y = e.pageY - pos.y;
// Get pixel information array (red, green, blue, alpha)
var pixel = context.getImageData(x,y,1,1).data;
var red = pixel[0];
var main_img = document.getElementById('map_wrapper').getElementsByTagName('img').item(0);
if (red == 0)
{
...
}
else {
...
}
});
},3000);}); // End DOM Ready
function drawCanvas(e)
{
// Get context of hidden convas and set size according to main image
var cvs = document.getElementById('hiddencvs');
var ctx = cvs.getContext('2d');
var mapWrapper = document.getElementById('map_wrapper').getElementsByTagName('img').item(0);
cvs.width = mapWrapper.clientWidth;
cvs.height = mapWrapper.clientHeight;
// Create img element for buttons image
var img = document.createElement("img");
img.src = "img/main-page-buttons.png";
// Draw buttons image inside hidden canvas, strech it to canvas size
ctx.drawImage(img, 0, 0,cvs.width,cvs.height);
}
$(window).resize(function(e){
drawCanvas(e);
}
);
function findPos(obj)
{
...
}
</script>
I'd appreciate any help!
Thanks!
Ron.
You don't wait for the image to be loaded so, depending on the cache, you may draw an image or not in the canvas.
You should do this :
$(function(){
var img = document.createElement("img");
img.onload = function() {
var mapWrapper = document.getElementById('map_wrapper').getElementsByTagName('img').item(0);
...
// your whole code here !
...
}
img.src = "img/main-page-buttons.png";
});

Variable values aren't available for use after image.onload?

I'm using Canvas to perform a couple of things on an image which is loaded/drawn using image.onload & context.drawImage combo. I'm calculating the bounding size for scaling the images using a simple function which returns the values. I need those values for use at a later point in my code, but no matter what I do, I'm not able to assign the values to a variable. I'm also not able to access my Canvas's styleheight/stylewidth attributes after I assign it the calculated dimensions.
Here's a pseudos ample of my code
$(document).ready(function(){
//Canvas access, context reference etc here.
//Since I'm assigning styles to the canvas on the fly, the canvas has no ht/wdt yet
var dimes = '';
var image = new Image();
image.onload = function(){
//Apply original image height/width as canvas height/width 'attributes'
//(so that I can save the original sized image)
//Check if the image is larger than the parent container
//Calculate bounds if not
//Apply calculated dimensions as 'style' height/width to the canvas, so that the image fits
dimes = scaleImage(...);
//Works!
console.log(dimes);
//Rest all code
}
image.src = '...';
//Blank!!!
console.log(dimes);
//These all blank as well!!!
jQuery('#mycanvas').height() / width() / css('height') / css('width');
document.getElementById(canvas).style.height / .style.width / height / width;
});
I need to access the calculated dimensions for a 'reset' kind of function, that resets my canvas with the drawn image to the calculated size.
As #apsillers noted, the console.log(dimes) code is being executed after you simply define the image.onload() event handler.
If you want to access dimes outside of image.onload(), you'll need to ensure it's being executed after the image loads... e.g. as a response to a button click.
Put the var dimes = ""; before the $(document).ready() to make it a global variable.
Then if you need to access dimes in an event handler, it's ready for you:
$(document).ready(function() {
var image = new Image();
var dimes = "";
image.onload = function() {
dimes = scaleImage(...);
};
$(button).click(function() {
if (dimes === "") {
// image is not yet loaded
} else {
console.log(dimes);
}
});
});
Of course, dimes will now only be accessible inside this first $(document).ready() event handler. If you add another one (which you can certainly do in jQuery), you'll need to use the $.fn.data() jQuery object method to store dimes:
$(document).ready(function() {
var image;
$(document).data("dimes", ""); // initializes it
image.onload = function() {
$(document).data("dimes", scaleImage(...));
};
});
// some other code
$(document).ready(function() {
$("#myButton").click(function() {
var dimes = $(document).data("dimes");
if (dimes === "") {
// image not yet loaded
} else {
console.log(dimes);
}
});
});
Your img.onload function can run only after the JavaScript execution thread stops being busy, i.e., after your ready function completes. Thus, your console.log(dimes) call is running before your onload function.
Put any code that needs to use dimes inside of the onload function. Otherwise, the code the needs to use dimes might run before the onload handler fires.
http://jsfiddle.net/KxTny/1/
$(document).ready(function(){
var dimes = 0;
var width = 20;
var height = 30;
pass(dimes, width, height);
});​
function pass(dimes, width, height) {
alert(dimes);
alert(height);
alert(width);
}

Categories

Resources