Generate multiple images from loop - javascript

I tried to write a loop, that loads the image from local path. For that i try to use Konva:
const playerLayer = new Konva.Layer();
var playerAmount = 1;
while (playerAmount < 6) {
var playerIcon = new Image();
var playerInstance = new Konva.Image({
x: 660,
y: 140,
image: playerIcon,
width: 32,
height: 32
});
playerIcon.src = "media/heroes/hero1.png";
playerLayer.add(playerInstance);
playerAmount++;
}
stage.add(playerLayer);
For some reason images don't appear.
What i checked:
Konva.Image's succesfully become children of the PlayerLayer, i can see them in code inspector
Layer appears on the page, there is just nothing on it (i can see it in inspector)
Replacing image with simple shapes (Regular.Polygon) works fine.

You need to redraw the layer when an image is loaded:
playerIcon.onload = function() {
playerLayer.batchDraw();
}

Related

Canvas to PDF, HTML, Konva.js

I am working about draggable objects on Konva stage. I want to the canvas object layer turn to PDF. I use toDataURL. Like this;
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height,
id: 'stage',
});
var grid_layer = new Konva.Layer();
var object_layer = new Konva.Layer();
stage.add(grid_layer);
stage.add(object_layer);
function updateScreen() {
object_layer.batchDraw()
}
function downloadURI(uri, name) {
var link = document.createElement('a');
link.download = name;
link.href = uri;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
delete link;
}
document.getElementById('save').addEventListener(
'click',
function() {
var dataURL = stage.toDataURL({ pixelRatio: 3 });
downloadURI(dataURL, 'stage.png');
},
false
);
Save button work without objects and save canvas image. But when i run the code with objects on stage, the page reloads and the button doesn't work. doesn't save canvas image
I would strongly recommend to doing it like shown in the Konva Wiki.
// Code form KonvaJS wiki
var pdf = new jsPDF('l', 'px', [stage.width(), stage.height()]);
pdf.setTextColor('#000000');
// first add texts
stage.find('Text').forEach((text) => {
const size = text.fontSize() / 0.75; // convert pixels to points
pdf.setFontSize(size);
pdf.text(text.text(), text.x(), text.y(), {
baseline: 'top',
angle: -text.getAbsoluteRotation(),
});
});
// then put image on top of texts (so texts are not visible)
pdf.addImage(
stage.toDataURL({ pixelRatio: 2 }),
0,
0,
stage.width(),
stage.height()
);
pdf.save('canvas.pdf');
This should add all text and other objects to a pdf.
From the comments, I can conclude that you don't host the images using the server you use for the konva stuff. You can't access the images from your website as they are not from the same origin. This helps secure the files on your computer from the access of websites like yours. So you would have to move the images to the server and access them from there.

draw images in a layer and align them as a matrix

How can I make the images that I call in a for loop in KineticJS to be aligned in a kind of matrix?
The behavior that I want to have is to draw them four by four. I don't know their exact number, since I'm using a database to call their paths, so I just use a for loop.
EDIT
I changed the code sample with a fiddle to make things simpler : http://jsfiddle.net/tg8TM/
So I did this test
imageObj.onload = function() {
var ligne = 1;
for (var i=0; i<10; i++) {
var img = new Kinetic.Image({
x: 100*i,
y: 50,
image:imageObj,
width: 100,
height: 100
});
if (img.getX()>stage.getWidth()){ //maybe I should use if (i%4 ===0)
ligne++;
img.setX(100* ligne+1);
img.setY(50 * (ligne+1) );
layer.add(img);
layer.draw();
}
else {
layer.add(img);
layer.draw();
}
};
}
Here, the images in the end of the stage should be set to another x,y to be drawn in another "line" (like \n). Instead, the output now is diagonal images. Please help me to figure out how to make it. Did I miss something?
You can draw your imageObj in rows/cols within the stage like this:
(untested code alert!)
var w=imageObj.width;
var h=imageObj.height;
var nextX=0;
var nextY=0;
for(var i=0;i<10;i++){
var img=new Kinetic.Image({
x:nextX,
y:nextY,
...
});
nextX+=w;
if(nextX+w>stage.getWidth()){
nextX=0;
nextY+=h;
}
}

Using canvas to create desktop notification images, only one image works from background page

I'm having an issue while using canvas in a background page to create data URLs for desktop notifications' images.
I want to use the "image" notifications which require a 3:2 ratio to display properly. The images I want to use (from hulu.com) are a different ratio, so I decided to use the canvas element to create the corresponding data URL off of these images so that the ratio is correct. It kind of works in theory, but…
…I'm having issues if I'm creating more than one canvas/notification in the background page. One image is created properly, but the rest comes out empty.
Confusingly, opening the same background page in a new tab (i.e. exact same code) makes everything works just fine: all the notifications are created with the images loaded from hulu.com. Also, just changing the dimensions from 360x240 to 300x200 makes it work. Finally, though they're similar computers with the same Chrome version (34.0.1847.116), it works without modification at work while it doesn't on my own laptop.
I made a test extension available at the bottom of this post. Basically, it only has a generated background page. The code for that page is this:
var images = ["http://ib2.huluim.com/video/60376901?size=290x160&img=1",
"http://ib2.huluim.com/video/60366793?size=290x160&img=1",
"http://ib4.huluim.com/video/60372951?size=290x160&img=1",
"http://ib1.huluim.com/video/60365336?size=290x160&img=1",
"http://ib3.huluim.com/video/60376290?size=290x160&img=1",
"http://ib4.huluim.com/video/60377231?size=290x160&img=1",
"http://ib4.huluim.com/video/60312203?size=290x160&img=1",
"http://ib1.huluim.com/video/60376972?size=290x160&img=1",
"http://ib4.huluim.com/video/60376971?size=290x160&img=1",
"http://ib1.huluim.com/video/60376616?size=290x160&img=1"];
for (var i = 0; i < 10; i++) {
getDataURL(i);
}
/*
* Gets the data URL for an image URL
*/
function getDataURL(i) {
var img = new Image();
img.onload = function() {
var canvas = document.createElement('canvas');
canvas.width = 360;
canvas.height = 240;
var ctx = canvas.getContext('2d');
ctx.drawImage(this, 0, 0);
ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect (10, 10, 55, 50);
var dataURL = canvas.toDataURL('image/png');
chrome.notifications.create('', {
type: 'image',
iconUrl: 'logo_128x128.png',
title: String(i),
message: 'message',
imageUrl: dataURL
}, function(id) {});
}
//img.src = chrome.extension.getURL('logo_128x128.png');;
img.src = images[i];
}
The commented out line for img.src = ... is a test where it loads a local file instead of a remote one. In that case, all the images are created.
The red rectangle added to the canvas is to show that it's not just the remote image that is an issue: the whole resulting canvas is empty, without any red rectangle.
If you download and add the test extension below, you should get 10 notifications but only one with an image.
Then, to open the background page in a new tab, you can inspect the background page, type this in the console:
chrome.extension.getURL('_generated_background_page.html')
and right-click the URL, and click "Open in a new Tab" (or window). Once open you should get 10 notifications that look fine.
Any idea of what is going on? I haven't been able to find any kind of limitations for background pages relevant to that. Any help would be appreciated, because this has been driving me crazy!
Files available here: https://www.dropbox.com/s/ejbh6wq0qixb7a8/canvastest.zip
edit: based on #GameAlchemist's comment, I also tried the following: same getDataURL method, but the loop wrapped inside an onload for the logo:
function loop() {
for (var i = 0; i < 10; i++) {
getDataURL(i);
}
}
var logo = new Image();
logo.onload = function () {
loop();
}
logo.src = chrome.extension.getURL('logo_128x128.png');
Remember that the create() method is asynchronous and you should use a callback with. The callback can invoke next image fetching.
I would suggest doing this in two steps:
Load all the images first
Process the image queue
The reason is that you can utilize the asynchronous image loading better this way instead of chaining the callbacks which would force you to load one and one image.
For example:
Image loader
var urls = ["http://ib2.huluim.com/video/60376901?size=290x160&img=1",
"http://ib2.huluim.com/video/60366793?size=290x160&img=1",
"http://ib4.huluim.com/video/60372951?size=290x160&img=1",
"http://ib1.huluim.com/video/60365336?size=290x160&img=1",
"http://ib3.huluim.com/video/60376290?size=290x160&img=1",
"http://ib4.huluim.com/video/60377231?size=290x160&img=1",
"http://ib4.huluim.com/video/60312203?size=290x160&img=1",
"http://ib1.huluim.com/video/60376972?size=290x160&img=1",
"http://ib4.huluim.com/video/60376971?size=290x160&img=1",
"http://ib1.huluim.com/video/60376616?size=290x160&img=1"];
var images = [], // store image objects
count = urls.length; // for loader
for (var i = 0; i < urls.length; i++) {
var img = new Image; // create image
img.onload = loader; // share loader handler
img.src = urls[i]; // start loading
images.push(img); // push image object in array
}
function loader() {
count--;
if (count === 0) process(); // all loaded, start processing
}
//TODO need error handling here as well
Fiddle with concept code for loader
Processing
Now the processing can be isolated from the loading:
function process() {
// share a single canvas (use clearRect() later if needed)
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d'),
current = 0;
canvas.width = 360;
canvas.height = 240;
createImage(); // invoke processing for first image
function createImage() {
ctx.drawImage(images[current], 0, 0); // draw current image
ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect (10, 10, 55, 50);
chrome.notifications.create('', {
type : 'image',
iconUrl : 'logo_128x128.png',
title : String(i),
message : 'message',
imageUrl: canvas.toDataURL() // png is default
},
function(id) { // use callback
current++; // next in queue
if (current < images.length) {
createImage(); // call again if more images
}
else {
done(); // we're done -> continue to done()
}
});
}
}
Disclaimer: I don't have a test environment to test Chrome extensions so typos/errors may be present.
Hope this helps!

cc.sprite.create not working? cocos2d-html

I am new to Cocos2d-html5 v2.2.1 and I am trying to add a sprite (simple image) to the canvas. The code does add an image with the correct width and height but it is just black.
I cant seem to find any errors so I am kinda stuck.
Any help would be great. My code is below:
In main.js i load the resources:
applicationDidFinishLaunching:function () {
if(cc.RenderDoesnotSupport()){
//show Information to user
alert("Browser doesn't support WebGL");
return false;
}
// initialize director
var director = cc.Director.getInstance();
//cc.EGLView.getInstance()._adjustSizeToBrowser();
//cc.EGLView.getInstance()._resizeWithBrowserSize(true);
//cc.EGLView.getInstance().setDesignResolutionSize(600, 400, cc.RESOLUTION_POLICY.SHOW_ALL);
// set FPS. the default value is 1.0/60 if you don't call this
director.setAnimationInterval(1.0 / this.config['frameRate']);
//load resources
cc.LoaderScene.preload(g_resources, function () {
director.replaceScene(new this.startScene());
}, this);
return true;
}
g_resources is defined in resource.js:
var s_jet = "images/jet.png";
var s_character = "images/p1_front.png";
var g_resources = [
//image
{src:s_jet},
{src:s_character}];
spriteScene.js:
init:function () {
var selfPointer = this;
this._super();
var size = cc.Director.getInstance().getWinSize();
var lazyLayer = cc.LayerColor.create(new cc.Color4B(45, 50, 128, 255), 600, 600);
//var lazyLayer = cc.Layer.create();
lazyLayer.setAnchorPoint(new cc.Point(0.5,0.5));
var characterSprite = cc.Sprite.create("./images/p1_front.png");
lazyLayer.addChild(characterSprite, 0);
this.addChild(lazyLayer);
var rotateToA = cc.RotateTo.create(2, 0);
var scaleToA = cc.ScaleTo.create(2, 1, 1);
characterSprite.setPosition(new cc.Point(size.width/2,size.height/2));
I just dont understand why the sprite is just being drawn as a black box.
Edit: When I uncomment the line below from main.js; at first the image is still black but when I resize the browser, the image appears:-
cc.EGLView.getInstance().setDesignResolutionSize(600, 400, cc.RESOLUTION_POLICY.SHOW_ALL);
I dont know what this is implying.
Ok guys! I figured it out and I am pissed. Changed this line:
this.characterSprite.setPosition(new cc.Point(size.width/2,size.height/2));
to:
this.characterSprite.setPosition(cc.p(size.width/2, size.height/2));
Documentation/tutorials for cocos2d-html5 are outdated and this is getting frustrating.

How to save x and y position to a jSon file after drag and drop?

In my code bellow Im displaying the x and y coordinates when Im dragging "var rec" in a alert box.
Now I wanna save the new coordinates x and y to a jSon file when stoped dragging "var rec".
I started testing with this line of code:
dragend.data("dragend").originalPosition
window.onload = function() {
var stage = new Kinetic.Stage({
container : "container",
width : 1400,
height : 1448
});
var layer = new Kinetic.Layer();
stage.add(layer);
var rect = new Kinetic.Rect({
x: 50,
y: 50,
width: 50,
height: 50,
fill : 'black'
});
var group = new Kinetic.Group({
draggable: true
});
group.add(rect);
layer.add(group);
group.on('dragend',function(){
alert(group.getPosition().x+"/"+group.getPosition().y);
});
layer.draw();
}
you can use jQuery plugin jQuery.twFile that allows you to read and write to a local file.
Stringify you data and save it to file.
var data = JSON.stringify(yourObject);
It depends for how long you want to save it. You can use the localStorage.
Please, take a look here:
localStorage Definition and Usage

Categories