Save Data from Freehand Drawing (not as an image file) - javascript

I have been trying to save data/object from HTML5 Canvas' drawing feature, how would I save to mySQL table by x and y coordinate points, instead of converting it into a JPEG or an image file?.
The goal is to save the strokes as data file instead of image file. How can I do this?
var canvas = document.getElementById('canvas'),
coord = document.getElementById('coord'),
ctx = canvas.getContext('2d'), // get 2D context
imgCat = new Image();
/*********** draw image *************/
imgCat.src = 'http://c.wearehugh.com/dih5/openclipart.org_media_files_johnny_automatic_1360.png';
imgCat.onload = function() { // wait for image load
ctx.drawImage(imgCat, 0, 0); // draw imgCat on (0, 0)
};
/*********** handle mouse events on canvas **************/
var mousedown = false;
ctx.strokeStyle = '#0000FF';
ctx.lineWidth = 2;
canvas.onmousedown = function(e) {
var pos = fixPosition(e, canvas);
mousedown = true;
ctx.beginPath();
ctx.moveTo(pos.x, pos.y);
return false;
};
canvas.onmousemove = function(e) {
var pos = fixPosition(e, canvas);
coord.innerHTML = '(' + pos.x + ',' + pos.y + ')';
if (mousedown) {
ctx.lineTo(pos.x, pos.y);
ctx.stroke();
}
};
canvas.onmouseup = function(e) {
mousedown = false;
};
/********** utils ******************/
// Thanks to http://stackoverflow.com/questions/55677/how-do-i-get-the-coordinates-of-a-mouse-click-on-a-canvas-element/4430498#4430498
function fixPosition(e, gCanvasElement) {
var x;
var y;
if (e.pageX || e.pageY) {
x = e.pageX;
y = e.pageY;
} else {
x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
x -= gCanvasElement.offsetLeft;
y -= gCanvasElement.offsetTop;
return {
x: x,
y: y
};
}
``
<div id="left_col">
<canvas id="canvas" width="900" height="900" style='background-image:url(http://www.robertshadbolt.com/content/01-articles/01-900x900/900x900.gif);' center cetner no-repeat></canvas>
<div id="coord" hidden></div>
Fiddle

Canvas cannot handle vector graphics in the sense it will rasterize anything drawn to it. Therefor canvas will only provide you with bitmaps (raw or encoded as an image). The canvas can only show the result of those vectors being rasterized, but can never provide them in raw form afterwards.
To obtain the effect of dealing with vectors you need to do the following:
Track and collect the points in a serializeable format such as an array with literal objects. In other words: you need to "record" these points in your mouse handlers parallel to rendering them to canvas.
You will also need to separate "strokes" (a stroke is from mouse down to mouse up, then create a new array for the next stroke etc. meaning you will need an object with two levels, one to collect stroke arrays, and one array per stroke).
When done you can serialize the array using JSON.stringify() and send to your database.
To restore, read that string back and use JSON.parse() to restore the array.
Simplified Example
// some dummy point in a serializeable format:
var points = [
{x: 10, y: 10},
{x: 20, y: 50},
{x: 100, y: 10}
];
// serialize
var str = JSON.stringify(points);
document.write("To server: " + str + "<br>");
// send str to database here...
// RESTORE
// read from database here
var restoredPoints = JSON.parse(str);
document.write("Point from restored array - x: " +
restoredPoints[1].x + " y: " +
restoredPoints[1].y);
In a more real example your object would look like (pseudo code):
var strokes = [];
onmousedown:
create new array -> strokes.push([]);
index = strokes.length - 1;
add point to current stroke -> strokes[index].push({x:x, y:y});
onmousemove:
add point to current stroke -> strokes[index].push({x:x, y:y});

Related

Convert mouse position to Canvas Coordinates and back

I'm creating a canvas with an overlay div to add markers on click and I want markers to change position when I pan zoom the canvas or resize the window. I'm using https://github.com/timmywil/panzoom to pan zoom.
The problem is when I convert mouse position to canvas coordinates it worked correctly but when I convert it back to screen position to render markers on overlay div, the result is not as same as initialized mouse position and recalculate marker's position on resize also not correct.
This canvas is fullscreen with no scroll.
width = 823; height = 411;
scale = 2; panX = 60; panY = 10;
mouse.pageX = 467; mouse.pageY = 144;
// {x: 475, y: 184} correct coords when I use ctx.drawImage(..) to test
canvasCoords = getCanvasCoords(mouse.pageX, mouse.pageY, scale);
// {x: 417, y: 124}
screenCoords = toScreenCoords(canvasCoords.x, canvasCoords.y, scale, panX, panY);
------------------------------
but with scale = 1; it worked correctly.
// convert mouse position to canvas coordinates
getCanvasCoords(pageX: number, pageY: number, scale: number) {
var rect = this.pdfInfo.canvas.getBoundingClientRect();
let x = (pageX - rect.left + this.scrollElement.scrollTop) / scale;
let y = (pageY - rect.top + this.scrollElement.scrollLeft) / scale;
return {
x: Number.parseInt(x.toFixed(0)),
y: Number.parseInt(y.toFixed(0)),
};
}
// convert canvas coords to screen coords
toScreenCoords(
x: number,
y: number,
scale: number
) {
var rect = this.pdfInfo.canvas.getBoundingClientRect();
let wx =
x * scale + rect.left - this.scrollElement.scrollTop / scale;
let wy =
y * scale + rect.top - this.scrollElement.scrollLeft / scale;
return {
x: Number.parseInt(wx.toFixed(0)),
y: Number.parseInt(wy.toFixed(0)),
};
}
getNewPos(x, oldV, newV) {
return (x * oldV) / newV;
}
// update screen coords with new screen width and height
onResize(old, new) {
this.screenCoordList.forEach(el => {
el.x = getNewPos(el.x, old.width, new.width);
el.y = getNewPos(el.y, old.height, new.height);
})
}
How to get it worked with scale and pan? if you know any library can do the job please recommend, thank you.
Here's a code snippet that seems to be working, you can probably adapt it for your purposes.
What I used was:
function toCanvasCoords(pageX, pageY, scale) {
var rect = canvas.getBoundingClientRect();
let x = (pageX - rect.left) / scale;
let y = (pageY - rect.top) / scale;
return toPoint(x, y);
}
and
function toScreenCoords(x, y, scale) {
var rect = canvas.getBoundingClientRect();
let wx = x * scale + rect.left + scrollElement.scrollLeft;
let wy = y * scale + rect.top + scrollElement.scrollTop;
return toPoint(wx, wy);
}
I'm just getting the mouse position from the window object. I'm may be mistaken, but I think this is why scrollLeft and scrollTop don't appear in toCanvasCoords (since the position is relative to the client area of the window itself, the scroll doesn't come into it). But then when you transform back, you have to take it into account.
This ultimately just returns the mouse position relative to the window (which was the input), so it's not really necessary to do the whole transformation in a roundabout way if you just want to attach an element to the mouse pointer. But transforming back is useful if you want to have something attached to a certain point on the canvas image (say, a to feature on the map) - which I'm guessing is something that you're going for, since you said that you want to render markers on an overlay div.
In the code snippet bellow, the red circle is drawn on the canvas itself at the location returned by toCanvasCoords; you'll notice that it scales together with the background.
I didn't use an overlay div covering the entire map, I just placed a couple of small divs on top using absolute positioning. The black triangle is a div (#tracker) that basically tracks the mouse; it is placed at the result of toScreenCoords. It serves as a way to check if the transformations work correctly. It's an independent element, so it doesn't scale with the image.
The red triangle is another such div (#feature), and demonstrates the aforementioned "attach to feature" idea. Suppose the background is a something like a map, and suppose you want to attach a "map pin" icon to something on it, like to a particular intersection; you can take that location on the map (which is a fixed value), and pass it to toScreenCoords. In the code snippet below, I've aligned it with a corner of a square on the background, so that you can track it visually as you change scale and/or scroll. (After you click "Run code snippet", you can click "Full page", and then resize the window to get the scroll bars).
Now, depending on what exactly is going on in your code, you may have tweak a few things, but hopefully, this will help you. If you run into problems, make use of console.log and/or place some debug elements on the page that will display values live for you (e.g. mouse position, client rectangle, etc.), so that you can examine values. And take things one step at the time - e.g. first get the scale to work, but ignore scrolling, then try to get scrolling to work, but keep the scale at 1, etc.
const canvas = document.getElementById('canvas');
const context = canvas.getContext("2d");
const tracker = document.getElementById('tracker');
const feature = document.getElementById('feature');
const slider = document.getElementById("scale-slider");
const scaleDisplay = document.getElementById("scale-display");
const scrollElement = document.querySelector('html');
const bgImage = new Image();
bgImage.src = "https://i.stack.imgur.com/yxtqw.jpg"
var bgImageLoaded = false;
bgImage.onload = () => { bgImageLoaded = true; };
var mousePosition = toPoint(0, 0);
var scale = 1;
function updateMousePosition(evt) {
mousePosition = toPoint(evt.clientX, evt.clientY);
}
function getScale(evt) {
scale = evt.target.value;
scaleDisplay.textContent = scale;
}
function toCanvasCoords(pageX, pageY, scale) {
var rect = canvas.getBoundingClientRect();
let x = (pageX - rect.left) / scale;
let y = (pageY - rect.top) / scale;
return toPoint(x, y);
}
function toScreenCoords(x, y, scale) {
var rect = canvas.getBoundingClientRect();
let wx = x * scale + rect.left + scrollElement.scrollLeft;
let wy = y * scale + rect.top + scrollElement.scrollTop;
return toPoint(wx, wy);
}
function toPoint(x, y) {
return { x: x, y: y }
}
function roundPoint(point) {
return {
x: Math.round(point.x),
y: Math.round(point.y)
}
}
function update() {
context.clearRect(0, 0, 500, 500);
context.save();
context.scale(scale, scale);
if (bgImageLoaded)
context.drawImage(bgImage, 0, 0);
const canvasCoords = toCanvasCoords(mousePosition.x, mousePosition.y, scale);
drawTarget(canvasCoords);
const trackerCoords = toScreenCoords(canvasCoords.x, canvasCoords.y, scale);
updateTrackerLocation(trackerCoords);
updateFeatureLocation()
context.restore();
requestAnimationFrame(update);
}
function drawTarget(location) {
context.fillStyle = "rgba(255, 128, 128, 0.8)";
context.beginPath();
context.arc(location.x, location.y, 8.5, 0, 2*Math.PI);
context.fill();
}
function updateTrackerLocation(location) {
const canvasRectangle = offsetRectangle(canvas.getBoundingClientRect(),
scrollElement.scrollLeft, scrollElement.scrollTop);
if (rectContains(canvasRectangle, location)) {
tracker.style.left = location.x + 'px';
tracker.style.top = location.y + 'px';
}
}
function updateFeatureLocation() {
// suppose the background is a map, and suppose there's a feature of interest
// (e.g. a road intersection) that you want to place the #feature div over
// (I roughly aligned it with a corner of a square).
const featureLoc = toScreenCoords(84, 85, scale);
feature.style.left = featureLoc.x + 'px';
feature.style.top = featureLoc.y + 'px';
}
function offsetRectangle(rect, offsetX, offsetY) {
// copying an object via the spread syntax or
// using Object.assign() doesn't work for some reason
const result = JSON.parse(JSON.stringify(rect));
result.left += offsetX;
result.right += offsetX;
result.top += offsetY;
result.bottom += offsetY;
result.x = result.left;
result.y = result.top;
return result;
}
function rectContains(rect, point) {
const inHorizontalRange = rect.left <= point.x && point.x <= rect.right;
const inVerticalRange = rect.top <= point.y && point.y <= rect.bottom;
return inHorizontalRange && inVerticalRange;
}
window.addEventListener('mousemove', (e) => updateMousePosition(e), false);
slider.addEventListener('input', (e) => getScale(e), false);
requestAnimationFrame(update);
#canvas {
border: 1px solid gray;
}
#tracker, #feature {
position: absolute;
left: 0;
top: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-bottom: 10px solid black;
transform: translate(-4px, 0);
}
#feature {
border-bottom: 10px solid red;
}
<div>
<label for="scale-slider">Scale:</label>
<input type="range" id="scale-slider" name="scale-slider" min="0.5" max="2" step="0.02" value="1">
<span id="scale-display">1</span>
</div>
<canvas id="canvas" width="500" height="500"></canvas>
<div id="tracker"></div>
<div id="feature"></div>
P.S. Don't do Number.parseInt(x.toFixed(0)); generally, work with floating point for as long as possible to minimize accumulation of errors, and only convert to int at the last minute. I've included the roundPoint function that rounds the (x, y) coordinates of a point to the nearest integer (via Math.round), but ended up not needing to use it at all.
Note: The image below is used as the background in the code snippet, to serve as a reference point for scaling; it is included here just so that it is hosted on Stack Exchange's imgur.com account, so that the code is not referencing a (potentially volatile) 3rd-pary source.

How to store and restore canvas to use it again?

I am using PDF.js to show PDF in browser. PDF.js uses canvas to render PDF. I have js scripts that draws the lines on the canvas when user double clicks on the canvas. It also adds X check mark to remove the already drawn line.
based on my research i cannot simply just remove the line from the canvas because underneath pixels are gone when you draw something on it. To get it working i have to store lines and then clear canvas and re-load canvas and re-draw lines
Issue
I am not able to store canvas and restore canvas. When i click on X i was able to get lines re-drawn but canvas does not get restored. Canvas remains blank
Run the demo in full page
$(function () {
var $canvas = $("#myCanvas");
var canvasEl = $canvas.get(0);
var ctx = canvasEl.getContext("2d");
var lines = [];
var backupCanvas = document.createElement("canvas");
var loadingTask = pdfjsLib.getDocument('https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf');
loadingTask.promise.then(function (doc) {
console.log("This file has " + doc._pdfInfo.numPages + " pages");
doc.getPage(1).then(page => {
var scale = 1;
var viewPort = page.getViewport(scale);
canvasEl.width = viewPort.width;
canvasEl.height = viewPort.height;
canvasEl.style.width = "100%";
canvasEl.style.height = "100%";
var wrapper = document.getElementById("wrapperDiv");
wrapper.style.width = Math.floor(viewPort.width / scale) + 'px';
wrapper.style.height = Math.floor(viewPort.height / scale) + 'px';
page.render({
canvasContext: ctx,
viewport: viewPort
});
storeCanvas();
});
});
function storeCanvas() {
backupCanvas.width = canvasEl.width;
backupCanvas.height = canvasEl.height;
backupCanvas.ctx = backupCanvas.getContext("2d");
backupCanvas.ctx.drawImage(canvasEl, 0, 0);
}
function restoreCanvas() {
ctx.drawImage(backupCanvas, 0, 0);
}
$canvas.dblclick(function (e) {
var mousePos = getMousePos(canvasEl, e);
var line = { startX: 0, startY: mousePos.Y, endX: canvasEl.width, endY: mousePos.Y, pageY: e.pageY };
lines.push(line);
drawLine(line, lines.length - 1);
});
function drawLine(line, index) {
// draw line
ctx.beginPath();
ctx.strokeStyle = '#df4b26';
ctx.moveTo(line.startX, line.startY);
ctx.lineTo(line.endX, line.endY);
ctx.closePath();
ctx.stroke();
// add remove mark
var top = line.pageY;
var left = canvasEl.width + 20;
var $a = $("<a href='#' class='w-remove-line'>")
.data("line-index", index)
.attr("style", "line-height:0")
.css({ top: top, left: left, position: 'absolute' })
.html("x")
.click(function () {
var index = $(this).data("line-index");
$(".w-remove-line").remove();
ctx.clearRect(0, 0, canvasEl.width, canvasEl.height);
// restore canvas
restoreCanvas();
lines.splice(index, 1);
for (var i = 0; i < lines.length; i++) {
drawLine(lines[i], i);
}
});
$("body").append($a);
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
X: Math.floor(evt.clientX - rect.left),
Y: Math.floor(evt.clientY - rect.top),
};
}
});
canvas {
border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.2.228/pdf.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<b> Double Click on PDF to draw line and then click on X to remove lines</b>
<div id="wrapperDiv">
<canvas id="myCanvas"></canvas>
</div>
The PDF.js render() function is async so you need to store the canvas after the render has finished. Your code is firing storeCanvas() too early and storing a blank canvas. Easy fix, render() returns a promise so ...
page.render({
canvasContext: ctx,
viewport: viewPort
}).then( () => {
storeCanvas();
});
https://jsfiddle.net/fyLant01/1/
Reference: from https://github.com/mozilla/pdf.js/blob/master/src/display/api.js#L998
/**
* Begins the process of rendering a page to the desired context.
* #param {RenderParameters} params Page render parameters.
* #return {RenderTask} An object that contains the promise, which
* is resolved when the page finishes rendering.
*/

Fabric.JS and Fabric-Brush - Can't add to lower canvas

I'm trying to use Fabric.js with Fabric Brush This issue that I'm running into is that Fabric Brush only puts the brush strokes onto the Top Canvas and not the lower canvas. (The stock brushes in fabric.js save to the bottom canvas) I think I need to convert "this.canvas.contextTop.canvas" to an object and add that object to the the lower canvas. Any ideas?
I've tried running:
this.canvas.add(this.canvas.contextTop)
in
onMouseUp: function (pointer) {this.canvas.add(this.canvas.contextTop)}
But I'm getting the error
Uncaught TypeError: obj._set is not a function
So the contextTop is CanvasHTMLElement context. You cannot add it.
You can add to the fabricJS canvas just fabric.Object derived classes.
Look like is not possible for now.
They draw as pixel effect and then they allow you to export as an image.
Would be nice to extend fabricJS brush interface to create redrawable objects.
As of now with fabricJS and that particular version of fabric brush, the only thing you can do is:
var canvas = new fabric.Canvas(document.getElementById('c'))
canvas.freeDrawingBrush = new fabric.CrayonBrush(canvas, {
width: 70,
opacity: 0.6,
color: "#ff0000"
});
canvas.isDrawingMode = true
canvas.on('mouse:up', function(opt) {
if (canvas.isDrawingMode) {
var c = fabric.util.copyCanvasElement(canvas.upperCanvasEl);
var img = new fabric.Image(c);
canvas.contextTopDirty = true;
canvas.add(img);
canvas.isDrawingMode = false;
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.1/fabric.min.js"></script>
<script src="https://tennisonchan.github.io/fabric-brush/bower_components/fabric-brush/dist/fabric-brush.min.js"></script>
<button>Enter free drawing</button>
<canvas id="c" width="500" height="500" ></canvas>
That is just creating an image from the contextTop and add as an object.
I have taken the approach suggested by AndreaBogazzi and modified the Fabric Brush so that it does the transfer from upper to lower canvas (as an image) internal to Fabric Brush. I also used some code I found which crops the image to a smaller bounding box so that is smaller than the full size of the canvas. Each of the brushes in Fabric Brush has an onMouseUp function where the code should be placed. Using the case of the SprayBrush, the original code here was:
onMouseUp: function(pointer) {
},
And it is replaced with this code:
onMouseUp: function(pointer){
function trimbrushandcopytocanvas() {
let ctx = this.canvas.contextTop;
let pixels = ctx.getImageData(0, 0, canvas.upperCanvasEl.width, canvas.upperCanvasEl.height),
l = pixels.data.length,
bound = {
top: null,
left: null,
right: null,
bottom: null
},
x, y;
// Iterate over every pixel to find the highest
// and where it ends on every axis ()
for (let i = 0; i < l; i += 4) {
if (pixels.data[i + 3] !== 0) {
x = (i / 4) % canvas.upperCanvasEl.width;
y = ~~((i / 4) / canvas.upperCanvasEl.width);
if (bound.top === null) {
bound.top = y;
}
if (bound.left === null) {
bound.left = x;
} else if (x < bound.left) {
bound.left = x;
}
if (bound.right === null) {
bound.right = x;
} else if (bound.right < x) {
bound.right = x;
}
if (bound.bottom === null) {
bound.bottom = y;
} else if (bound.bottom < y) {
bound.bottom = y;
}
}
}
// Calculate the height and width of the content
var trimHeight = bound.bottom - bound.top,
trimWidth = bound.right - bound.left,
trimmed = ctx.getImageData(bound.left, bound.top, trimWidth, trimHeight);
// generate a second canvas
var renderer = document.createElement('canvas');
renderer.width = trimWidth;
renderer.height = trimHeight;
// render our ImageData on this canvas
renderer.getContext('2d').putImageData(trimmed, 0, 0);
var img = new fabric.Image(renderer,{
scaleY: 1./fabric.devicePixelRatio,
scaleX: 1./fabric.devicePixelRatio,
left: bound.left/fabric.devicePixelRatio,
top:bound.top/fabric.devicePixelRatio
});
this.canvas.clearContext(ctx);
canvas.add(img);
}
setTimeout(trimbrushandcopytocanvas, this._interval); // added delay because last spray was on delay and may not have finished
},
The setTimeout function was used because Fabric Brush could still be drawing to the upper canvas after the mouseup event occurred, and there were occasions where the brush would continue painting the upper canvas after its context was cleared.

Is it possible to make every line that I draw draggable in Canvas?

This is my Javascript
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
canvas.addEventListener('click', drawLine, false);
var clicks = 0;
var lastClick = [0, 0];
$(function() {
$.each(['#f00', '#ff0', '#0f0', '#0ff', '#00f', '#f0f', '#000', '#fff'], function() {
$('#tools').append("<a href='#' onclick=\"context.strokeStyle = '" + this + "';return false;\" style='width: 10px; background: " + this + ";'></a> ");
});
});
function getCursorPosition(e) {
var x;
var y;
if (e.pageX != undefined && e.pageY != undefined) {
x = e.pageX;
y = e.pageY;
} else {
x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
return [x, y];
}
function drawLine(e) {
//context = this.getContext('2d');
x = getCursorPosition(e)[0] - this.offsetLeft;
y = getCursorPosition(e)[1] - this.offsetTop;
if (clicks != 1) {
clicks++;
} else {
context.beginPath();
context.moveTo(lastClick[0], lastClick[1]);
context.lineTo(x, y, 6);
// context.strokeStyle = '#000000';
context.stroke();
clicks = 0;
}
lastClick = [x, y];
};
This HTML
<div id='tools'>
</div>
<canvas id="canvas" width="500" height="500"></canvas>
I want to generate a new DIV when I finish drawing the line, and make it draggable, how can I do it? I not sure how can contain the line inside the DIV.
The Div should be create when I stop drawing one line.
This is the Jfiddle for a clearer picture
http://jsfiddle.net/pVZzY/1/
I suggest kinetic.js for this task.
Take a look at it http://kineticjs.com/
This will surely make your intended job much easier
Canvas doesn't allow you to alter/move/scale the objects that you've just draw.
Think of it as paper sheet that you color up with pencils, you can't move the pencil line around the only way is to erase the old line and draw a new one - same goes for canvas.
But! There are a bunch of libraries that make working with canvas easier, one of which is http://kineticjs.com/, another one is http://paperjs.org/. I can't claim for kineticjs, but seems it's similar to paper.js in the way that they both create an Object layer.
Briefly speaking - they provide you with API to create and change scene objects (images, lines, shapes) and deal with draw-clear-redraw Canvas concept at the backstage.
fyi, regarding js libs mentioned in other posts, i just checked and:
kineticjs is no longer maintained (3-5 years) but last version is apparently very stable. 3775 stars on github.
paper is still going. > 10,000 stars on github.

Raphael transform object diagonally and infinite setIntervals

I'm working on a small animation where the user drags a circle and the circle returns back to the starting point. I figured out a way to have the circle return to the starting point. The only problem is that it will hit one of the sides of the frame before returning. Is it possible for it to go straight back (follow the path of a line drawn between the shape and starting point).
The other problem is that my setInterval doesn't want to stop. If you try pulling it a second time it would pull it back before you release your mouse. It also seems to speed up after every time. I have tried using a while loop with a timer but the results weren't as good. Is this fixable?
var paper = Raphael(0, 0, 320, 200);
//var path = paper.path("M10 10L40 40").attr({stoke:'#000000'});
//var pathArray = path.attr("path");
var circle = paper.circle(50, 50, 20);
var newX;
var newY;
circle.attr("fill", "#f00");
circle.attr("stroke", "#fff");
var start = function () {
this.attr({cx: 50, cy: 50});
this.cx = this.attr("cx"),
this.cy = this.attr("cy");
},
move = function (dx, dy) {
var X = this.cx + dx,
Y = this.cy + dy;
this.attr({cx: X, cy: Y});
},
up = function () {
setInterval(function () {
if(circle.attr('cx') > 50){
circle.attr({cx : (circle.attr('cx') - 1)});
} else if (circle.attr('cx') < 50){
circle.attr({cx : (circle.attr('cx') + 1)});
}
if(circle.attr('cy') > 50){
circle.attr({cy : (circle.attr('cy') - 1)});
} else if (circle.attr('cy') < 50){
circle.attr({cy : (circle.attr('cy') + 1)});
}
path.attr({path: pathArray});
},2);
};
circle.drag(move, start, up);
Here's the Jfiddle: http://jsfiddle.net/Uznp2/
Thanks alot :D
I modified the "up" function to the one below
up = function () {
//starting x, y of circle to go back to
var interval = 1000;
var startingPointX = 50;
var startingPointY = 50;
var centerX = this.getBBox().x + (this.attr("r")/2);
var centerY = this.getBBox().y + (this.attr("r")/2);
var transX = (centerX - startingPointX) * -1;
var transY = (centerY - startingPointY) * -1;
this.animate({transform: "...T"+transX+", "+transY}, interval);
};
and the "start" function as follows:
var start = function () {
this.cx = this.attr("cx"),
this.cy = this.attr("cy");
}
Is this the behavior you are looking for? Sorry if I misunderstood the question.
If the circle need to get back to its initial position post drag, we can achieve that via simple animation using transform attribute.
// Assuming that (50,50) is the location the circle prior to drag-move (as seen in the code provided)
// The animation is set to execute in 1000 milliseconds, using the easing function of 'easeIn'.
up = function () {
circle.animate({transform: 'T50,50'}, 1000, 'easeIn');
};
Hope this helps.

Categories

Resources