Please help me calculate the 'bleed' of an image.
First question: How do I get the dimensions of a dynamic image?
Second question: Sombody knows what is the calculation for bleed?
I will combine the image + bleed indicator..
(If the picture is dynamic i need the bleed to be dynamic too...)
eg x-3=x, y-3=x
I have this code that represents what I want to achieve.
Fiddle
HTML:
<canvas id="c"></canvas>
<br>
<div>
<button onclick="blue_square_2();return true;">Inner Square</button>
<button onclick="red_stroke_2();return true;">Outer Square</button>
</div>
JS:
var canvas = new fabric.StaticCanvas('c');
canvas.setBackgroundImage('img/24-18-0.jpg', canvas.renderAll.bind(canvas));
this.__canvases.push(canvas);
var c2 = document.getElementById("c");
var c2_context = c2.getContext("2d");
function blue_square_2() { //Green color square
canvas.add(new fabric.Rect({
left: 250,
top: 300,
fill: "",
stroke: "green",
strokeWidth: 11.34,
width: 468,
height: 568,
opacity: 0.7
}));
}
function red_stroke_2() { //Blue color edges
canvas.add(new fabric.Rect({
left: 250,
top: 300,
fill: "",
stroke: "blue",
strokeWidth: 11.34,
width: 489,
height: 589,
opacity: 0.7
}));
}
//For someone who also have question like mine, this this is my own answer and calculations
<img id="scream" src="back2.jpg" alt="The Scream" width="220px" height="277px">
<canvas id="c" style="border:1px solid black;"></canvas>
<div>
<button onclick="blue_square_2();return true;">Blue Square</button>
<button onclick="green_stroke_2();return true;">Green Square</button>
<button onclick="clear_rect_2();return true;">Erase Everything</button>
</div>
<script type="text/javascript">
// draw image
var canvas = new fabric.StaticCanvas('c');
canvas.setBackgroundImage('back2.jpg', canvas.renderAll.bind(canvas));
function getHeight(){
return document.querySelector('img').naturalHeight;
}
function getWidth(){
return document.querySelector('img').naturalWidth;
}
function setSize(x,y){
width = x;
height = y;
}
function setCanvasSize(x,y){
canvas.setWidth(x);
canvas.setHeight(y);
width = x;
height = y;
}
var sourceWidth = getWidth();
var sourceHeight = getHeight();
var targetWidth = 400;
var targetHeight = 200;
var sourceRatio = sourceWidth / sourceHeight;
var targetRatio = targetWidth / targetHeight;
var scale;
if ( sourceRatio < targetRatio ) {
scale = sourceWidth / targetWidth;
} else {
scale = sourceHeight / targetHeight;
}
var resizeWidth = parseInt((sourceWidth / scale));
var resizeHeight = parseInt((sourceHeight / scale));
// ctx.drawImage(img,0,0,width,height);
setCanvasSize(resizeWidth,resizeHeight);
console.log(height);
console.log(width);
if(width != getWidth()){
linewidth = (11.34 * 9 ) / (getWidth() / width) ;
linewidth2 = linewidth/2;
}
console.log(linewidth);
// fabric.Object.prototype.originX = true; fabric.Object.prototype.originY = true;
var c2 = document.getElementById("c");
var ctx = c2.getContext("2d");
var rect1 = new fabric.Rect({
left: width/2,
top: height/2,
fill:"",
stroke:"green",
strokeWidth:linewidth,
width: width,
height: height,
opacity: 0.5
});
console.log(linewidth);
var rect2 = new fabric.Rect({
left: width/2 ,
top: height/2 ,
fill:"",
stroke:"blue",
strokeWidth:linewidth2,
width: width-(linewidth+linewidth2),
height: height-(linewidth+linewidth2),
opacity: 0.5
});
Related
In the below Image I have three boxes in the canvas and there are three buttons at the bottom of the image. Whenever I click a button, the corresponding object in the canvas gets selected(i,e, when I click the green button, green rectangle in the canvas, gets selected).
My requirement is to highlight only the selected portion and other portion of the canvas should be grayed out. (Ex: If I click the green button green rectangle should be selected and other portion should be overlayed with a gray background).
Js Fiddle Link: https://jsfiddle.net/rnvs2hdk/1/
var canvas = new fabric.Canvas('c');
canvas.backgroundColor = 'yellow';
var li= []
canvas.renderAll();
fabric.Image.fromURL('http://fabricjs.com/assets/pug_small.jpg', function(myImg) {
var img1 = myImg.set({ left: 0, top: 0 ,width:400,height:500});
canvas.add(img1);
var green = new fabric.Rect({
left: 50,
top: 50,
width: 50,
height: 50,
fill: 'rgba(255,255,255,1)',
stroke: 'rgba(34,177,76,1)',
strokeWidth: 5,
name:"green"
});
var yellow = new fabric.Rect({
left: 150,
top: 50,
width: 50,
height: 50,
fill: 'rgba(255,255,255,1)',
stroke: 'rgba(255,255,0,1)',
strokeWidth: 5,
name:"yellow"
});
var red = new fabric.Rect({
left: 250,
top: 50,
width: 50,
height: 50,
fill: 'rgba(255,255,255,1)',
stroke: 'rgba(255,0,0,1)',
strokeWidth: 5,
name:"red"
});
canvas.add(green, yellow,red);
li.push(green);
li.push(yellow);
li.push(red);
li.some(v=>{
var btn = document.createElement("BUTTON"); // Create a <button> elem
btn.innerHTML = v.name;
btn.addEventListener('click',function(e){
var name = e.target
if(name.innerText == "green"){
canvas.setActiveObject(li[0]);
}
if(name.innerText == "yellow"){
canvas.setActiveObject(li[1]);
}
if(name.innerText == "red"){
canvas.setActiveObject(li[2]);
}
});// Insert text
document.body.appendChild(btn);
});
console.log(li);
});
Expected Result:(example)
Here's my solution. Using the after:render event, you can perform canvas draw actions over each frame after it is rendered. This approach has the benefit of avoiding having to create and destroy fabric objects as needed which is an expensive operation.
Be sure to call the .setCoords() method during actions like scaling and moving so that objects will update their position information while performing these actions.
var canvas = new fabric.Canvas('c');
canvas.backgroundColor = 'yellow';
var li = [];
canvas.renderAll();
fabric.Image.fromURL('http://fabricjs.com/assets/pug_small.jpg', function(myImg) {
var img1 = myImg.set({
left: 0,
top: 0,
width: 400,
height: 500
});
canvas.add(img1);
var green = new fabric.Rect({
left: 50,
top: 50,
width: 50,
height: 50,
fill: 'rgba(255,255,255,1)',
stroke: 'rgba(34,177,76,1)',
strokeWidth: 5,
name: "green",
hasRotatingPoint: false
});
var yellow = new fabric.Rect({
left: 150,
top: 50,
width: 50,
height: 50,
fill: 'rgba(255,255,255,1)',
stroke: 'rgba(255,255,0,1)',
strokeWidth: 5,
name: "yellow",
hasRotatingPoint: false
});
var red = new fabric.Rect({
left: 250,
top: 50,
width: 50,
height: 50,
fill: 'rgba(255,255,255,1)',
stroke: 'rgba(255,0,0,1)',
strokeWidth: 5,
name: "red",
hasRotatingPoint: false
});
canvas.add(green, yellow, red);
li.push(green);
li.push(yellow);
li.push(red);
li.some(v => {
var btn = document.createElement("BUTTON"); // Create a <button> elem
btn.innerHTML = v.name;
btn.addEventListener('click', function(e) {
var name = e.target
if (name.innerText == "green") {
canvas.setActiveObject(li[0]);
}
if (name.innerText == "yellow") {
canvas.setActiveObject(li[1]);
}
if (name.innerText == "red") {
canvas.setActiveObject(li[2]);
}
}); // Insert text
document.body.appendChild(btn);
});
console.log(li);
});
canvas.on({
'object:moving': function(e) {
//makes objects update their coordinates while being moved
e.target.setCoords();
},
'object:scaling': function(e) {
//makes objects update their coordinates while being scaled
e.target.setCoords();
}
});
//the after:render event allows you to perform a draw function on each frame after it is rendered
canvas.on('after:render', function() {
var ctx = canvas.contextContainer,
obj = canvas.getActiveObject();
if (obj) {
//set the fill color of the overlay
ctx.fillStyle = "rgba(0, 0, 0, 0.3)";
var bound = obj.getBoundingRect();
ctx.beginPath();
//draw rectangle to the left of the selection
ctx.rect(0, 0, bound.left, canvas.height);
//draw rectangle to the right of the selection
ctx.rect(bound.left + bound.width, 0, canvas.width - bound.left - bound.width, canvas.height);
//draw rectangle above the selection
ctx.rect(bound.left, 0, bound.width, bound.top);
//draw rectangle below the selection
ctx.rect(bound.left, bound.top + bound.height, bound.width, canvas.height - bound.top - bound.height)
ctx.fill();
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<canvas id="c" width="400" height="400"></canvas>
<div id="bt"></div>
I have Accomplished this creating 4 more rectangles around the actual rectangle. I have grayed out the outer rectangles so it gives the overlay effect. Also, I will delete all the rectangles before creating a new one.
let blankColor = "rgba(0,0,0,0)";
let grayOut = "rgba(0,0,0,0.4)";
let rect = createRect(x, y, width, height, 1, blankColor);
let rect1 = createRect(0, 0, getViewPortDimensions()[0], y, 0, grayOut);
let rect2 = createRect(0, y + height, getViewPortDimensions()[0], getViewPortDimensions()[1] - (y + height), 0, grayOut);
let rect3 = createRect(0, y, x, height, 0, grayOut);
let rect4 = createRect(x + width, y, getViewPortDimensions()[0] - (x + width), height, 0, grayOut);
state.canvas.add(rect, rect1, rect2, rect3, rect4);
Deleting the already drawn rectangle:
state.canvas.forEachObject((o, index) => {
if (index != 0) {
state.canvas.remove(o);
}
})
I'd like to use a polyline to connect two rectangles and stay connected to the same points on the respective rectangles as the rectangles move (specifically, for two rectangles on a page, I'd like the polyline to connect the bottom middle point of one rectangle to the top middle part of another rectangle. The reason I'm using a PolyLine is because I will eventually be adding in elbows down the road as well). I'm having issues with the polyline coordinates updating in response to the moving rectangles though.
This demonstrates some of the issues I am hitting:
var canvas = new fabric.Canvas('c');
rect = null;
line = null;
function addLine(x1, y1, x2, y2) {
var coords = [{x: x1, y: y1}, {x: x2, y: y2}];
this.line = new fabric.Polyline(coords, {
stroke: 'green',
strokeWidth: 5,
fill: 'rgba(0,0,0,0)',
selectable: true,
evented: false
});
this.canvas.add(this.line);
}
function addRect(left, top, width, height, line1, line2, line3, line4) {
this.rect = new fabric.Rect({
left: left,
top: top,
width: width,
height: height,
fill: '#9f9',
originX: 'left',
originY: 'top',
centeredRotation: true
});
this.rect.line1 = line1;
this.rect.line2 = line2;
this.rect.line3 = line3;
this.rect.line4 = line4;
this.canvas.add(this.rect);
}
var r1_left = 10;
var r1_top = 20;
var r1_width = 125;
var r1_height = 150;
var r2_left = 350;
var r2_top = 300;
var r2_width = 125;
var r2_height = 150;
addLine(r1_left + r1_width/2, r1_top + r1_height, r2_left + r2_width/2, r2_top);
addRect(r1_left, r1_top, r1_width, r1_height, null, null, this.line, null);
addRect(r2_left, r2_top, r2_width, r2_height, this.line, null, null, null);
this.canvas.renderAll();
this.canvas.on('object:moving', function(e) {
var p = e.target;
if (p.line1) {
let x_2_new = p.left + p.width/2;
let y_2_new = p.top;
p.line1.set('points', [p.line1.points[0], {'x': x_2_new, 'y': y_2_new}]);
p.line1.set('height', y_2_new - p.line1.points[0]['y']);
p.line1.set('width', x_2_new - p.line1.points[0]['x']);
p.set('oCoords', p.line1.calcCoords());
} else if (p.line2) {
p.line2.set({'points': [{'x': p.left + p.width, 'y': p.top + p.height/2}, p.line2.points[1]]});
} else if (p.line3) {
p.line3.set({'points': [{'x': p.left + p.width/2, 'y': p.top + p.height}, p.line3.points[1]]});
} else if (p.line4) {
p.line4.set({'points': [p.line4.points[0], {'x': p.left, 'y': p.top + p.height/2}]});
}
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
</head>
<body>
<canvas id="c" width="700" height="700" style="border:1px solid #ccc"></canvas>
<script>
</script>
</body>
</html>
For the upper rectangle, I have tried simply setting the x and y coordinates as the object moves. With this, I encounter the error that x and y seem to be bound by the oCoords and aCoords of the line.
For the lower rectangle, I have tried setting the coordinates directly. With this, the entire line seems to shift around the page.
Any advice about what I could change here would be great. Thanks!
Here is the code, what you need, jsfiddle
(function() {
var canvas = this.__canvas = new fabric.Canvas('c', { selection: false });
fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';
function makeCircle(left, top, line1, line2) {
var c = new fabric.Rect({
top: top,
left: left,
width: 30,
height: 30,
selection: false,
fill: '#ccc'
});
c.hasControls = c.hasBorders = false;
c.line1 = line1;
c.line2 = line2;
return c;
}
function makeLine(coords) {
return new fabric.Line(coords, {
fill: 'red',
stroke: 'red',
strokeWidth: 5,
selectable: false,
evented: false,
});
}
var line = makeLine([ 250, 125, 250, 375 ]),
line2 = makeLine([ 250, 375, 250, 350 ]);
canvas.add(line);
canvas.add(
makeCircle(line.get('x1'), line.get('y1'), null, line),
makeCircle(line.get('x2'), line.get('y2'), line, line2),
);
canvas.on('object:moving', function(e) {
var p = e.target;
p.line1 && p.line1.set({ 'x2': p.left, 'y2': p.top });
p.line2 && p.line2.set({ 'x1': p.left, 'y1': p.top });
canvas.renderAll();
});
})();
<div>
<canvas id="c" width="700" height="575" style="border:1px solid #999"></canvas>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/fabric.js/2.7.0/fabric.min.js"></script>
I wrote an app where I am trying to hide right eye of the dog using fabric.js rectangle.
But if I resize the window the rectangle is moved.
Here's the fiddle and code :
`
var canvas = this.__canvas = new fabric.Canvas('c');
canvas.setWidth(window.innerWidth*0.98);
canvas.setHeight(window.innerHeight*0.98);
canvas.backgroundColor = 'pink';
canvas.selection = false;
var x1=150, y1=150, x2=180, y2=180, img1;
var rect = new fabric.Rect({
stroke: 'blue',
opacity: 1,
strokeWidth: 2,
selectable: true,
fill : 'green',
left : x1,
top : y1,
width : x2,
height : y2
});
fabric.Image.fromURL('http://fabricjs.com/assets/pug_small.jpg', function(myImg) {
//i create an extra var for to change some image properties
img1 = myImg.set({ left: 0, top: 0 ,width:canvas.width,height:canvas.height});
canvas.add(img1);
canvas.add(rect);
});
window.addEventListener("resize", function() {
console.log('resizing');
var dims = {
w : canvas.width,
h : canvas.height
};
canvas.setWidth(window.innerWidth*0.98);
canvas.setHeight(window.innerHeight*0.98);
img1.width = window.innerWidth*0.98;
img1.height = window.innerHeight*0.98;
rect.left *= dims.w/canvas.width;
rect.top *= dims.h/canvas.height;
rect.width *= dims.w/canvas.width;
rect.height *= dims.h/canvas.height;
});`
Am I missing something?
I drew a rectangle with kinetic.js and animating it in a circular path. In each animation frame i reduce it's radius.
Now i want to draw the line of this rectangle's animating path. I am not sure how can i do it by kinetic.js. Please help!
My codes
var R = 150;
$(document).ready(function () {
var stage = new Kinetic.Stage({
container: 'container',
width: 500,
height: 500
});
var layer = new Kinetic.Layer();
var rect = new Kinetic.Rect({
x: 10,
y: 10,
width: 100,
height: 100,
fill: 'black',
stroke: 'red'
});
layer.add(rect);
stage.add(layer);
var centerX = stage.width() / 2;
var anim = new Kinetic.Animation(
function (f) {
var cX = stage.width() / 2;
var cY = stage.height() / 2;
R = R - 1 / 1000;
var X = cX + R * Math.cos(f.time / 1000);
var Y = cY + R * Math.sin(f.time / 1000);
rect.setX(X);
rect.setY(Y);
}, layer);
anim.start();
});
Here is the codes: http://jsfiddle.net/tanvirgeek/n8z8N/
Thanks In advance.
This is how you can draw line segments that follow the path of your rectangle:
Demo: http://jsfiddle.net/m1erickson/Cbq2c/
First Create a Kinetic.Line that will trace the rectangle's path
var line=new Kinetic.Line({
stroke:"blue"
});
layer.add(line);
Second When you generate a new XY in the animation loop, add that XY to the line's points
var points=line.getPoints();
points.push(X,Y);
line.setPoints(points);
Important Warning! This Kinetics animation loop develops an undesirable pausing "stagger". This stagger is small in Chrome, noticeable in IE and horrible in FireFox. This seems to be due to the Kinetic.Line being unable to smoothly add + draw thousands of changing points of data, so I instead recommend using regular html5 canvas and requestAnimationFrame to do your effect.
<!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://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.0.1.min.js"></script>
<style>
body{padding:20px;}
#container{
border:solid 1px #ccc;
margin-top: 10px;
width:350px;
height:350px;
}
</style>
<script>
$(function(){
var stage = new Kinetic.Stage({
container: 'container',
width: 350,
height: 350
});
var layer = new Kinetic.Layer();
stage.add(layer);
var line=new Kinetic.Line({
points:[0,0,100,100],
stroke:"blue",
strokeWidth:2
});
layer.add(line);
var rect = new Kinetic.Rect({
x: 100,
y: 100,
width: 15,
height: 15,
fill: 'black',
stroke: 'red'
});
layer.add(rect);
var cx=stage.getWidth() / 2;
var cy=stage.getHeight()/2;
var R=100;
var A=0;
points=[];
var anim = new Kinetic.Animation(
function (f) {
R = R - 1 / 100;
A += Math.PI/180;
var X = cx + R * Math.cos(A);
var Y = cy + R * Math.sin(A);
points.push(X,Y);
line.setPoints(points);
rect.setX(X);
rect.setY(Y);
},
layer);
anim.start();
}); // end $(function(){});
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
Here is the jsfiddle.
I want to limit the maximum height/width of the object when you are resizing it.
Here is the code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://raw.github.com/kangax/fabric.js/master/dist/all.js"></script>
</head>
<body>
<canvas id="c" width="300" height="300" style="border:1px solid #ccc"></canvas>
<script>
(function() {
var canvas = new fabric.Canvas('c');
canvas.add(new fabric.Rect({ width: 50, height: 50, fill: 'red', top: 100, left: 100 }));
canvas.add(new fabric.Rect({ width: 30, height: 30, fill: 'green', top: 50, left: 50 }));
})();
</script>
</body>
</html>
When scaling fabric Objects, the scaleX and scaleY properties are updated to reflect the new scaled size of the object. So the actual width of a rect with an initial width of 50 when scaled 2x will be 100.
What you need to do is figure out the maximum scale allowed for your shape given it's maxHeight or maxWidth. That's calculated by dividing the maximum dimension by the initial dimension.
Here's an example of how to implement maximum sizes for objects
var canvas = new fabric.Canvas("c");
var rect1 = new fabric.Rect({ width: 50, height: 50, fill: 'red', top: 100, left: 100});
var rect2 = new fabric.Rect({ width: 30, height: 30, fill: 'green', top: 50, left: 50 });
// add custom properties maxWidth and maxHeight to the rect
rect1.set({maxWidth:100, maxHeight:120});
canvas.observe("object:scaling", function(e){
var shape = e.target
, maxWidth = shape.get("maxWidth")
, maxHeight = shape.get("maxHeight")
, actualWidth = shape.scaleX * shape.width
, actualHeight = shape.scaleY * shape.height;
if(!isNaN(maxWidth) && actualWidth >= maxWidth){
// dividing maxWidth by the shape.width gives us our 'max scale'
shape.set({scaleX: maxWidth/shape.width})
}
if(!isNaN(maxHeight) && actualHeight >= maxHeight){
shape.set({scaleY: maxHeight/shape.height})
}
console.log("width:" + (shape.width * shape.scaleX) + " height:" + (shape.height * shape.scaleY));
});
Works with most fabric objects.. but you want to get the ratio of your object, for maxWidth you can copy this... for maxHeight reverse it.
fabric.Image.fromURL(photo, function(image) {
//console.log(image.width, image.height);
var heightRatio = image.height / image.width;
var maxWidth = 100;
image.set({
left: canvasDimensions.width / 2,//coord.left,
top: canvasDimensions.height / 2, //coord.top,
angle: 0,
width: maxWidth,
height: maxWidth * heightRatio
})
//.scale(getRandomNum(minScale, maxScale))
.setCoords();
canvas.add(image);
})