Raphael.js set movement with text "Raphael is undefined" - javascript

I have been struggling to implement drag and drop for a set in raphael.js.
I have managed to do so for sets that are made up of circles, using this code on JSFiddle.
var r = Raphael(10, 50, 600, 600);
var Intermediate = r.set();
var start = function () {
// storing original coordinates
this.ox = this.attr("cx");
this.oy = this.attr("cy");
};
move = function (dx, dy) {
// move will be called with dx and dy
Intermediate.attr({cx: this.ox + dx, cy: this.oy + dy});
};
up = function () {};
Intermediate.drag(move, start, up);
However this does not work for sets made up from rectangles and text, because they do not have cy and cx properties. Replacing cx and cy with x and y respectively does not work as two objects will have different x and y values while concentric circles will have the same cx and cy values.
I found a solution, here, also on JSFiddle, which defines a new method in Raphael.st.
Raphael.st.draggable = function() {};
It then just enables the set to be draggable:
mySet.draggable();
Hoever when I try implement this solution in visual studio I get an error "0x800a1391 - JavaScript runtime error: 'Raphael' is undefined".
I don't understand why this is, I have added the Raphael script to my HTML.

Related

getting proper mouse position inside a zoomable iframe

I have a project on svg-edit where i have to create polygon on mouse-click , the svg-canvas (not HTML5 canvas suppose as drawing board) is zoomable, i can create polygon on 100% zoom but when i zoomin or zoomout i can't, actually i am unable to get right x and y position after zoom.as you can see in image.
I had tried this method to get points--
//Container 1440*1920
var svgcanvas = document.getElementById("svgcanvas");
//zoom
var initialZoom = 1440 * 1920;
zoomWidth = parseFloat(svgcanvas.style.width);
zoomHeight = parseFloat(svgcanvas.style.height);
currentZoom = zoomHeight * zoomWidth;
zoom = currentZoom / initialZoom;
//points
var rect = event.target.getBoundingClientRect();
var x1 = ((event.clientX) / zoom) - rect.left;
var y1 = ((eevent.clientY) / zoom) - rect.top;
and my task is
It seems you are not interacting with the svg-edit API at all. Things get much easier if you do.
// do not interact with the DOM element, but with the API object
var svgcanvas = svgEditor.canvas;
// your event listener function
function listener (event) {
var rect = svgcanvas.getBBox(event.target);
var x1 = rect.x;
var y = rect.y;
...
}
No need to handle zooming; the SvgCanvas instance does that for you.

Snap SVG: Dragging group doesn't update elements

JSFiddle here: JSFiddle
When dragging a group of objects, the individual objects' location attributes don't seem to be getting updated. This occurs whether I use the default drag() handler or define my own. Even the group BBox operation doesn't seem to update. Code:
var s = Snap("#svg");
var move = function (dx, dy, posx, posy) {
this.attr({
x: posx,
y: posy
});
//this.transform("t" + dx + "," + dy);
};
var block = s.rect(100, 100, 100, 100);
var circle = s.circle(100, 100, 50);
var group = s.g(block, circle);
//group.drag(move, function () {}, function () {});
group.drag();
//block.drag(move, function () {}, function () {});
//just a way to keep info coming w/o an interminable script
document.addEventListener('mousemove', function (e) {
bbox = block.getBBox();
block_x = block.attr("x");
block_y = block.attr("y");
gbbox = group.getBBox();
console.log("block is at " + block_x + "," + block_y,
" Block Bbbox is at " + bbox.x + "," + bbox.y,
" Group Bbbox is at " + gbbox.x + "," + gbbox.y);
}, false);
If I define only one object (say, a rect) and leave it out of a group, and pass my own "move" function to the call to drag, and include setting the "x" and "y" attributes explicitly, then that works. But if I include the rect in a group, then...I can't figure out how to do it, and I've tried a few ways (see the multiple commented-out lines showing things I've tried). I need to know where the rect sub-group element ends up after the drag, or at least the BBox of the whole group. Neither of these seem to be getting updated -- i.e. the console log I put in shows the same numbers forever, no matter where I move the object(s).
Can anyone help?
JSFiddle here: JSFiddle
I think this is because they are two different things, so they aren't actually interchangable.
The drag handler uses transforms. A transform doesn't affect any other attributes, its just an attribute on an element (in this case the group element).
getBBox will work in its current transform space, note this may be different to the clients (eg if the svg were zoomed in/out). So they are two slightly different methods, that do different things.
Use getBoundingClientRect if you need a bounding box relative to the client window. Use getBBox if you need a bounding box in the elements current coordinate space.
Code is using snap.svg.zpd as well, so zoom is possible. Problem is at onStopMove function. Events are fired when group is moved arround. In group is one circle(this.select('#main-inner-circle')) which does not have predefined location inside group. Im trying to get correct cx and cy of that inner circle after moving group.
self.onMove = function (dx, dy, ev, x, y) {
var clientX, clientY;
var tdx, tdy;
if ((typeof dx == 'object') && (dx.type == 'touchmove')) {
clientX = dx.changedTouches[0].clientX;
clientY = dx.changedTouches[0].clientY;
dx = clientX - this.data('ox');
dy = clientY - this.data('oy');
}
var snapInvMatrix = this.transform().diffMatrix.invert();
snapInvMatrix.e = snapInvMatrix.f = 0;
tdx = snapInvMatrix.x(dx, dy);
tdy = snapInvMatrix.y(dx, dy);
this.transform("t" + [tdx, tdy] + this.data('ot'));
}
self.onStartMove = function (x, y, ev) {
if ((typeof x == 'object') && (x.type == 'touchstart')) {
x.preventDefault();
this.data('ox', x.changedTouches[0].clientX);
this.data('oy', x.changedTouches[0].clientY);
}
this.data('ot', this.transform().local);
if (callbacks.onStartMove) {
callbacks.onStartMove();
}
}
self.onStopMove = function () {
var self = this.select('#main-inner-circle');
this.data('ot', this.transform().local);
//self.data('ot', self.transform().local);
console.log(self.getTransformedBBox());
console.log(this.getBBox());
//console.log($(self.node).offset().left - $(self.node).parent().offset().left);
var bBox = this.getBBox();
//var x = bBox.x + $(self.node).offset().left - $(self.node).parent().offset().left + self.getBBox().width / 2;
//var y = bBox.y + $(self.node).offset().top - $(self.node).parent().offset().top + self.getBBox().height / 2;
model.updateElementCoordinates(index, $(this.node).attr("rel"), { x: self.getTransformedBBox().cx, y: self.getTransformedBBox().cy });
if (callbacks.onStopMove) {
callbacks.onStopMove();
}
}
In order to post this question, I'd created the JSFiddle but left out the crucial snap.svg definitions...
<script src="http://snapsvg.io/assets/js/snap.svg-min.js"></script>
...with that, then indeed the group.getBBox() method actually works. However:
Apparently, using getBBox() is incredibly slow -- much slower than just accessing a "x" attribute of something like I was doing before grouping objects. All I know is that my code slows to a crawl if I use getBBox() (I have a lot of objects on the screen).
Further down in the same post mentioned earier ["Get coordinates of svg group on drag with snap.svg"1 recommended getBoundingClientRect(), which also works fine AND is fast enough! My new, working Fiddle showing all of these methods is here: New JSFiddle.
So, future users: use .node.getBoundingClientRect().

HTML5 canvas rectangles using easeljs

I am creating a multiple choice quiz on a canvas.
Naturally for the options I used squares as checkBoxes. Now I have put an event Listener on clicking a checkbox, it should get colored. However the listener doesnt work on entire square only the border. May I know how can the problem be resolved and also I wanted to know how to know if a square is filled with a color.
Function for loading options with oIndex from 0,1, till numberOfOptions
pHeight is a a global variable, optionChecks- the checkbox and optionsClick- the invisible rectangle for clicking on
function loadOption(oIndex){
optionChecks[oIndex] = new createjs.Shape();
optionChecks[oIndex].graphics.beginStroke("blue");
optionChecks[oIndex].graphics.setStrokeStyle(2);
optionChecks[oIndex].graphics.drawRect( canvas2.width*0.05 ,pHeight+20 ,20 ,20);
stage.addChild(optionChecks[oIndex] );
stage.update();
var y1 = pHeight+15;
var ht = y1;
var maxWidth = canvas2.width *0.8;
var text = problemOptions[oIndex];
var lineHeight = 25;
var x = (canvas2.width - maxWidth) / 2;
var y = y1;//pHeight+15;
//function for wrapping text
wrapText(ctx2, text, x, y, maxWidth, lineHeight);
ht = wHeight +10;
stage.update();
optionClicks[oIndex] = new createjs.Shape();
optionClicks[oIndex].graphics.beginStroke("black");
optionClicks[oIndex].graphics.setStrokeStyle(2);
optionClicks[oIndex].graphics.drawRect( canvas2.width*0.05,y1,maxWidth-500 ,pHeight-y1+10);
optionClicks[oIndex].addEventListener("click", handleOption);
stage.addChild(optionClicks[oIndex] );
}
Thanks in advance.
You could draw another opaque rect and use the button's hitArea - http://createjs.com/Docs/EaselJS/classes/DisplayObject.html#property_hitArea

Trying to retrieve Rendered Text Width in Raphael

So I am looking to retrieve the size of a text string in Raphael and I can't seem to do it. Although the documentation says that
.attr('width');
is an option...and I can't set the width either.
Here is a FIDDLE
This is what I have been trying...plus other crude ways (even using Jquery)
var page = Raphael("drawing_board");
// start, move, and up are the drag functions
start = function () {
// storing original coordinates
this.ox = this.attr("x");
this.oy = this.attr("y");
this.attr({opacity: .5});
console.log( this.attr('width') ); //THIS IS WHERE I AM TRYING TO GET THE WIDTH
},
move = function (dx, dy) {
// move will be called with dx and dy
nowX = Math.min(600, this.ox + dx);
nowY = Math.min(400, this.oy + dy);
nowX = Math.max(0, nowX);
nowY = Math.max(0, nowY);
this.attr({x: nowX, y: nowY });
},
up = function () {
// restoring state
this.attr({opacity: 1});
};
page.text(200, 50, "TEXT 1").attr({ cursor: "move", 'font-size': 16 , fill: '#3D6AA2'}).drag(move, start, up);
page.text(200, 200, "TEXT 2").attr({ cursor: "move", 'font-size': 16 , fill: '#3D6AA2'}).drag(move, start, up);
Maybe I need to use something other than
this.attr('width' : 30); //To Set
this.attr('width'); //To Get
You can use:
this.node.getBBox().width
this.node -> gets the SVG element associated with the Raphael element
getBBox() -> bounding box
You can also use Raphael's getBBox method directly:
this.getBBox().width
Your approach doesn't work because the svg text element doesn't have a width attribute.
this.getBBox() is the RaphaelJS method to get the computed bbox thus returning an object with x y x1 x2 width and height properties. It's as cross browser as Raphaeljs is.
SVG Text elements doesn't have the width attribute. Check it on the w3c SVG specification: http://www.w3.org/TR/SVG/text.html#TextElement There's no width on the attributes list, so you can't set it.
But we could get the width of the DOM element with jQuery. It can be done first retrieving the DOM element reference and passing it to the jQuery constructor, then using the width() function. Here's the updated fiddle: http://jsfiddle.net/Rmegm/8/

Transforming to bound box with Raphael.js

I am in need of some math help. I am trying to dynamically transform my Raphael set of elements to a given bound box within my canvas.
For example, say my canvas (paper) is 600 x 300 and is filled with paths. These paths are all in a set.
Now I want fill my canvas with a given bound box. The bound box is in pixel coordinates. e.g. [[50,10], [100,20]]
So the end result would be a function call that would zoom and position the SVG elements. This would cause the canvas to be cropped to the coordinate bounds.
var bbox = [[50,10], [100,20]]
animateToBoundBox(set, bbox, duration);
function animateToBoundBox(set, bbox, duration) { /* beautiful code */ }
I think the way to accomplish this would be by using the element matrix but I'm not sure. What do you think the most elegant way of handling this would be?
Thanks
The other answers are correct -- you want to use setViewBox.
Here's a version that supports animation. It's not entirely beautiful and you'll have to look at the page source to extract the code, but it should do more or less exactly what you want.
Here's the view box animation as a Raphael extension:
Raphael.fn.animateViewBox = function animateViewBox( x, y, w, h, duration, easing_function, callback )
{
var cx = this._viewBox ? this._viewBox[0] : 0,
dx = x - cx,
cy = this._viewBox ? this._viewBox[1] : 0,
dy = y - cy,
cw = this._viewBox ? this._viewBox[2] : this.width,
dw = w - cw,
ch = this._viewBox ? this._viewBox[3] : this.height,
dh = h - ch,
self = this;;
easing_function = easing_function || "linear";
var interval = 25;
var steps = duration / interval;
var current_step = 0;
var easing_formula = Raphael.easing_formulas[easing_function];
var intervalID = setInterval( function()
{
var ratio = current_step / steps;
self.setViewBox( cx + dx * easing_formula( ratio ),
cy + dy * easing_formula( ratio ),
cw + dw * easing_formula( ratio ),
ch + dh * easing_formula( ratio ), false );
if ( current_step++ >= steps )
{
clearInterval( intervalID );
callback && callback();
}
}, interval );
}
And the (not so beautiful) demonstration is here: http://voidblossom.com/tests/easedViewBox.php
If you're really bent on using transform (which could have a few benefits if leveraged well, but will in general be fragile compared to viewbox manipulation), there's another example using transform located at http://voidblossom.com/tests/zoomByTransform.php.
Not sure if I completely understand what you are looking for, but it sounds like you want to zoom the view to a specific bounding box. Have you looked at the setViewBox function? Basically your function would call it like this:
setViewBox(bbox[0][0], bbox[0][1], bbox[1][0] - bbox[0][1], bbox[1][1] - bbox[0][0])
From what I can tell, everything you want to accomplish would be better handled with Paper.setViewBox() in an animation. See http://raphaeljs.com/reference.html#Paper.setViewBox

Categories