With Snap SVG I am trying to create an rect dynamically.
When I click, it should create a rect at the position of the mouse click.
it's create the rect, BUT the postion is always wrong.
Here is my script : http://jsfiddle.net/noteStylet/L2kpd6yt/
So My question is Who to create a rect at the mouse click postion and not below.
HTML :
<h1>Click to create </h1>
<div>
<svg id="plan" width="900" height="500"></svg>
</div>
Javascript :
var snap = Snap("#plan");
//create an image
var imagePlan = snap.image("http://upload.wikimedia.org/wikipedia/commons/4/42/Cathedral_schematic_plan_fr_vectorial.svg", 10, 10, 900, 500);
imagePlan.click(function (evt) {
//When click, create a rect
var rect1 = snap.rect(evt.clientX, evt.clientY, 40, 40);
});
Thanks !
We should use this method :
var transformed = pt.matrixTransform(mySvg.getScreenCTM().inverse());
var rect1 = s.rect(transformed.x, transformed.y, 40, 40);
instead of
var rect1 = snap.rect(evt.clientX, evt.clientY, 40, 40);
We have to use :
var mySvg = $("#svg1")[0];
var pt = mySvg.createSVGPoint(); // create the point;
imagePlan.click(function(evt)
{
pt.x = evt.x;
pt.y = evt.y;
// convert the mouse X and Y so that it's relative to the svg element
var transformed = pt.matrixTransform(mySvg.getScreenCTM().inverse());
var rect1 = s.rect(transformed.x, transformed.y, 40, 40);
});
Here is the Example : http://jsfiddle.net/noteStylet/L2kpd6yt/6/
Your problem is the grid system of the svg you need to re-abjust it so that your mouse is not the (0,0) but rather the (-20,-80).
change the rect creation code to :
var rect1 = snap.rect(evt.clientX-20, evt.clientY-80, 40, 40);
and it should work
update:
Ok so what you need is 1.get mouse position and 2.the position of the image ( left & top values). Then subtract them from current mouse position so you can adjust the svg grid to feet your needs
var snap = Snap("#plan");
//create an image
var imagePlan = snap.image("http://upload.wikimedia.org/wikipedia/commons/4/42/Cathedral_schematic_plan_fr_vectorial.svg", 10, 10, 900, 500);
var currentMousePos = { x: -1, y: -1 };
$(document).mousemove(function(event) {
currentMousePos.x = event.pageX;
currentMousePos.y = event.pageY;
var image = $( "#plan" );
var position = image.position();
imagePlan.click(function()
{
//When click, create a rect
var rect1 = snap.rect(currentMousePos.x-position.left ,currentMousePos.y-position.top, 40, 40);
});
});
Related
I want to replicate the basic functionality of a free transform tool (no rotation), by dragging on the border of a easeljs Shape and adjusting the container to match it. I'm currently using the scaleX and scaleY properties and it sort of works but is not quite right.
If you do one scaling transformation it works pretty well. However if you release, then do another scaling transformation, it jumps very glitchily, and can occasionally break sending the x/y coordinates all the way to stage 0. Any help on this issue would be great!
http://jsfiddle.net/frozensoviet/dsczvrpw/13/
//circle
var circle = new createjs.Shape(new createjs.Graphics()
.beginFill("#b2ffb2")
.drawCircle(0, 0, 50));
circle.setBounds(0, 0, 50, 50);
//create the border as a seperate object
var cBorder = new createjs.Shape(new createjs.Graphics().setStrokeStyle(10)
.beginStroke("#000").drawCircle(0, 0, 50));
cBorder.setBounds(0, 0, 50, 50);
//add both to the container
circleContainer.addChild(circle);
circleContainer.addChild(cBorder);
var cWidth = circleContainer.getBounds().width;
var cHeight = circleContainer.getBounds().height;
//find initial mouse position relative to circle center
cBorder.on("mousedown", function (evt) {
//initial mouse pos
this.initial = {
x: Math.abs(-(circleContainer.x - evt.stageX)),
y: Math.abs(circleContainer.y - evt.stageY)
};
});
//set the relevant circle axis scale to ratio of mouse pos/initial mouse pos
cBorder.on("pressmove", function (evt) {
//current moouse pos
this.offset = {
x: Math.abs(-(circleContainer.x - evt.stageX)),
y: Math.abs(circleContainer.y - evt.stageY)
};
if (this.initial.x > this.initial.y) {
//sides
circleContainer.scaleX = this.offset.x / this.initial.x;
} else if (this.initial.x < this.initial.y) {
//top/bottom
circleContainer.scaleY = this.offset.y / this.initial.y;
} else {
//diagonals
circleContainer.scaleX = this.offset.x / this.initial.x;
circleContainer.scaleY = this.offset.y / this.initial.y;
}
stage.update();
});
The issue is your initial calculations don't account for the change in the scale of the circle. You would have to transform the coordinates using localToGlobal. Fortunately, there is an even easier way:
this.initial = {
x: Math.abs(evt.localX),
y: Math.abs(evt.localY)
};
You can also turn on ignoreScale on the border, which makes it not stretch:
createjs.Graphics().setStrokeStyle(10,null,null,null,true) // The 5th argument
Lastly, your bounds setting might work for your demo, but it is not correct. Your circle draws from the center, so it should be:
cBorder.setBounds(-25, -25, 50, 50);
Here is an updated fiddle: http://jsfiddle.net/tfy1sjnj/3/
i am working with fabric js and i want to draw two objects within canvas and when second object is drawn it should be drawn inside first object and never move outside the first object.I have tried this code
$(document).ready(function () {
var canvas = new fabric.Canvas('demo');
var rec = new fabric.Rect({
width: 200,
height: 100,
top: 10,
fill: 'blue',
});
rec.name = 'aaa';
canvas.add(rec);
canvas.on('object:moving', function (e) {
var h = rec.top;
var w = rec.width;
var obj = e.target;
obj.setCoords();
var rect = obj.getBoundingRect;
if(rect > h){
rect.top = Math.max(rect.top, rect.top-rect.getBoundingRect().top);
// alert(rect.top);
}
});
var text=new fabric.IText('Jayesh');
canvas.add(text);
});
Thanks in advance.Pls help
I have five rectangles placed at different points along a circle like this - http://imgur.com/uVYkwl7.
Upon clicking any rectangle i want the circle to move to the left of the screen, gradually scaling down it's radius until the circle's center reaches x=0. I'd like the five rectangles to move along with the circle while its being scaled down and also adjust their own positions and scale on the circle so that they are within the view's bounds, like this - http://imgur.com/acDG0Aw
I'd appreciate any help on how to go about doing this. Heres my code for getting to the 1st image and animating the circle:
var radius = 300;
var center = view.center;
var circle = new Path.Circle({
center: view.center,
radius: radius,
strokeColor: 'black',
name: 'circle'
});
var path = new Path.Rectangle({
size: [230, 100],
fillColor: '#1565C0'
});
var rectText = ['Text 1',
'Text 2',
'Text 3',
'Text 4',
'Text 5'
];
var symbol = new Symbol(path);
var corners = [
new Point(center.x, center.y - radius),
new Point(center.x - radius, center.y - radius / 2),
new Point(center.x + radius, center.y - radius / 2),
new Point(center.x - radius, center.y + radius / 2),
new Point(center.x + radius, center.y + radius / 2)
];
var rectClicked = false;
var clickedRect = null;
var rectClick = function(event) {
rectClicked = true;
clickedRect = this;
};
function onFrame(event) {
// Your animation code goes in here
if (rectClicked) {
for (var i = 0; i < 1; i++) {
var item = project.activeLayer.children[i];
if (item.name == 'circle') {
if (item.position.x < 0) {
rectClicked = false;
} else {
item.position.x -= 10;
item.scale(1/1.01);
}
}
}
}
}
// Place the instances of the symbol:
for (var i = 0; i < corners.length; i++) {
var placedSymbol = symbol.place(corners[i]);
placedSymbol.onMouseDown = rectClick;
var rText = new PointText({
point: placedSymbol.bounds.topLeft + 20,
content: rectText[i],
fontSize: '20',
fillColor: 'white'
});
}
Paper.js provides rotations around a pivot out of the box.
var pivotPoint = new Point(10, 5);
circle.rotate(30,pivotPoint);
Here is the docs reference for this behaviour and here is a very basic Sketch example to illustrate this
The above snippet will rotate a circle(you can change this to rectangle in your case) by 30 degrees around a pivot point at coordinates 10,5 on the x/y axis.
Thus what you describe is certainly doable as long as the path that your elements will follow is always circular.
Bear in mind that in order for the pivot rotation to work the way you want them to you need to update the pivotPoint and reinitiate the rotation again.
Note: In case you want to move along an arbitrary shape instead of circular path, you should search for Paper.js animation-along-a-path which is something that I've seen been done before without much difficulty - e.g this simple Sketch by the creator of Paper.js himself.
The sketch I provided above is a basic example of rotation around a pivot point.
I'm dumping the Sketch code here in case the link goes dead:
//Create a center point
var centerCircle = new Path.Circle(paper.view.center, 100);
centerCircle.strokeColor = 'black';
centerCircle.dashArray = [10, 12];
//Create the circles
var circle1Radius = 30;
var circle1 = new Path.Circle((centerCircle.position-centerCircle.bounds.width/2)+circle1Radius, circle1Radius);
circle1.fillColor = '#2196F3';
var circle2Radius = 40;
var circle2 = new Path.Circle((centerCircle.position-centerCircle.bounds.width/2)+circle2Radius, circle2Radius);
circle2.fillColor = '#E91E63';
var circle3Radius = 40;
var circle3 = new Path.Circle((centerCircle.position-centerCircle.bounds.width/2)+circle2Radius, circle2Radius);
circle3.fillColor = '#009688';
var i=0;
var animationGap = 125; //how long to move before animating the next circle
var rotationSpeed = 2;
function onFrame(event) {
circle1.rotate(rotationSpeed,centerCircle.position);
if(i>animationGap)
circle2.rotate(rotationSpeed,centerCircle.position);
if(i>animationGap*2)
circle3.rotate(rotationSpeed,centerCircle.position);
i++;
}
I am trying to do an interactive drawing using Fabric.js. Now I can draw a rectangle by using mouse. But after I finish drawing the rectangle, I can not select it unless I resize it once by using the left top controller after drawing. I wonder what break the event system.
Here is my code: http://jsfiddle.net/rmFgX/1/
var canvas = new fabric.Canvas('canvas');
var rect = new fabric.Rect({
top : 100,
left : 100,
width : 60,
height : 70,
fill : 'red'
});
canvas.add(rect);
canvas.on('mouse:down', function (option) {
console.log(option);
if (typeof option.target != "undefined") {
return;
} else {
var startY = option.e.offsetY,
startX = option.e.offsetX;
console.log(startX, startY);
var rect2 = new fabric.Rect({
top : startY,
left : startX,
width : 0,
height : 0,
fill : 'transparent',
stroke: 'red',
strokewidth: 4
});
canvas.add(rect2);
console.log("added");
canvas.on('mouse:move', function (option) {
var e = option.e;
rect2.set('width', e.offsetX - startX);
rect2.set('height', e.offsetY - startY);
rect2.saveState();
});
}
});
canvas.on('mouse:up', function () {
canvas.off('mouse:move');
});
updated the fiddle http://jsfiddle.net/rmFgX/5/
For an object when changing position/dimension -related properties (left, top, scale, angle, etc.) set does not update position of object's borders/controls.
If you need to update those, call:
setCoords().
Is there any option to increase bar chart as animation from 0 to ?
bars.animate({'stroke':"#FF0"},1000); this can change attributes. Actually I need to change value of bar chart height and also change label when increase which didn't find yet.
var svgWidth = 400;
var svgHeight = 450;
var r = Raphael('overview');
var barBorder = {stroke: '#000', 'stroke-width':1};
r.setViewBox(0, 0, svgWidth, svgHeight, false);
r.setSize('100%', '100%');
var colors = [ "#999", "#B2B2B2", "#CCC"];
data4 = [[83], [72], [43]];
data2 = [[13], [22], [20]];
var bars = r.barchart(50, 20, 250, 150, data4, {colors: colors, 'gutter': '-1%'}).bars.attr(barBorder);//.hover(fin, fout);
var unicorn = r.path("M350 150 H10 V10").attr({stroke: "#000","stroke-width": 1});
bars.animate({'stroke':"#FF0"},1000);
Demo.
Finally changed barchart() to rect()
here is my solution http://jsfiddle.net/sweetmaanu/sqnXM/
// Create options object that specifies the rectangle
var PatientBar1 = { width: 100,height: 200,x: 0,y: 0}
var PatientBar2 = { width: 100,height: 180,x: 100,y: 20}
var PatientBar3 = { width: 100,height: 120,x: 200,y: 80}
var speed = 2000;
// Create new raphael object
var patient01 = new Raphael('patient02-mobile', 300, 300);
/*
* Create rectangle object with y-position at bottom by setting it to the specified height,
* also give the rectangle a height of '0' to make it invisible before animation starts
*/
var rect1 = patient01.rect(PatientBar1.x, PatientBar1.height, PatientBar1.width, 0).attr({fill: '#999', stroke:'#000'});
var rect2 = patient01.rect(PatientBar2.x, 200, PatientBar2.width, 0).attr({fill: '#B2B2B2', stroke:'#000'});
var rect3 = patient01.rect(PatientBar3.x, 200, PatientBar3.width, 0).attr({fill: '#CCC', stroke:'#000'});
/*
* Animate the rectangle from bottom up by setting the height to the earlier specified
* height and by setting the y-position to the top of the rectangle
*/
var anim1 = rect1.animate({
y:PatientBar1.y,
height:PatientBar1.height
}, speed);
var anim2 = Raphael.animation({
y:PatientBar2.y,
height:PatientBar2.height
}, speed);
var anim3 = Raphael.animation({
y:PatientBar3.y,
height:PatientBar3.height
}, speed);
rect2.animate(anim2.delay(2000));
rect3.animate(anim3.delay(4000));
Please post answer if anybody find solution :)