I want to visualize my sorting algorithms and redraw the created Canvas each time. My Old Canvas keeps all the old values. It just creates a new Canvas and puts it above the old Canvas. But I thought with the redraw I could solve it. I also tried to delete the canvas via canvas.remove() and create a completly new one and it also didn't worked out.
My setup call:
let canvas;
function setup() {
values = new Array(20);
this.canvas = createCanvas(values.length*w, 640);
createArray(values.length);
var slider = document.getElementById("slider");
slider.oninput = function() {
this.canvas = resizeCanvas(values.length*w, 640);
length = this.value;
createArray(length);
redraw();
}
var button = document.getElementById("btn");
button.onclick = function(){
quickSort(values, 0, values.length - 1);
}
}
And my draw call:
function draw() {
background(0);
for (let i = 0; i < values.length; i++) {
noStroke();
if (states[i] == 0) {
fill('#E0777D');
} else if (states[i] == 1) {
fill('#D6FFB7');
} else {
fill(255);
}
rect(i * w, height - values[i], w, values[i]);
}
}
Thanks for helping me out :).
Try to do canvas=null when you are done using the canvas
Related
I'm writing a small game with canvas in javascript. For that, I use a update function. You can see it here:
var ctx = canvas.getContext("2d");
//some other code here
function animate() {
window.requestAnimationFrame(animate);
ctx.clearRect(0, 0, width, height);
for (let i = 0; i < circleArray.length; i++) {
circleArray[i].update();
}
}
animate();
And now i want to cancel the AnimationFrame, because i want to send a Text like "YOU WON" but with the update function, that sitll loops, this text will be overwritten.
function startGame() {
//some other code here
//OnWin
this.win = function() {
window.cancelAnimationFrame(animate);
//some small style properties here
ctx.fillText("YOU WON!", width/2, height/2);
}
//some other code here
}
startGame();
I think, that the Animationframe loops, because cancelAnimationFrame() will only cancel the frame. But the function still running. I had an idea that i should do it with a boolean but i think that's not a really clear.
Here is my test Bool, but it hasn't worked.:
var ctx = canvas.getContext("2d"),
win = false;
//some other code here
function animate() {
if (!win) window.requestAnimationFrame(animate);
ctx.clearRect(0, 0, width, height);
for (let i = 0; i < circleArray.length; i++) {
circleArray[i].update();
}
}
animate();
//some code here
function startGame() {
win = false
//some other code here
//OnWin
this.win = function() {
win = true
window.cancelAnimationFrame(animate);
//some small style properties here
ctx.fillText("YOU WON!", width/2, height/2);
}
//some other code here
}
startGame();
Thanks for every useful help ^^
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.
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();
};
I'm tring to draw an expanding and contracting ring that pulses using javascript and html 5. The problem is (using the below code) when the path is repainted the current path remains visible and just gets fatter. Anybody know why this could be?
function drawOuterInfoCircle(){
var number = 25;
var increase = true;
function draw(){
if(increase==true){
number++
//alert('increase');
if(number==30){
increase=false
}
}
if(increase==false){
number--;
//alert('decrease');
if(number==25){
increase=true
}
}
var drawingCanvas = document.getElementById('canvas_circle');
var drawingContext1 = drawingCanvas.getContext('2d');
drawingContext1.strokeStyle = "#990000";
drawingContext1.lineWidth = 12;
drawingContext1.beginPath();
drawingContext1.arc(100, 100, number, 0, Math.PI*2, true);
drawingContext1.closePath();
drawingContext1.stroke();
}
setInterval(draw,100);
}
I've tried clearing the canvas with the following (from post 3088229) tna
drawingContext1.fillStyle = 'rgba(0,0,0,0)';
drawingContext1.fill();
the fiddle
You are filling with opacity 0, try rgba(0,0,0,1)
before each ring drawing erase the older canvas and redraw on it,
function draw(){
var drawingCanvas = document.getElementById('canvas_circle');
var drawingContext1 = drawingCanvas.getContext('2d');
drawingContext1.clearRect(0,0,drawingCanvas_width,drawingCanvas_height);
if(increase==true){
number++
//alert('increase');
if(number==30){
increase=false
}
}
if(increase==false){
number--;
//alert('decrease');
if(number==25){
increase=true
}
}
//var drawingCanvas = document.getElementById('canvas_circle');
//var drawingContext1 = drawingCanvas.getContext('2d');
drawingContext1.strokeStyle = "#990000";
drawingContext1.lineWidth = 12;
drawingContext1.beginPath();
drawingContext1.arc(100, 100, number, 0, Math.PI*2, true);
drawingContext1.closePath();
drawingContext1.stroke();
}
Is it possible to make elements inside a HTML5 Canvas element draggable and resizable. Is there any way to make the dynamic image in the following code to be movable:
var ctx, imgArray;
function initAll() {
ctx = document.getElementById("canvas").getContext("2d");
imgArray = ["http://i46.tinypic.com/nqe1dt.jpg",
"http://i50.tinypic.com/i21phi.jpg",
"http://i49.tinypic.com/1zmfcrq.jpg",
"http://i50.tinypic.com/v8g6mo.jpg",
"http://i49.tinypic.com/21kh7ah.jpg"];
drawCanvas();
document.getElementById("checkgroup").onchange = drawCanvas;
}
function drawCanvas() {
ctx.clearRect(0, 0, 600, 400);
for(var i=0; i < imgArray.length; ++i) {
var img = new Image();
img.posX = (i < 3) ? i*200 : (i-2.5)*200;
img.posY = (i < 3) ? 0 : 200;
img.src = imgArray[i];
img.onload = function() {
ctx.drawImage(this, this.posX, this.posY, 150, 150);
}
}
}
window.onload = initAll;
The project is found at JSBin: http://jsbin.com/welcome/7209/edit
Use KineticJS which provides shape object support for canvas.
KineticJS will provide mouse events for its shapes and thus you can implement drag-like functionality more easily:
http://www.html5canvastutorials.com/kineticjs/html5-canvas-drag-and-drop-tutorial/