draw images in a layer and align them as a matrix - javascript

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;
}
}

Related

zoom into html canvas

I would like show a cutting of a canvas element in another canvas element. For explanation i have the following structure:
Canvas Element which gets filled it's background by an image. On top of this image i draw a arrow and a possible path. The background-image is really big, which means that i can not get that much Information from this big image. This is the reason for point two.
I would like to show a cutting of the canvas element 1. For example like the following image:
Currently i get the coordinate of the red arrow in canvas element 1, now i would like to do something like a cutting of this section with offset like in the image.
How could i solve something like this with JavaScript / JQuery. In summary i have two canvas elements. One of them is showing a big map with a red arrow which represents the current location (this works already), but now i wanna show a second canvas element with the zoom of this section where the red arrow is. Currently i am getting the coordinates, but no idea how i could "zoom" into an canvas element.
Like some of the current answers said, i provide some code:
My HTML Code, there is the mainCanvasMap, which has a Background Image and there is the zoomCanvas, which should display a section of the mainCanvasMap!
Here is a JavaScript snippet, which renders the red arrow on the map and should provide a zoom function (where the red-arrow is located) to the zoomCanvas Element.
var canvas = {}
canvas.canvas = null;
canvas.ctx = null;
canvas.scale = 0;
var zoomCanvas = {}
zoomCanvas.canvas = null;
zoomCanvas.ctx = null;
zoomCanvas.scale = 0;
$(document).ready(function () {
canvas.canvas = document.getElementById('mainCanvasMap');
canvas.ctx = canvas.canvas.getContext('2d');
zoomCanvas.canvas = document.getElementById('zoomCanvas');
zoomCanvas.ctx = zoomCanvas.canvas.getContext('2d');
setInterval(requestTheArrowPosition, 1000);
});
function requestTheArrowPosition() {
renderArrowOnMainCanvasElement();
renderZoomCanvas();
}
function renderArrowOnMainCanvasElement(){
//ADD ARROW TO MAP AND RENDER THEM
}
function renderZoomCanvas() {
//TRY TO ADD THE ZOOM FUNCTION, I WOULD LIKE TO COPY A SECTION OF THE MAINCANVASMAP
zoomCanvas.ctx.fillRect(0, 0, zoomCanvas.canvas.width, zoomCanvas.canvas.height);
zoomCanvas.ctx.drawImage(canvas.canvas, 50, 100, 200, 100, 0, 0, 400, 200);
zoomCanvas.canvas.style.top = 100 + 10 + "px"
zoomCanvas.canvas.style.left = 100 + 10 + "px"
zoomCanvas.canvas.style.display = "block";
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<!--MY MAIN CANVAS ELEMENT, WHICH HAS A BACKGROUND IMAGE AND WHERE THE ARROW IS RENDEREED-->
<canvas id="mainCanvasMap" style="width:100%; height:100%; background: url('https://image.jimcdn.com/app/cms/image/transf/dimension=624x10000:format=jpg/path/s7d1eecaa5cee1012/image/i4484f962de0bf3c2/version/1543751018/image.jpg') 0% 0% / 100% 100%;"></canvas>
<!-- MY ZOOM CANVAS ELEMENT, SHOULD SHOW A CUTTING OF THE MAINCANVASMAP -->
<canvas id="zoomCanvas" style="height:100%;width:100%"></canvas>
The code is only a pseudo-code, but it shows what i like to do.
Your code is using css for the canvas image, that not always looks the way we think...
I will recommend you to draw everything from scratch, here is a starting point:
canvas = document.getElementById('mainCanvasMap');
ctx = canvas.getContext('2d');
zoomCanvas = document.getElementById('zoomCanvas');
zoomCtx = zoomCanvas.getContext('2d');
var pos = {x:0, y:40}
image = document.getElementById('source');
image.onload = draw;
function draw() {
ctx.drawImage(image,0,0);
setInterval(drawZoom, 80);
}
function drawZoom() {
// simple animation on the x axis
x = Math.sin(pos.x++/10 % (Math.PI*2)) * 20 + 80
zoomCtx.drawImage(image, x, pos.y, 200, 100, 0, 0, 400, 200);
}
<canvas id="mainCanvasMap"></canvas>
<canvas id="zoomCanvas"></canvas>
<img id="source" src="https://image.jimcdn.com/app/cms/image/transf/dimension=624x10000:format=jpg/path/s7d1eecaa5cee1012/image/i4484f962de0bf3c2/version/1543751018/image.jpg" style="display:none">

Generate multiple images from loop

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();
}

Custom image angles in collage

I am working on a collage in HTML5 canvas. However, I am finding difficulty in arranging the images in different angles. I want to arrange first pic at angle of PI/4 and the other one at angle -PI/70. Here is the jsFiddle with the problem.
var pic1 = new Image();
pic1.src = "http://www.fantom-xp.com/wallpapers/23/Windows_7_-_Swan.jpg";
context.translate(170,170);
context.rotate(Math.PI/8);
pic1.onload = function(){
context.drawImage(pic1, 20, 20, 200, 200);
}
var pic2 = new Image();
pic2.src = "http://www.redorbit.com/media/uploads/2004/10/38_ec8164eb3e4bddf76ef1b8eb564b9514.jpg";
context.translate(100,10);
context.rotate(-Math.PI/70);
pic2.onload = function(){
context.drawImage(pic2, 0, 0, 200, 200);
}
What am I missing?
Assuming you want to rotate your images around their center points you need to use this drawImage:
context.drawImage(image, -image.width/2, -image.height/2).
That's because the translate point becomes the rotation point.
Here's a generic image rotation function:
function tiltedPicture(centerX,centerY,degreeAngle,image){
ctx.save();
ctx.translate(centerX,centerY);
ctx.rotate(degreeAngle*Math.PI/180);
ctx.drawImage(image,-image.width/2,-image.height/2);
ctx.restore();
}
There are some issues in your code.
First of all, your first image couldn't be loaded. You will see it when you add:
pic1.onerror = function() {
console.log('Error loading');
}
Next you should use save and restore methods. Read here.
The problem is when you call twice context.translate(170,170); you will get th final translation at x: 340, y: 340. If you will combine more complex transformaions you could get result which is hard to predict. Fortunatelly there are methods save and restore. Save - saves current transformation state, and Restore - restores last saved state.
Usage in your case (for the first pic):
pic1.onload = function(){
context.save();
context.translate(170,170);
context.rotate(Math.PI/2);
context.drawImage(pic1, 20, 20, 200, 200);
context.restore();
}
pic1.onerror = function() {
console.log('error loading');
}
See demo.

Save image from Stage with offset KineticJS HTML5

I want to save part of a KineticJS stage. This code is working perfect:
stage.toDataURL({
width: 350,
height: 350,
mimeType: "image/jpeg",
callback: function(dataUrl) {
/*
* here you can do anything you like with the data url.
* In this tutorial we'll just open the url with the browser
* so that you can see the result as an image
*/
window.open(dataUrl);
}
});
}, false);
But what i want is to add an offset to that, so image would start and coordinates (75,75) of the stage area. Any idea?
Well, since there is no crop() method you would have to revert to moving all the objects on your stage 75 in both directions, luckily, this is not very difficult.
Something like:
var layersList = stage.getChildren();
for (var layerNum in layersList){ //loop through all layers
var childList = layerList.getChildren(); //get all children of the layer
for(var childNum in childList){
childList[childNum].move(-75,-75);
}
}
stage.draw();
stage.toDataURL({.....});
You can undo this by using the same code and doing .move(75,75); to place each item back in their original position
or if you want an offset defined through a function just do this:
function moveStage(offsetX, offsetY){
var layersList = stage.getChildren();
for (var layerNum in layersList){ //loop through all layers
var childList = layerList.getChildren(); //get all children of the layer
for(var childNum in childList){
childList[childNum].move(-offsetX,-offsetY);
}
}
stage.draw();
stage.toDataURL({.....});
}

Transform (Move/Scale/Rotate) shapes with KineticJS

I'm trying to build a transform manager for KineticJS that would build a bounding box and allow users to scale, move, and rotate an image on their canvas. I'm getting tripped up with the logic for the anchor points.
http://jsfiddle.net/mharrisn/whK2M/
I just want to allow a user to scale their image proportionally from any corner, and also rotate as the hold-drag an anchor point.
Can anyone help point me in the right direction?
Thank you!
Here is a proof of concept of a rotational control I've made:
http://codepen.io/ArtemGr/pen/ociAD
While the control is dragged around, the dragBoundFunc is used to rotate the content alongside it:
controlGroup.setDragBoundFunc (function (pos) {
var groupPos = group.getPosition()
var rotation = degrees (angle (groupPos.x, groupPos.y, pos.x, pos.y))
status.setText ('x: ' + pos.x + '; y: ' + pos.y + '; rotation: ' + rotation); layer.draw()
group.setRotationDeg (rotation); layer.draw()
return pos
})
I am doing the same thing, and I've posted a question which is allmoast the same, but I found a link where you have the resize and move tool ready developed. So I have used the same. It does not contain the rotate tool however, but this can be a good start for you too, it is very simple and logical. Here is the link: http://www.html5canvastutorials.com/labs/html5-canvas-drag-and-drop-resize-and-invert-images/
I will come back with the rotation tool as well if I manage to get it working perfectly.
I hope I am not late yet for posting this code snippet that I made. I had the same problem with you guys dealing with this kind of task. Its been 3 days since I tried so many workarounds to mimic the fabricjs framework capability when dealing with images and objects. I could use Fabricjs though but it seems that Kineticjs is more faster/consistent to deal with html5.
Luckily, we already have existing plugin/tool that we could easily implement together with kineticjs and this is jQuery Transform tool. SUPER THANKS TO THE AUTHOR OF THIS! Just search this on google and download it.
I hope the code below that I created would help lots of developers out there who is pulling their hair off to solve this kind of assignment.
$(function() {
//Declare components STAGE, LAYER and TEXT
var _stage = null;
var _layer = null;
var simpleText = null;
_stage = new Kinetic.Stage({
container: 'canvas',
width: 640,
height: 480
});
_layer = new Kinetic.Layer();
simpleText = new Kinetic.Text({
x: 60,
y: 55,
text: 'Simple Text',
fontSize: 30,
fontFamily: 'Calbiri',
draggable: false,
name:'objectInCanvas',
id:'objectCanvas',
fill: 'green'
});
//ADD LAYER AND TEXT ON STAGE
_layer.add(simpleText);
_stage.add(_layer);
_stage.draw();
//Add onclick event listener to the Stage to remove and add transform tool to the object
_stage.on('click', function(evt) {
//Remove all objects' transform tool inside the stage
removeTransformToolSelection();
// get the shape that was clicked on
ishape = evt.targetNode;
//Add and show again the transform tool to the selected object and update the stage layer
$(ishape).transformTool('show');
ishape.getParent().moveToTop();
_layer.draw();
});
function removeTransformToolSelection(){
//Search all objects inside the stage or layer who has the name of "objectInCanvas" using jQuery iterator and hide the transform tool.
$.each(_stage.find('.objectInCanvas'), function( i, child ) {
$(child).transformTool('hide');
});
}
//Event listener/Callback when selecting image using file upload element
function handleFileSelect(evt) {
//Remove all objects' transform tool inside the stage
removeTransformToolSelection();
//Create image object for selected file
var imageObj = new Image();
imageObj.onload = function() {
var myImage = new Kinetic.Image({
x: 0,
y: 0,
image: imageObj,
name:'objectInCanvas',
draggable:false,
id:'id_'
});
//Add to layer and add transform tool
_layer.add(myImage);
$(myImage).transformTool();
_layer.draw();
}
//Adding source to Image object.
var f = document.getElementById('files').files[0];
var name = f.name;
var url = window.URL;
var src = url.createObjectURL(f);
imageObj.src = src;
}
//Attach event listener to FILE element
document.getElementById('files').addEventListener('change', handleFileSelect, false);
});

Categories