Canvas Vertical Wave - javascript

I have this canvas have made in horizontal. But what I want to achive is a vertical wave. I tried to change the values from x to y but unfortunately that didn't work.
First thing I want to make it vertically. And after I achive that I want to make a square like this. But one step at a time.
On local I made the wave vertically but the mouse movement from this function didn't work.
function onMouseMove(event) {
var mouseX = event.clientX;
var mouseY = event.clientY;
var xPart;
if(Math.abs(_halfStageHeight - mouseY) < _colRadius) {
if(_allowHitBool){
_mouseYSpeed = mouseY - _oldMouseY;
xPart = Math.floor(mouseX/_particleDistNum);
_particleArray[xPart].yVel = _mouseYSpeed/2;
_allowHitBool = false;
setTimeout(function() {
_allowHitBool = true;
}, 100);
}
}
_oldMouseX = mouseX;
_oldMouseY = mouseY;
}
This is the horizontal wave. jsFiddle
Thank you

You could use transformations to rotate the canvas 90 degrees to vertical:
function init() {
var stage = document.getElementById('stage');
_stageWidth = stage.width = window.innerWidth;
_stageHeight = stage.height = window.innerHeight;
_halfStageHeight = _stageHeight/2;
_stageContext = stage.getContext('2d');
_stageContext.fillStyle = "#fff";
_particleDistNum = _stageWidth/(_totalParticles-1);
createParticles();
// rotate the canvas 90 degrees to vertical
_stageContext.translate(stage.width/2,stage.height/2);
_stageContext.rotate(Math.PI/2);
_stageContext.translate(-stage.width/2,-stage.height/2);
}

Related

Fabric JS getContext('2d') not matching getImageData color

Website: http://minimedit.com/
Currently implementing an eye dropper. It works fine in my normal resolution of 1080p, but when testing on a higher or lower resolution it doesn't work.
This is the basics of the code:
var ctx = canvas.getContext("2d");
canvas.on('mouse:down', function(e) {
var newColor = dropColor(e, ctx);
}
function dropColor(e, ctx) {
var mouse = canvas.getPointer(e.e),
x = parseInt(mouse.x),
y = parseInt(mouse.y),
px = ctx.getImageData(x, y, 1, 1).data;
return rgb2hex('rgba('+px+')');
}
When I first initiate the canvas I have it resize to fit resolution:
setResolution(16/9);
function setResolution(ratio) {
var conWidth = ($(".c-container").css('width')).replace(/\D/g,'');
var conHeight = ($(".c-container").css('height')).replace(/\D/g,'');
var tempWidth = 0;
var tempHeight = 0;
tempHeight = conWidth / ratio;
tempWidth = conHeight * ratio;
if (tempHeight > conHeight) {
canvas.setWidth(tempWidth);
canvas.setHeight(conHeight);
} else {
canvas.setWidth(conWidth);
canvas.setHeight(tempHeight);
}
}
The x and y mouse coordinates work fine when zoomed in, but they don't line up with the returned image data. It seems as though the ctx isn't changing it's width and height and scaling along with the actual canvas size.
The canvas element is showing the correct width and height before using getContext as well.
Any ideas on a solution?
Feel free to check out the full scripts on the live website at: http://minimedit.com/
Try "fabric.devicePixelRatio" for calculating actual position, for example:
x = parseInt(mouse.x) * fabric.devicePixelRatio

Image in canvas leaves a tiled trail when panned

I am trying to create a pannable image viewer which also allows magnification. If the zoom factor or the image size is such that the image no longer paints over the entire canvas then I wish to have the area of the canvas which does not contain the image painted with a specified background color.
My current implementation allows for zooming and panning but with the unwanted effect that the image leaves a tiled trail after it during a pan operation (much like the cards in windows Solitaire when you win a game). How do I clean up my canvas such that the image does not leave a trail and my background rectangle properly renders in my canvas?
To recreate the unwanted effect set magnification to some level at which you see the dark gray background show and then pan the image with the mouse (mouse down and drag).
Code snippet added below and Plnkr link for those who wish to muck about there.
http://plnkr.co/edit/Cl4T4d13AgPpaDFzhsq1
<!DOCTYPE html>
<html>
<head>
<style>
canvas{
border:solid 5px #333;
}
</style>
</head>
<body>
<button onclick="changeScale(0.10)">+</button>
<button onclick="changeScale(-0.10)">-</button>
<div id="container">
<canvas width="700" height="500" id ="canvas1"></canvas>
</div>
<script>
var canvas = document.getElementById('canvas1');
var context = canvas.getContext("2d");
var imageDimensions ={width:0,height:0};
var photo = new Image();
var isDown = false;
var startCoords = [];
var last = [0, 0];
var windowWidth = canvas.width;
var windowHeight = canvas.height;
var scale=1;
photo.addEventListener('load', eventPhotoLoaded , false);
photo.src = "http://www.html5rocks.com/static/images/cors_server_flowchart.png";
function eventPhotoLoaded(e) {
imageDimensions.width = photo.width;
imageDimensions.height = photo.height;
drawScreen();
}
function changeScale(delta){
scale += delta;
drawScreen();
}
function drawScreen(){
context.fillRect(0,0, windowWidth, windowHeight);
context.fillStyle="#333333";
context.drawImage(photo,0,0,imageDimensions.width*scale,imageDimensions.height*scale);
}
canvas.onmousedown = function(e) {
isDown = true;
startCoords = [
e.offsetX - last[0],
e.offsetY - last[1]
];
};
canvas.onmouseup = function(e) {
isDown = false;
last = [
e.offsetX - startCoords[0], // set last coordinates
e.offsetY - startCoords[1]
];
};
canvas.onmousemove = function(e)
{
if(!isDown) return;
var x = e.offsetX;
var y = e.offsetY;
context.setTransform(1, 0, 0, 1,
x - startCoords[0], y - startCoords[1]);
drawScreen();
}
</script>
</body>
</html>
You need to reset the transform.
Add context.setTransform(1,0,0,1,0,0); just before you clear the canvas and that will fix your problem. It sets the current transform to the default value. Then befor the image is draw set the transform for the image.
UPDATE:
When interacting with user input such as mouse or touch events it should be handled independently of rendering. The rendering will fire only once per frame and make visual changes for any mouse changes that happened during the previous refresh interval. No rendering is done if not needed.
Dont use save and restore if you don't need to.
var canvas = document.getElementById('canvas1');
var ctx = canvas.getContext("2d");
var photo = new Image();
var mouse = {}
mouse.lastY = mouse.lastX = mouse.y = mouse.x = 0;
mouse.down = false;
var changed = true;
var scale = 1;
var imageX = 0;
var imageY = 0;
photo.src = "http://www.html5rocks.com/static/images/cors_server_flowchart.png";
function changeScale(delta){
scale += delta;
changed = true;
}
// Turns mouse button of when moving out to prevent mouse button locking if you have other mouse event handlers.
function mouseEvents(event){ // do it all in one function
if(event.type === "mouseup" || event.type === "mouseout"){
mouse.down = false;
changed = true;
}else
if(event.type === "mousedown"){
mouse.down = true;
}
mouse.x = event.offsetX;
mouse.y = event.offsetY;
if(mouse.down) {
changed = true;
}
}
canvas.addEventListener("mousemove",mouseEvents);
canvas.addEventListener("mouseup",mouseEvents);
canvas.addEventListener("mouseout",mouseEvents);
canvas.addEventListener("mousedown",mouseEvents);
function update(){
requestAnimationFrame(update);
if(photo.complete && changed){
ctx.setTransform(1,0,0,1,0,0);
ctx.fillStyle="#333";
ctx.fillRect(0,0, canvas.width, canvas.height);
if(mouse.down){
imageX += mouse.x - mouse.lastX;
imageY += mouse.y - mouse.lastY;
}
ctx.setTransform(scale, 0, 0, scale, imageX,imageY);
ctx.drawImage(photo,0,0);
changed = false;
}
mouse.lastX = mouse.x
mouse.lastY = mouse.y
}
requestAnimationFrame(update);
canvas{
border:solid 5px #333;
}
<button onclick="changeScale(0.10)">+</button><button onclick="changeScale(-0.10)">-</button>
<canvas width="700" height="500" id ="canvas1"></canvas>
Nice Code ;)
You are seeing the 'tiled' effect in your demonstration because you are painting the scaled image to the canvas on top of itself each time the drawScreen() function is called while dragging. You can rectify this in two simple steps.
First, you need to clear the canvas between calls to drawScreen() and second, you need to use the canvas context.save() and context.restore() methods to cleanly reset the canvas transform matrix between calls to drawScreen().
Given your code as is stands:
Create a function to clear the canvas. e.g.
function clearCanvas() {
context.clearRect(0, 0, canvas.width, canvas.height);
}
In the canavs.onmousemove() function, call clearCanvas() and invoke context.save() before redefining the transform matrix...
canvas.onmousemove = function(e) {
if(!isDown) return;
var x = e.offsetX;
var y = e.offsetY;
/* !!! */
clearCanvas();
context.save();
context.setTransform(
1, 0, 0, 1,
x - startCoords[0], y - startCoords[1]
);
drawScreen();
}
... then conditionally invoke context.restore() at the end of drawScreen() ...
function drawScreen() {
context.fillRect(0,0, windowWidth, windowHeight);
context.fillStyle="#333333";
context.drawImage(photo,0,0,imageDimensions.width*scale,imageDimensions.height*scale);
/* !!! */
if (isDown) context.restore();
}
Additionally, you may want to call clearCanvas() before rescaling the image, and the canvas background could be styled with CSS rather than .fillRect() (in drawScreen()) - which could give a performance gain on low spec devices.
Edited in light of comments from Blindman67 below
See Also
Canvas.context.save : https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save
Canvas.context.restore : https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/restore
requestAnimationFrame : https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame
Paul Irish, requestAnimationFrame polyfill : http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
Call context.save to save the transformation matrix before you call context.fillRect.
Then whenever you need to draw your image, call context.restore to restore the matrix.
For example:
function drawScreen(){
context.save();
context.fillStyle="#333333";
context.fillRect(0,0, windowWidth, windowHeight);
context.restore();
context.drawImage(photo,0,0,imageDimensions.width*scale,imageDimensions.height*scale);
}
Also, to further optimize, you only need to set fillStyle once until you change the size of canvas.

HTML5 canvas zoom my drawings

Hello i create program like a paint on HTML5 canvas. I have problem i need create few tools drawing and zoom. I don't have idea how to create zoom without delay. Drawing example: http://jsfiddle.net/x5rrvcr0/
How i can zooming my drawings?
drawing code:
<style>
canvas {
background-color: #CECECE;
}
html, body {
background-color: #FFFFFF;
}
</style>
<script>
$(document).ready(function () {
var paintCanvas = document.getElementById("paintCanvas");
var paintCtx = paintCanvas.getContext("2d");
var size = 500;
paintCanvas.width = size;
paintCanvas.height = size;
var draw = false;
var prevMouseX = 0;
var prevMouseY = 0;
function getMousePos(canvas, evt) {
evt = evt.originalEvent || window.event || evt;
var rect = canvas.getBoundingClientRect();
if (evt.clientX !== undefined && evt.clientY !== undefined) {
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
}
$("#paintCanvas").on("mousedown", function(e) {
draw = true;
var coords = getMousePos(paintCanvas);
prevMouseX = coords.x;
prevMouseY = coords.y;
});
$("#paintCanvas").on("mousemove", function(e) {
if(draw) {
var coords = getMousePos(paintCanvas, e);
paintCtx.beginPath();
paintCtx.lineWidth = 10;
paintCtx.strokeStyle = "#000000";
paintCtx.moveTo(prevMouseX, prevMouseY);
paintCtx.lineTo(coords.x, coords.y);
paintCtx.stroke();
prevMouseX = coords.x;
prevMouseY = coords.y;
}
});
$("#paintCanvas").on("mouseup", function(e) {
draw = false;
});
});
</script>
<body>
<canvas id="paintCanvas"></canvas>
</body>
If you want to keep the pixelated effect in the zoom, you need to draw on a temp canvas, then only after copy that temp canvas to the main screen.
You no longer need to zoom in the temp canvas, just draw on 1:1 scale always. When copying to the view canvas, then you apply the zoom (and maybe translate) that you want.
Keep in mind that drawings are anti-aliased, so you when zooming you will see some shades of grey when drawing in black, for instance.
I kept the recording code of #FurqanZafar since it is a good idea to record things in case you want to perform undo : in that case just delete the last record entry and redraw everything.
http://jsfiddle.net/gamealchemist/x5rrvcr0/4/
function updatePaintCanvas() {
paintContext.clearRect(0, 0, paintContext.canvas.width, paintContext.canvas.height);
paintContext.save();
paintContext.translate(cvSize * 0.5, cvSize * 0.5);
paintContext.scale(scale, scale);
paintContext.drawImage(drawCanvas, -cvSize * 0.5, -cvSize * 0.5);
paintContext.restore();
}
Heres the updated fiddle: http://jsfiddle.net/x5rrvcr0/2/ with basic zooming functionality
If you draw multiple paths on mouse move then your sketch will appear broken or disconnected, instead you should only stroke a single path until "mouseup" event.
You can then store these paths in an array and later redraw them at different zoom levels:
function zoom(context, paths, styles, scale) {
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
context.save();
applyStyles(context, styles);
scaleFromCenter(context, scale);
for (var i = 0; i < paths.length; i++) {
context.beginPath();
context.moveTo(paths[i][0].x, paths[i][0].y);
for (var j = 1; j < paths[i].length; j++)
context.lineTo(paths[i][j].x, paths[i][j].y);
context.stroke();
}
context.restore();
};

RaphealJS Resize and mouse shift

I have been using RaphealJS to create a vector drawing tool, I have all the drawing completed and working
my issues comes in when I resize the browser window and try to draw the mouse pointer is off from the location that is being drawn.
I use the mouse move event on the browser and draw lines , Like so
$(document).mousemove(function(e){
if (IE) {
var dh = $("#details").height();
var dw = $("#details").width();
xx = e.offsetX;
yy = e.offsetY;
} else {
var offset = $("#workcanvas").offset();
xx = e.pageX - offset.left;
yy = e.pageY - offset.top;
}
if (lineObject != null) {
lineObject.updateEnd(xx, yy);
} else {
lineObject = Line(xx, yy, xx, yy, MasterCanvas);
}
});
I create my canvas and background image
var MasterCanvas = Raphael($("#workcanvas").attr("id"));
var MasterBGImage = MasterCanvas.image(imgPath, 0, 0, $("#workcanvas").width(),$("#workcanvas").height());
MasterCanvas.setViewBox(0, 0, $("#workcanvas").width(), $("#workcanvas").height(), true);
and in my window resize event I tried this
MasterCanvas.setSize($("#workcanvas").width(), $("#workcanvas").height());
Now I have beat my head against this for a few days to no avail. Please note: I can the drawing function work, and as long as the window does not resize every thing is great but when the page resizes the drawing point is off.
Just in case anyone else has this problem, it turns out to be a viewBox problem, I had to calculate the mouse position based on the viewBox coordinates not the screen so my original code becomes:
$(document).mousemove(function(e){
var uupos = MasterCanvas.canvas.createSVGPoint();
uupos.x = e.clientX;
uupos.y = e.clientY;
var ctm = MasterCanvas.canvas.getScreenCTM();
if (ctm = ctm.inverse())
uupos = uupos.matrixTransform(ctm);
x = uupos.x;
y = uupos.y;
if (lineObject != null) {
lineObject.updateEnd(x, y);
} else {
lineObject = Line(x, y, x, y, MasterCanvas);
}
});
Edit:
Looks like this solution is SVG only though and it does not work in IE8 which is a requirement for me - any ideas.
Is there something like viewBox coordinates in VML

Implement dragging an image within a canvas

I want to implement dragging of an image within a canvas. I want simplest code for that. So far I have seen a lot of examples but they have used complex ways of implementation. I want an example that is easy to learn and implement.
It's pretty difficult. You'll first need to write a function that can detect when you click a particular element. However, before we can do that, we must define what we mean by "element". Is it the product of a single draw instruction (e.g. a rectangle or arc), or something complex? (Imagine I wanted to draw a cat and make the entire cat draggable as a unit.)
A canvas is nothing but a collection of pixels. If you want your program to have an idea of "shapes" or even "collections of shapes treated as a unit" you'll need to implement them yourself as data structures external to the canvas itself. Once you have that, you can write an onmousedown handler that takes the x/y point clicked and determine what shape (if any) the click falls inside of (and if it falls inside of multiple shapes, check which has the foremost z-index). Then add an onmousemove handler that erases and redraws the shape on the canvas based on the information in the shape data object.
This is a moderately difficult problem with very difficult prerequisite problems (creating data structures that can describe a wide range of shapes as well as collections of shapes). I highly recommend you use a canvas drawing library that has already solved these problems. I use cake.js but there are loads of options available.
If you don't have to use the HTML5 canvas, jQuery UI is a lot simpler:
HTML:
<img class="drag-me" src="http://www.google.com/images/srpr/logo3w.png">​
JavaScript:
$(function() {
$('.drag-me').draggable();
});
​
See it in action:
http://jsfiddle.net/flackend/TQzSe/
The jQuery UI API has a lot of options too to make it act how you want:
http://jqueryui.com/demos/draggable/
Plus, if it doesn't do what you need, it's easy to implement yourself. Post here if you need help with that.
jsfiddle.net/Zevan/QZejF/5 This may help you.
<html>
<head>
<title>Test Page</title>
<script type="text/javascript" src="jquery.js"></script>
</head>
<body>
<canvas id="c" width = "500" height = "500" ></canvas>
<script type="text/javascript">
var canvas = $("#c");
var c = canvas[0].getContext("2d");
//var path = "http://wonderfl.net/images/icon/e/ec/ec3c/ec3c37ba9594a7b47f1126b2561efd35df2251bfm";
var path = "blue.jpg";
var path2 = "purple.jpg";
var image1 = new DragImage(path, 200, 100);
var image2 = new DragImage(path2, 300, 100);
var loop = setInterval(function() {
c.fillStyle = "gray";
c.fillRect(0, 0, 500, 500);
image1.update();
image2.update();
}, 30);
var mouseX = 0,
mouseY = 0;
var mousePressed = false;
var dragging = false;
canvas.mousemove(function(e) {
mouseX = e.offsetX;
mouseY = e.offsetY;
})
$(document).mousedown(function() {
mousePressed = true;
}).mouseup(function() {
mousePressed = false;
dragging = false;
});
function DragImage(src, x, y) {
var that = this;
var startX = 0,
startY = 0;
var drag = false;
this.x = x;
this.y = y;
var img = new Image();
img.src = src;
this.update = function() {
if (mousePressed ) {
var left = that.x;
var right = that.x + img.width;
var top = that.y;
var bottom = that.y + img.height;
if (!drag) {
startX = mouseX - that.x;
startY = mouseY - that.y;
}
if (mouseX < right && mouseX > left && mouseY < bottom && mouseY > top) {
if (!dragging){
dragging = true;
drag = true;
}
}
} else {
drag = false;
}
if (drag) {
that.x = mouseX - startX;
that.y = mouseY - startY;
}
c.drawImage(img, that.x, that.y);
}
}
</script>
</body>
</html>

Categories

Resources