KonvaJS - Toggle anchors when mouseon/mouseoff of image - javascript

In my KonvaJS project, I'm adding images aka "stickers" onto an uploaded image, and with KonvaJS, I'm adding "Anchors" to rotate and resize the images.
When the mouse is off the main image, (or maybe when you click on the sticker, it toggles edit mode?), I'd like to remove the anchors and lines.
How is this possible?
function centreRectShape(shape) {
shape.x((stage.getWidth() - shape.getWidth()) / 2);
shape.y((stage.getHeight() - shape.getHeight()) / 2);
}
var stage = new Konva.Stage({
container: 'canvas-container',
width: 650,
height: 300
});
var layer = new Konva.Layer();
stage.add(layer);
var bgRect = new Konva.Rect({
width: stage.getWidth(),
height: stage.getHeight(),
fill: 'gold',
opacity: 0.1
});
layer.add(bgRect);
var uploadedImage = new Konva.Image({
draggable: false
});
layer.add(uploadedImage);
imgObj = new Image();
imgObj.onload = function() {
uploadedImage.image(imgObj);
var padding = 20;
var w = imgObj.width;
var h = imgObj.height;
var targetW = stage.getWidth() - (2 * padding);
var targetH = stage.getHeight() - (2 * padding);
var widthFit = targetW / w;
var heightFit = targetH / h;
var scale = (widthFit > heightFit) ? heightFit : widthFit;
w = parseInt(w * scale, 10);
h = parseInt(h * scale, 10);
uploadedImage.size({
width: w,
height: h
});
centreRectShape(uploadedImage);
layer.draw();
}
imgObj.src = 'https://images.pexels.com/photos/787961/pexels-photo-787961.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260';
$('.sticker').on('click', function() {
addSticker($(this).attr('src'));
});
function addSticker(imgUrl) {
stickerObj = new Konva.Image({
x: 240,
y: 20,
width: 93,
height: 104,
draggable: true
});
layer.add(stickerObj);
var stickerImage = new Image();
stickerImage.onload = function() {
stickerObj.image(stickerImage);
layer.draw();
};
stickerImage.src = imgUrl;
var imgRotator = new Konva.Transformer({
node: stickerObj,
keepRatio: true,
enabledAnchors: ['top-left', 'top-right', 'bottom-left', 'bottom-right']
});
layer.add(imgRotator);
}
html,
* {
margin: 0;
padding: 0;
}
body {
background: #eee;
}
#image-editor {
background: #fff;
border-radius: 3px;
border: 1px solid #d8d8d8;
width: 650px;
margin: 0 auto;
margin-top: 20px;
box-shadow: 0 3px 5px rgba(0, 0, 0, .2);
}
.stickers {
padding: 10px 5px;
background: #eee;
}
.stickers>img {
margin-right: 10px;
}
<script src="https://unpkg.com/konva#2.4.1/konva.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="image-editor">
<div id="canvas-container"></div>
<div class="stickers">
<div>
click sticer below and then rotate
</div>
<img class="sticker" src="https://craftblock.me/koa/fb-upload-clone/stickers/sticker%20(1).png" alt="Sticker" width="62px">
</div>
</div>

The most simple way is to add to the addSticker() function event handlers for both mouseover and mouseout. You can attach them, e. g., to the stage object.
stage.on('mouseover', function() {
imgRotator.attachTo(stickerObj);
layer.draw();
});
stage.on('mouseout', function() {
imgRotator.detach();
layer.draw();
});
They do two things:
attach / detach the Transformer object to / from the selected node.
refresh the layer.
From here on you can improve it. You could make the addSticker() function to return an object with the attachTo and detach methods to be able to call them from somewhere else. Something like:
function addSticker(imgUrl) {
...
return {
showTransformer: function() {
imgRotator.attachTo(stickerObj);
layer.draw();
},
hideTransformer: function() {
imgRotator.detach();
layer.draw();
}
};
}
Also, if you mean to have more than one sticker, you should implement some logic to track to which sticker should the events apply.
Edit:
You have made two comments to this answer:
"I think it's best if the mouseout is for that specific sticker."
The anchors to resize and rotate the image are actually outside the image. If you hide them after the mouseout event... well, your users will never reach them ;)
You have two options to avoid it:
Create a custom hit region which includes the anchors.
Replace the event with a click to toggle the transformer object.
I use the second approach in the updated snippet.
"What if there's multiple added stickers?"
You should use a closure to keep the references to the different objects in the scope of that functions.
Combining the click to toggle and the closure we have:
stickerObj.on('click', (function(transformer, sticker) {
return function() {
transformer.getNode() ? transformer.detach() : transformer.attachTo(sticker);
layer.draw();
};
})(imgRotator, stickerObj));
Extra tips:
Even after detaching the transformer, the user will be still able to move the image around. That's because draggable is a property of the image (inherited from node), not of the transformer.
So maybe you also want to toggle node.draggable(boolean);.
If for some reasons you don't want to detach/attach the transformer, you can achieve a similar effect toggling borderEnabled(), resizeEnabled() and rotateEnabled().
function centreRectShape(shape) {
shape.x((stage.getWidth() - shape.getWidth()) / 2);
shape.y((stage.getHeight() - shape.getHeight()) / 2);
}
var stage = new Konva.Stage({
container: 'canvas-container',
width: 650,
height: 300
});
var layer = new Konva.Layer();
stage.add(layer);
var bgRect = new Konva.Rect({
width: stage.getWidth(),
height: stage.getHeight(),
fill: 'gold',
opacity: 0.1
});
layer.add(bgRect);
var uploadedImage = new Konva.Image({
draggable: false
});
layer.add(uploadedImage);
imgObj = new Image();
imgObj.onload = function() {
uploadedImage.image(imgObj);
var padding = 20;
var w = imgObj.width;
var h = imgObj.height;
var targetW = stage.getWidth() - (2 * padding);
var targetH = stage.getHeight() - (2 * padding);
var widthFit = targetW / w;
var heightFit = targetH / h;
var scale = (widthFit > heightFit) ? heightFit : widthFit;
w = parseInt(w * scale, 10);
h = parseInt(h * scale, 10);
uploadedImage.size({
width: w,
height: h
});
centreRectShape(uploadedImage);
layer.draw();
}
imgObj.src = 'https://images.pexels.com/photos/787961/pexels-photo-787961.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260';
$('.sticker').on('click', function() {
addSticker($(this).attr('src'));
});
function addSticker(imgUrl) {
stickerObj = new Konva.Image({
x: 240,
y: 20,
width: 93,
height: 104,
draggable: true
});
layer.add(stickerObj);
var stickerImage = new Image();
stickerImage.onload = function() {
stickerObj.image(stickerImage);
layer.draw();
};
stickerImage.src = imgUrl;
var imgRotator = new Konva.Transformer({
node: stickerObj,
keepRatio: true,
enabledAnchors: ['top-left', 'top-right', 'bottom-left', 'bottom-right']
});
layer.add(imgRotator);
stickerObj.on('click', (function(transformer, sticker) {
return function() {
transformer.getNode() ? transformer.detach() : transformer.attachTo(sticker);
layer.draw();
};
})(imgRotator, stickerObj));
}
html,
* {
margin: 0;
padding: 0;
}
body {
background: #eee;
}
#image-editor {
background: #fff;
border-radius: 3px;
border: 1px solid #d8d8d8;
width: 650px;
margin: 0 auto;
margin-top: 20px;
box-shadow: 0 3px 5px rgba(0, 0, 0, .2);
}
.stickers { pitón reticulada
padding: 10px 5px;
background: #eee;
}
.stickers>img {
margin-right: 10px;
}
<script src="https://unpkg.com/konva#2.4.1/konva.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="image-editor">
<div id="canvas-container"></div>
<div class="stickers">
<div>
click sticer below and then rotate
</div>
<img class="sticker" src="https://craftblock.me/koa/fb-upload-clone/stickers/sticker%20(1).png" alt="Sticker" width="62px">
</div>
</div>

Related

How to repeat-x background of a image in fabric when rezise it

I want to repeat background when i resize it.
Here is my code, i've tried.
var canvas = new fabric.Canvas('c', {
clipTo: function(ctx) {
ctx.rect(1000, 1000, 400, 400);
}
});
fabric.Image.fromURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR/mAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAASdEVYdFNvZnR3YXJlAEdyZWVuc2hvdF5VCAUAAADLSURBVFhH7ZnBCoMwEET9/68URBHSNj0UolFoI+aQickKlT05jz0MGQIPkb2kadu3ta42ff/MTtLRazct55bajOMjO0lHr920vnWMMTGV0GuphVALoRaiqNV1dq4TLsdUIrTe+z0fw+ndmEo0w/D61AmXYyqh1179WjGVuNLyl0eohVALuZ8Wtzwgt9zyiNxSC6EWQi1EUYtbHpBbbnlEbqmFUAuhFqKoxS0PyC23PCK31EKohVAL0dXK3vLSOX0TnKZ1z8fw/3uiW37L27QIZwrV4gAAAABJRU5ErkJggg==', function(img) {
var patternSourceCanvas = new fabric.StaticCanvas();
patternSourceCanvas.add(img);
var pattern = new fabric.Pattern({
source: function() {
patternSourceCanvas.setDimensions({
width: img.getWidth(),
height: img.getHeight()
});
return patternSourceCanvas.getElement();
},
repeat: 'repeat'
});
var rectangle = new fabric.Rect({
fill: pattern,
left: 1150,
top: 1150,
width: img.getWidth(),
height: img.getHeight()
});
canvas.add(rectangle);
canvas.renderAll();
});
canvas.on('object:scaling', function(e) {
if (e.target != null) {
console.log(e.target);
}
});
body {
overflow: hidden;
}
.container {
top: -1000px;
left: -1000px;
position: relative;
z-index: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.17/fabric.min.js"></script>
<div class="container">
<canvas id="c" width="2400" height="2400"></canvas>
</div>
How can I make, background repeat?
Here is jsFiddle
#Ngọc Hòa we'll have to use object:scaling event to scale the object back to 1x and change size of the object to make repeat the pattern instead of scaling it. See it here
var canvas = new fabric.Canvas('c');
fabric.Object.prototype.transparentCorners = false;
var padding = 0;
fabric.Image.fromURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR/mAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAASdEVYdFNvZnR3YXJlAEdyZWVuc2hvdF5VCAUAAADLSURBVFhH7ZnBCoMwEET9/68URBHSNj0UolFoI+aQickKlT05jz0MGQIPkb2kadu3ta42ff/MTtLRazct55bajOMjO0lHr920vnWMMTGV0GuphVALoRaiqNV1dq4TLsdUIrTe+z0fw+ndmEo0w/D61AmXYyqh1179WjGVuNLyl0eohVALuZ8Wtzwgt9zyiNxSC6EWQi1EUYtbHpBbbnlEbqmFUAuhFqKoxS0PyC23PCK31EKohVAL0dXK3vLSOX0TnKZ1z8fw/3uiW37L27QIZwrV4gAAAABJRU5ErkJggg==', function(img) {
img.scaleToWidth(50);
var patternSourceCanvas = new fabric.StaticCanvas();
patternSourceCanvas.add(img);
patternSourceCanvas.renderAll();
var pattern = new fabric.Pattern({
source: function() {
patternSourceCanvas.setDimensions({
width: img.getScaledWidth() + padding,
height: img.getScaledHeight() + padding
});
patternSourceCanvas.renderAll();
return patternSourceCanvas.getElement();
},
repeat: 'repeat'
});
var rect = new fabric.Rect({
width: 250,
height: 250,
fill: pattern,
objectCaching: false
});
canvas.add(rect);
rect.center().setCoords();
});
canvas.on('object:scaling', function(e) {
if (e.target != null) {
console.log(e.target);
var obj = e.target;
var height = obj.height * obj.scaleY;
var width = obj.width * obj.scaleX;
obj.height = height;
obj.width = width;
obj.scaleX = 1;
obj.scaleY = 1;
}
});
https://jsfiddle.net/dotriz/ajsdmg4s/

Creating polygon shapes via mouse drag does not center the shape to its selection border box

Version
1.7.3
Test Case
https://jsfiddle.net/human_a/twdgya93/
In this fiddle, I have also tried creating the shape using the following code to avoid creating empty polygons, but the result is the same:
const polygon = new fabric.Polygon(calcPolygonPoints(8, Math.abs( origX - pointer.x ) / 2 ), {
objectCaching: false,
left: origX,
top: origY,
originX: 'center',
originY: 'center',
fill: 'rgba(255,255,255, 1)',
perPixelTargetFind: false,
strokeWidth: 1,
strokeDashArray: [0,0],
objType: 'shape',
stroke: 'rgba(17,17,17,1)',
hasControls: false,
hasBorders: false
})
Steps to reproduce
Click on the green button to go to drawing mode, drag the mouse inside the canvas to start creating the shape, let go of the mouse, then try selecting the newly created shape. The bounding box size matches the size of the new polygon, but it's not positioned correctly.
Expected Behavior
If instead of polygons I try to create any other type of shapes (rectangles, circles or triangles) It works perfectly fine.
Actual Behavior
Since polygons use a different method by calculating the points it calculates the width and the height, and since in this method of creating shapes the width/height are being calculated after the shape is created (with mouse:move event) the bounding rectangle will not be positioned correctly.
Also even if I try to change the size of the polygon (I don't want to scale the shapes, it's a bad idea) again the bounding rectangle is not positioned correctly, you can try it in the demo above using the number input field right next to the button.
PS
I did not write the calcPolygonPoints function, I found it somewhere on the web a while ago, unfortunately, I could not find its link again to credit the creator of this amazing function.
When you have a fiddle is very nice and fast to transform it in a working snippet, since then getting an answer is very easy.
Said so, the point is that the polygon in fabric.js do not support points updating. You were already calling the _calcDimensions() but that is not enough.
To correctly center the polygon in the bounding box you have to also populate its pathOffset property with updated values.
I added this in your snippet on the mouseUp event.
var canvas = new fabric.Canvas();
var el = document.getElementById('my-canvas');
var drawPoly = document.getElementById('draw-poly');
var changeSize = document.getElementById('change-size');
var origX, origY;
var calcPolygonPoints = (sideCount,radius) => {
var sweep=Math.PI*2/sideCount;
var cx=radius;
var cy=radius;
var points=[]
for(var i=0;i<sideCount;i++){
var x=cx+radius*Math.cos( i*sweep )
var y=cy+radius*Math.sin( i*sweep )
points.push( { x:x, y:y } )
}
return(points)
}
canvas.initialize(el, {
backgroundColor: '#fff',
width: 600,
height: 600
});
canvas.renderAll();
drawPoly.addEventListener('click', (e)=>{
canvas.defaultCursor = "crosshair";
canvas.selection = false;
canvas.discardActiveObject();
canvas.discardActiveGroup();
canvas.forEachObject(object=>{ object.selectable = false; });
canvas.renderAll();
canvas.on('mouse:down', opt => {
if (canvas.selection) return;
var pointer = canvas.getPointer(opt.e)
origX = pointer.x;
origY = pointer.y;
// I have also tried initial calculations here
// by using calcPolygonPoints(8, Math.abs( origX - pointer.x ) / 2 ) instead of []
// The result is the same
const polygon = new fabric.Polygon(calcPolygonPoints(8, Math.abs( origX - pointer.x ) / 2 ), {
objectCaching: false,
left: origX,
top: origY,
originX: 'center',
originY: 'center',
fill: 'rgba(255,255,255, 1)',
perPixelTargetFind: false,
strokeWidth: 1,
strokeDashArray: [0,0],
objType: 'shape',
stroke: 'rgba(17,17,17,1)',
hasControls: false,
hasBorders: false
})
// polygon._calcDimensions()
canvas.add(polygon).setActiveObject(polygon)
}).on('mouse:move', opt => {
if (canvas.selection || !canvas.getActiveObject()) return;
const newShape = canvas.getActiveObject()
var pointer = canvas.getPointer(opt.e)
if (newShape) {
newShape.set({
points: calcPolygonPoints(8, Math.abs( origX - pointer.x ) / 2 )
})
newShape._calcDimensions()
}
changeSize.value = Math.abs( origX - pointer.x ) / 2;
canvas.renderAll()
}).on('mouse:up', opt => {
// In my app I am using redux stores to turn off the drawing
// Here I used the following if statement to turn off the drawing
if (canvas.selection) return;
const newShape = canvas.getActiveObject()
if (newShape) {
newShape.set({
hasControls: true,
hasBorders: true
})
newShape.pathOffset = {
x: newShape.minX + newShape.width / 2,
y: newShape.minY + newShape.height / 2
};
var pointer = canvas.getPointer(opt.e);
var center = { x: (pointer.x + origX)/2, y: (pointer.y + origY)/2}
newShape.setPositionByOrigin(center, 'center', 'center')
newShape.setCoords()
canvas.renderAll()
}
canvas.renderAll()
canvas.selection = true;
canvas.off('mouse:down').off('mouse:move')
canvas.defaultCursor = "default";
canvas.discardActiveObject()
canvas.forEachObject(object=>{
if (object.evented) object.selectable = true;
})
})
})
changeSize.addEventListener('input', (e)=>{
if (!canvas.getActiveObject()) return;
canvas.getActiveObject().set({
points: calcPolygonPoints(8, parseInt(e.target.value, 10) )
})
canvas.getActiveObject()._calcDimensions()
canvas.renderAll()
})
button {
border: 0 none;
background: #2ecc70;
border-radius: 5px;
cursor: pointer;
color: #fff;
box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08);
text-transform: uppercase;
padding: 11px 22px;
font-weight: 600;
font-size: 13px;
letter-spacing: 1px;
margin: 10px auto;
outline: 0 none;
}
input {
border: 1px solid #ddd;
box-shadow: none;
padding: 11px;
font-size: 13px;
border-radius: 5px;
margin-left: 10px;
max-width: 50px;
outline: 0 none !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.3/fabric.min.js"></script>
<div id="wrapper">
<canvas id="my-canvas"></canvas>
<button id="draw-poly">Draw Polygon</button>
<input type="number" id="change-size" value="0" />
</div>

JavaScript - Dynamically create SVG and modify for cursor

Say I have a HTML5 canvas (In this case using fabric.js), and I want to change the cursor over the canvas to represent whatever brush size and colour has been selected. I'm thinking there should be a way to do this by changing an SVG's properties (size & colour) dynamically with JS so we don't have to use multiple images. Any ideas on if this is possible?
var canvas = new fabric.Canvas(c, {
isDrawingMode: true,
freeDrawingCursor: 'url("img/cursor.svg"), auto'
});
I think freeDrawingCursor is just looking for normal css property names. Here is an example of how to have a fabric object represent the cursor size and color:
var canvas = new fabric.Canvas('c', {
isDrawingMode: true,
freeDrawingCursor: 'none'
});
canvas.freeDrawingBrush.width = 10;
canvas.freeDrawingBrush.color = '#9f9';
var mousecursor = new fabric.Circle({
left: 0,
top: 0,
radius: canvas.freeDrawingBrush.width / 2,
fill: canvas.freeDrawingBrush.color,
originX: 'right',
originY: 'bottom',
})
canvas.add(mousecursor);
canvas.on('mouse:move', function(obj) {
mousecursor.top = obj.e.y - mousecursor.radius;
mousecursor.left = obj.e.x - mousecursor.radius;
canvas.renderAll()
})
canvas.on('mouse:out', function(obj) {
// put circle off screen
mousecursor.top = -100;
mousecursor.left = -100;
canvas.renderAll()
})
canvas {
border: 1px solid #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.3/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>
Existing answers didn't work for me in 2020. Try the following:
this.canvas.isDrawingMode = true;
this.canvas.freeDrawingCursor = 'none';
const mousecursor = new fabric.Circle({
left: 0,
top: 0,
radius: this.canvas.freeDrawingBrush.width / 2,
fill: this.canvas.freeDrawingBrush.color,
originX: 'right',
originY: 'bottom',
});
this.canvas.add(mousecursor);
// Cursor in canvas
this.canvas.on('mouse:move', event => {
mousecursor.top = event.e.layerY + mousecursor.radius;
mousecursor.left = event.e.layerX + mousecursor.radius;
this.canvas.renderAll();
});
// Cursor out of canvas
this.canvas.on('mouse:out', event => {
mousecursor.top = -100;
mousecursor.left = -100;
this.canvas.renderAll();
});
Worked fine with Angular 7.
I was looking for the same and found my way to this question. Unfortunately the solution by STHayden is not working for me. So I've modified it a bit and came up with the code below. It uses two canvas layers, the bottom for drawing, the top for the "cursor". Works pretty well for me now, maybe someone will find it helpful :)
//drawing layer
var canvas = new fabric.Canvas("draw", {
isDrawingMode: true,
freeDrawingCursor: 'none'
});
//mouse cursor layer
var cursor = new fabric.StaticCanvas("cursor");
canvas.freeDrawingBrush.width = 20;
canvas.freeDrawingBrush.color = '#ff0000';
var cursorOpacity = .5;
//create cursor and place it off screen
var mousecursor = new fabric.Circle({
left: -100,
top: -100,
radius: canvas.freeDrawingBrush.width / 2,
fill: "rgba(255,0,0," + cursorOpacity + ")",
stroke: "black",
originX: 'center',
originY: 'center'
});
cursor.add(mousecursor);
//redraw cursor on new mouse position when moved
canvas.on('mouse:move', function (evt) {
var mouse = this.getPointer(evt.e);
mousecursor
.set({
top: mouse.y,
left: mouse.x
})
.setCoords()
.canvas.renderAll();
});
//put cursor off screen again when mouse is leaving
canvas.on('mouse:out', function () {
mousecursor
.set({
top: mousecursor.originalState.top,
left: mousecursor.originalState.left
})
.setCoords()
.canvas.renderAll();
});
//while brush size is changed show cursor in center of canvas
document.getElementById("size").oninput = function () {
var size = parseInt(this.value, 10);
mousecursor
.center()
.set({
radius: size/2
})
.setCoords()
.canvas.renderAll();
};
//after brush size has been changed move offscreen, update brush size
document.getElementById("size").onchange = function () {
var size = parseInt(this.value, 10);
canvas.freeDrawingBrush.width = size;
mousecursor
.set({
left: mousecursor.originalState.left,
top: mousecursor.originalState.top,
radius: size/2
})
.setCoords()
.canvas.renderAll();
};
//change mousecursor opacity
document.getElementById("opacity").onchange = function () {
cursorOpacity = this.value;
var fill = mousecursor.fill.split(",");
fill[fill.length-1] = cursorOpacity + ")";
mousecursor.fill = fill.join(",");
};
//change drawing color
document.getElementById("color").onchange = function () {
canvas.freeDrawingBrush.color = this.value;
var bigint = parseInt(this.value.replace("#", ""), 16);
var r = (bigint >> 16) & 255;
var g = (bigint >> 8) & 255;
var b = bigint & 255;
mousecursor.fill = "rgba(" + [r,g,b,cursorOpacity].join(",") + ")";
};
#cont {
position: relative;
width: 500px;
height: 500px;
}
canvas {
border: 1px solid;
}
#cont canvas, .canvas-container {
position: absolute!important;
left: 0!important;
top: 0!important;
width: 100%!important;
height: 100%!important;
}
#cursor {
pointer-events: none!important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.4/fabric.min.js"></script>
Color: <input id="color" type="color" value="#ff0000"><br/>
Brush size: <input id="size" type="range" min="1" max="100" step="1" value="20"><br/>
Brush opacity: <input id="opacity" type="number" min="0" max="1" step="0.1" value="0.5"><br/>
<div id="cont">
<canvas id="draw" width="500" height="500"></canvas>
<canvas id="cursor" width="500" height="500"></canvas>
</div>

Javascript: No response after preload of images

Okay, I now tried to load two Kinetic images, but it still doesn't work. I also tried to put it on another layer and on another stage. Nothing helped. But with one image everything is fine.
var stage = new Kinetic.Stage({
container: 'container',
width: 1600,
height: 1000
});
var layer = new Kinetic.Layer();
var imageObj = new Image();
imageObj.onload = function() {
var yoda = new Kinetic.Image({
x: 200,
y: 50,
image: imageObj,
width: 106,
height: 118
});
var imageObj2 = new Image();
imageObj2.onload = function() {
var vader = new Kinetic.Image({
x: 400,
y: 200,
image: imageObj2,
width: 206,
height: 218
});
// add the shape to the layer
layer.add(yoda);
layer.add(vader);
// add the layer to the stage
stage.add(layer);
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/yoda.jpg';
imageObj2.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
OLD:
This is a sample code from http://www.html5canvastutorials.com/. I want to load two (or more) images and animate them both by clicking one button. Everything works fine with one picture, but this code confuses me. After the loadImages function is called there is no more reaction, even an alert isn't displayed. Where and how can I place my anim function?(I will implement the other animation later) Thanks for your ideas!
CSS
body {
margin: 0px;
padding: 0px;
}
#buttons {
position: absolute;
top: 50px;
left: 100px;
}
#buttons > input {
padding: 10px;
display: block;
margin-top: 5px;
}
HTML
<div id="container"></div>
<div id="buttons">
<input type="button" id="start" value="Start">
</div>
<canvas id="myCanvas" width="578" height="200"></canvas>
JS
document.getElementById('start').addEventListener('click', function() {
anim.start(); //button should start animation
}, false);
function loadImages(sources, callback) {
var images = {};
var loadedImages = 0;
var numImages = 0;
// get num of sources
for(var src in sources) {
numImages++;
}
for(var src in sources) {
images[src] = new Image();
images[src].onload = function() {
if(++loadedImages >= numImages) {
callback(images);
}
};
images[src].src = sources[src];
}
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var sources = {
darthVader: 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg',
yoda: 'http://www.html5canvastutorials.com/demos/assets/yoda.jpg'
};
loadImages(sources, function(images) {
context.drawImage(images.darthVader, 100, 30, 200, 137);
context.drawImage(images.yoda, 150, 55, 93, 104);
});
var angularSpeed = 360 / 4; //from this line on it's like the js-code doesn't exist
var anim = new Kinetic.Animation(function(frame) { exist
var angleDiff = frame.timeDiff * angularSpeed / 1000;
images.yoda.rotate(angleDiff); //sources. instead images.?
}, layer);
You are mixing html5 canvas code with KineticJS library code.
You must create Kinetic.Image objects from each of your image objects.
Only then you can use Kinetic.Animation to animate them into rotation.

HTML5 Canvas: how to have an image and a shape on the canvas and shape is Drag n Droppable?

I'm having trouble creating an HTML5 canvas in which a an image is present, a shape is present, and the shape is draggable on the same stage. My gut tells me that I need to create multiple layers or multiple stages/canvases. Then have one be regular and the other be Kinetic. I've found some code for draggable shapes, code for displaying images and shapes, and I think my problem only lies in the implementation of the syntax. Here's the code:
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
canvas {
border: 1px solid #9C9898;
}
</style>
<script src="http://www.html5canvastutorials.com/libraries/kinetic-v3.10.0.js"></script>
<script>
window.onload = function() {
var stage = new Kinetic.Stage({
container: "container",
width: 578,
height: 200
var layer = new Kinetic.Layer();
var rectX = stage.getWidth() / 2 - 50;
var rectY = stage.getHeight() / 2 - 25;
var box = new Kinetic.Rect({
x: rectX,
y: rectY,
width: 100,
height: 50,
fill: "#00D2FF",
stroke: "black",
strokeWidth: 4,
draggable: true
});
var layer1 = new Kinetic.Layer();
var imageObj = new Image();
imageObj.onload = function() {
var image = new Kinetic.Image({
x: stage.getWidth() / 2 - 53,
y: stage.getHeight() / 2 - 59,
image: imageObj,
width: 106,
height: 118
});
layer1.add(image);
stage.add(layer1);
// add cursor styling
box.on("mouseover", function() {
document.body.style.cursor = "pointer";
});
box.on("mouseout", function() {
document.body.style.cursor = "default";
});
layer.add(box);
stage.add(layer);
imageObj.src = "http://www.html5canvastutorials.com/demos/assets/yoda.jpg";
};
</script>
</head>
<body onmousedown="return false;">
<div id="container"></div>
</body>
</html>
Try this website: w3shools.com/html5/html5_draganddrop.asp

Categories

Resources