I am trying to place an image inside a circle using:
var gArrow2 = new Image();
gArrow2.src = '../../Content/images/green_s.png';
var circle2 = new Kinetic.Circle({
drawFunc: function(canvas) {
var context = canvas.getContext();
context.drawImage(gArrow2, 256, 256, 11, 23);
context.beginPath();
context.arc(256, 256, this.getRadius(), 0, 2 * Math.PI, false);
context.lineWidth = this.getStrokeWidth();
context.strokeStyle = this.getStroke();
context.stroke();
},
x: 256,
y: 256,
radius: 70,
stroke: '#00ffff',
strokeWidth: 4,
opacity: 0.5
});
layer2.add(circle2);
It does not work! I would appreciate your suggestions, thanks in advance.
You have to give gArrow2 time to load. You do this through gArrow2.onload.
Always put gArrow2.src after it's onload.
Then put any code that uses gArrow2 inside the onload function.
[Edit to add layer2.draw()]
I plugged your code in and got it working.
Looks like all that was needed was layer2.draw();
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/Qgnkx/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Prototype</title>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://www.html5canvastutorials.com/libraries/kinetic-v4.3.3-beta.js"></script>
<style>
#container{
border:solid 1px #ccc;
margin-top: 10px;
}
</style>
<script>
$(function(){
var stage = new Kinetic.Stage({
container: 'container',
width: 600,
height: 600
});
var layer2 = new Kinetic.Layer();
stage.add(layer2);
var gArrow2 = new Image();
gArrow2.onload=function(){
var circle2 = new Kinetic.Circle({
drawFunc: function(canvas) {
var context = canvas.getContext();
context.drawImage(gArrow2, 256, 256, 11, 23);
context.beginPath();
context.arc(256, 256, this.getRadius(), 0, 2 * Math.PI, false);
context.lineWidth = this.getStrokeWidth();
context.strokeStyle = this.getStroke();
context.stroke();
},
x: 256,
y: 256,
radius: 70,
stroke: '#00ffff',
strokeWidth: 4,
opacity: 0.5
});
layer2.add(circle2);
layer2.draw();
}
gArrow2.src = 'http://dl.dropbox.com/u/139992952/stackoverflow/house1.jpg';
}); // end $(function(){});
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
Related
Is there a way of adding e.g. circles or boxes to the html5 canvas by using konva.js? i tried it but somehow it doesn't work! What i want it e.g. one click is adding a circle with drag and drop, a doubleclick removes the circle.
This is how it works, maybe someone can use it!
$( document ).ready(function() {
var width = window.innerWidth;
var height = window.innerHeight;
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height
});
var layer = new Konva.Layer();
var colors = ["red", "orange", "yellow", "green", "blue", "purple"];
var rect1 = new Konva.Rect({
x: 25,
y: 25,
width: width-50,
height: height-50,
opacity: 1,
fill: 'green',
stroke: 'black',
strokeWidth: 2
});
var circle = new Konva.Circle({
x: 230,
y: 100,
radius: 30,
fill: 'grey',
stroke: 'black',
strokeWidth: 1,
draggable: true,
id: 'Origin'
});
circle.on('mouseover', function() {
document.body.style.cursor = 'pointer';
});
circle.on('mouseout', function() {
document.body.style.cursor = 'default';
});
circle.on("dragstart", function () {
this.moveToTop();
layer.draw();
});
circle.on("dragmove", function () {
document.body.style.cursor = "pointer";
});
circle.on("dblclick dbltap", function (evt) {
evt.cancelBubble = true;
console.log("item dblclick");
this.destroy();
layer.draw();
});
circle.on("click tap", function (evt) {
evt.cancelBubble = true;
var node = evt.target;
if (node) {
// update tooltip
var mousePos = node.getStage().getPointerPosition();
console.log("item normal click " + node.getId() + " > node-x" + node.x() +" - fill " + node.getFill());
}
});
rect1.on('dblclick', function() {
var clone;
clone = circle.clone({
x:stage.getPointerPosition().x,
y:stage.getPointerPosition().y,
id: 'myCircle'
});
layer.add(clone);
layer.draw();
console.log('content click on rect1 ' + JSON.stringify(stage.getPointerPosition()));
});
circle.on("mouseover", function () {
document.body.style.cursor = "pointer";
});
circle.on("mouseout", function () {
document.body.style.cursor = "default";
});
layer.add(rect1);
layer.add(circle);
stage.add(layer);
});
<!doctype html>
<html lang="{{ app()->getLocale() }}">
<script src="https://cdn.rawgit.com/konvajs/konva/1.7.6/konva.min.js"></script>
<script
src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<meta charset="utf-8">
<title>Add/Remove</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #F0F0F0;
}
</style>
</head>
<body>
<div id="container"></div>
</body>
</html>
Why this clipTo method doesn't work on the latest fabricjs version, which you could resize the object container and the image inside it. Also you able to move the container object and image object.
var imgInstance = new fabric.Image(img, {
width: instanceWidth,
height: instanceHeight,
top: (canvas.getHeight() / 2 - instanceHeight / 2),
left: (canvas.getWidth() / 2 - instanceWidth / 2),
originX: 'left',
originY: 'top'
});
canvas.add(imgInstance);
imgInstance.clipTo = function(ctx) {
/* image clipping method doesn't work on latest fabricjs version*/
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
clippingRect.render(ctx);
ctx.restore();
};
http://jsfiddle.net/efmbrm4v/2/
Or is their another approach shape object inside is the image object.
There is some caching issue with the latest version of FabricJS. To get around that, you need to set objectCaching property to false for the rectangle object.
$(document).ready(function() {
var imageLoader = document.getElementById('imageLoader');
imageLoader.addEventListener('change', handleImage, false);
});
var canvas = new fabric.Canvas('myCanvas');
var clippingRect = new fabric.Rect({
left: 100,
top: 100,
width: 100,
height: 100,
fill: 'transparent',
opacity: 1,
objectCaching: false //<-- set this
});
canvas.add(clippingRect);
function handleImage(e) {
var reader = new FileReader();
reader.onload = function(event) {
var img = new Image();
img.onload = function() {
var instanceWidth, instanceHeight;
instanceWidth = img.width;
instanceHeight = img.height;
var imgInstance = new fabric.Image(img, {
width: instanceWidth,
height: instanceHeight,
top: (canvas.getHeight() / 2 - instanceHeight / 2),
left: (canvas.getWidth() / 2 - instanceWidth / 2),
originX: 'left',
originY: 'top'
});
canvas.add(imgInstance);
imgInstance.clipTo = function(ctx) {
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
clippingRect.render(ctx);
ctx.restore();
};
canvas.renderAll();
};
img.src = event.target.result;
};
reader.readAsDataURL(e.target.files[0]);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.13/fabric.min.js"></script>
<canvas id="myCanvas" width="400" height="300" style="border: 1px solid black"></canvas>
<br />
<label>Choose a File:</label>
<br/>
<br />
<input type="file" id="imageLoader" name="imageLoader" />
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
In my code I created method to clip images using fabric shapes. I have used stackoverflow answer for achieving this. Somehow after using this method I cannot render the canvas using default fabric canvas render method.
var img01URL = 'https://www.google.com/images/srpr/logo4w.png';
var img02URL = 'http://fabricjs.com/lib/pug.jpg';
var canvas = new fabric.Canvas('c');
document.getElementById('download').addEventListener('click', function() {
canvas.renderAll();
this.href = canvas.toDataURL({
format: 'png',
multiplier: 2
});
this.download = "test.png";
}, false);
var clipRect1 = new fabric.Rect({
originX: 'left',
originY: 'top',
angle: 90,
left: 195,
top: 0,
width: 200,
height: 200,
fill: '#DDD', /* use transparent for no fill */
strokeWidth: 1,
lockMovementX: true,
lockMovementY: true,
angle: 5,
stroke: 'red'
});
var pugImg = new Image();
pugImg.onload = function (img) {
var pug = new fabric.Image(pugImg, {
angle: 0,
width: 500,
height: 500,
left: 245,
top: 35,
scaleX: 0.3,
scaleY: 0.3,
clipName: 'pug',
clipTo: function(ctx) {
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
clipRect1.render(ctx);
ctx.restore();
}
});
canvas.add(pug);
};
pugImg.src = img02URL;
pugImg.setAttribute('crossOrigin', 'anonymous');
#c {
border:0px solid #ccc;
}
<script src="//cdn.bootcss.com/fabric.js/1.5.0/fabric.js"></script>
<canvas id="c" width="500" height="400"></canvas>
<a id="download">Download as image</a>
Your problem is the multiplier.
When using that kind of clipTo functions, you are setting the transform of canvas to plain. When rendering with canvas with multiplier, the base canvas transformation is scaled by the multiplier.
Your rect will be drawn without this transform ( because of setTransform(1,0,0,1,0,0) and will clip out the image.
Instead of setting the transform to [1,0,0,1,0,0] you should set to the invers of the current transformation of the object you are clipping.
var img01URL = 'https://www.google.com/images/srpr/logo4w.png';
var img02URL = 'http://fabricjs.com/lib/pug.jpg';
var canvas = new fabric.Canvas('c');
document.getElementById('download').addEventListener('click', function() {
var data = canvas.toDataURL({
format: 'png',
multiplier: 2
});
console.log(data);
//var img = document.getElementById('export');
//img.src = data;
}, false);
var clipRect1 = new fabric.Rect({
originX: 'left',
originY: 'top',
angle: 90,
left: 195,
top: 0,
width: 200,
height: 200,
fill: '#DDD', /* use transparent for no fill */
strokeWidth: 1,
lockMovementX: true,
lockMovementY: true,
stroke: 'red',
angle: 5
});
var pugImg = new Image();
pugImg.onload = function (img) {
var pug = new fabric.Image(pugImg, {
angle: 0,
width: 500,
height: 500,
left: 245,
top: 35,
scaleX: 0.3,
scaleY: 0.3,
clipName: 'pug',
clipTo: function(ctx) {
ctx.save();
var myMatrix = this.calcTransformMatrix();
myMatrix = fabric.util.invertTransform(myMatrix);
ctx.transform.apply(ctx, myMatrix);
clipRect1.render(ctx);
ctx.restore();
}
});
canvas.add(pug);
};
pugImg.src = img02URL;
#c {
border:0px solid #ccc;
}
<script src="//www.deltalink.it/andreab/fabric/fabric.js"></script>
<canvas id="c" width="500" height="400"></canvas>
<a id="download">Download as image</a>
<img id="export" >
Im still learning but it seems everything I do does not work in getting the images to also be rotated along with being scaled and dragged. Can someone please help me out with this. Here is the code I am working with...
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body onmousedown="return false;">
<div style="height:1024px; width: 1280px; background-image: url(http://www.designmyprofile.com/images/graphics/backgrounds/background0172.jpg)" id="container"></div>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.5.2.min.js"></script>
<script>
function update(activeAnchor) {
var group = activeAnchor.getParent();
var topLeft = group.get('.topLeft')[0];
var topRight = group.get('.topRight')[0];
var bottomRight = group.get('.bottomRight')[0];
var bottomLeft = group.get('.bottomLeft')[0];
var image = group.get('.image')[0];
var anchorX = activeAnchor.getX();
var anchorY = activeAnchor.getY();
// update anchor positions
switch (activeAnchor.getName()) {
case 'topLeft':
topRight.setY(anchorY);
bottomLeft.setX(anchorX);
break;
case 'topRight':
topLeft.setY(anchorY);
bottomRight.setX(anchorX);
break;
case 'bottomRight':
bottomLeft.setY(anchorY);
topRight.setX(anchorX);
break;
case 'bottomLeft':
bottomRight.setY(anchorY);
topLeft.setX(anchorX);
break;
}
image.setPosition(topLeft.getPosition());
var width = topRight.getX() - topLeft.getX();
var height = bottomLeft.getY() - topLeft.getY();
if(width && height) {
image.setSize(width, height);
}
}
function addAnchor(group, x, y, name) {
var stage = group.getStage();
var layer = group.getLayer();
var anchor = new Kinetic.Circle({
x: x,
y: y,
stroke: '#666',
fill: '#ddd',
strokeWidth: 2,
radius: 8,
name: name,
draggable: true,
dragOnTop: false
});
anchor.on('dragmove', function() {
update(this);
layer.draw();
});
anchor.on('mousedown touchstart', function() {
group.setDraggable(false);
this.moveToTop();
});
anchor.on('dragend', function() {
group.setDraggable(true);
layer.draw();
});
// add hover styling
anchor.on('mouseover', function() {
var layer = this.getLayer();
document.body.style.cursor = 'pointer';
this.setStrokeWidth(4);
layer.draw();
});
anchor.on('mouseout', function() {
var layer = this.getLayer();
document.body.style.cursor = 'default';
this.setStrokeWidth(2);
layer.draw();
});
group.add(anchor);
}
function loadImages(sources, callback) {
var images = {};
var loadedImages = 0;
var numImages = 0;
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];
}
}
function initStage(images) {
var stage = new Kinetic.Stage({
container: 'container',
width: 1280,
height: 1024
});
var darthVaderGroup = new Kinetic.Group({
x: 270,
y: 100,
draggable: true
});
var yodaGroup = new Kinetic.Group({
x: 100,
y: 110,
draggable: true
});
var layer = new Kinetic.Layer();
/*
* go ahead and add the groups
* to the layer and the layer to the
* stage so that the groups have knowledge
* of its layer and stage
*/
layer.add(darthVaderGroup);
layer.add(yodaGroup);
stage.add(layer);
// darth vader
var darthVaderImg = new Kinetic.Image({
x: 0,
y: 0,
image: images.darthVader,
width: 200,
height: 138,
name: 'image'
});
darthVaderGroup.add(darthVaderImg);
addAnchor(darthVaderGroup, 0, 0, 'topLeft');
addAnchor(darthVaderGroup, 200, 0, 'topRight');
addAnchor(darthVaderGroup, 200, 138, 'bottomRight');
addAnchor(darthVaderGroup, 0, 138, 'bottomLeft');
darthVaderGroup.on('dragstart', function() {
this.moveToTop();
});
// yoda
var yodaImg = new Kinetic.Image({
x: 0,
y: 0,
image: images.yoda,
width: 93,
height: 104,
name: 'image'
});
yodaGroup.add(yodaImg);
addAnchor(yodaGroup, 0, 0, 'topLeft');
addAnchor(yodaGroup, 93, 0, 'topRight');
addAnchor(yodaGroup, 93, 104, 'bottomRight');
addAnchor(yodaGroup, 0, 104, 'bottomLeft');
yodaGroup.on('dragstart', function() {
this.moveToTop();
});
stage.draw();
}
var sources = {
darthVader: 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg',
yoda: 'http://www.html5canvastutorials.com/demos/assets/yoda.jpg'
};
loadImages(sources, initStage);
</script>
</body>
</html>
I’m having a problem with the rendering of the radial gradient; in fact only last colour of the gradient list of colours is rendered. The first three circles are animated. Is there any conflict between gradient and up-dating loop to render the animation?
Thanks
This is my code:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Disc and Animated-Circle</title>
<style>
#canvasOne {
position: absolute;
border: dotted 2px black;
left: 50%;
margin-left: -450px;
top: 50%;
margin-top: -250px;
}
</style>
<script type="text/javascript">
window.addEventListener("load", eventWindowLoaded, false);
function eventWindowLoaded() {
canvasApp();
}
function canvasApp() {
var theCanvas = document.getElementById("canvasOne");
var context = theCanvas.getContext("2d");
drawScreen();
function drawScreen() {
//translation to centre canvas
context.setTransform(1, 0, 0, 1, 0, 0);
var x = canvasOne.width/2;
var y = canvasOne.height/2;
var circleWidth = 100;
var circleHeight = 100;
context.translate(x+.5*circleWidth, y+.5*circleHeight);
context.save();
//speed
r += speed;
//canvas
context.fillStyle = "blue";
context.fillRect(-(canvasOne.width/2+circleWidth/2), -(canvasOne.height/2+circleHeight/2), canvasOne.width, canvasOne.height);
//circle 1
context.strokeStyle = "#66f";
context.lineWidth = 4;
context.beginPath();
context.arc(-circleWidth/2, -circleHeight/2, r,(Math.PI/180)*0,(Math.PI/180)*360, false);
context.closePath();
//call circle 1
context.stroke();
context.restore();
//circle 2
context.strokeStyle = "#69f";
context.lineWidth = 4;
context.beginPath();
context.arc(-circleWidth/2, -circleHeight/2, r+4,(Math.PI/180)*0,(Math.PI/180)*360, false);
context.closePath();
//call circle 2
context.stroke();
context.restore();
//circle 3
context.strokeStyle = "#6cf";
context.lineWidth = 4;
context.beginPath();
context.arc(-circleWidth/2, -circleHeight/2, r+8,(Math.PI/180)*0,(Math.PI/180)*360, false);
context.closePath();
//call circle 3
context.stroke();
context.restore();
//disc gradient
var grad = context.createRadialGradient(100, 100, 0, 100, 100, 100);
grad.addColorStop(0, 'white');
grad.addColorStop(.5, 'grey');
grad.addColorStop(1, 'black');
context.fillStyle = grad;
//disc
context.beginPath();
context.arc(-circleWidth/2, -circleHeight/2, 100, (Math.PI/180)*0,(Math.PI/180)*360, false);
context.closePath();
//call disc
context.fill();
} //end drawScreen
var speed = 20;
var r = 100;
setInterval(drawScreen, 200);
} //end canvasApp
</script>
</head>
<body>
<canvas id="canvasOne" width="900" height="500">
Canvas is not supported.
</canvas>
</body>
</html>
You have the centre of the gradient at (100,100) which is not the centre of the circle.
Change the line
var grad = context.createRadialGradient(100, 100, 0, 100, 100, 100);
to
var grad = context.createRadialGradient(-circleWidth/2, -circleHeight/2, 0, -circleWidth/2, -circleHeight/2, 100);