Does anyone know the best way to clear a canvas using paper.js
I tried the regular canvas clearing methods but they do not seem to work with paper.js
Html
<canvas id="myCanvas" style="background:url(images/graphpaper.jpg); background-repeat:no-repeat" height="400px" width="400px;"></canvas>
<button class="btn btn-default button" id="clearcanvas" onClick="clearcanvas();" type="button">Clear</button>
Javascript/Paperscript
<script type="text/paperscript" canvas="myCanvas">
// Create a Paper.js Path to draw a line into it:
tool.minDistance = 5;
var path;
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
function onMouseDown(event) {
// Create a new path and give it a stroke color:
path = new Path();
path.strokeColor = 'red';
path.strokeWidth= 3;
path.opacity="0.4";
// Add a segment to the path where
// you clicked:
path.add(event.point, event.point);
}
function onMouseDrag(event) {
// Every drag event, add a segment
// to the path at the position of the mouse:
path.add(event.point, event.point);
}
</script>
Regular clearing does not work because paper.js maintains a scene graph and takes care of drawing it for you. If you want to clear all items that you have created in a project, you need to delete the actual items:
project.activeLayer.removeChildren(); works as long as all your items are inside one layer. There is also project.clear() which removes everything, including the layer.
In case someone comes looking for an answer with little experience in Javascript, I made a simple example :
1) As Jürg Lehni mentioned project.activeLayer.removeChildren(); can be used to remove all items inside active layer.
2) To reflect the cleaning you have to call paper.view.draw();.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Circles</title>
<link rel="stylesheet" href="style.css">
<script type="text/javascript" src="paper-full.js"></script>
<script type="text/paperscript" canvas="canvas">
function onMouseUp(event) {
var circle = new Path.Circle({
center: event.middlePoint,
radius: event.delta.length / 2
});
circle.strokeColor = 'black';
circle.fillColor = 'white';
}
</script>
<script type="text/javascript">
paper.install(window);
window.onload = function () {
paper.setup('canvas');
document.getElementById('reset').onclick = function(){
paper.project.activeLayer.removeChildren();
paper.view.draw();
}
};
</script>
</head>
<body>
<canvas style="background-color: #eeeeed" id="canvas" resize></canvas>
<input id="reset" type="button" value="Reset"/>
</body>
</html>
CSS :
html,
body {
margin: 0;
overflow: hidden;
height: 100%;
}
/* Scale canvas with resize attribute to full size */
canvas[resize] {
width: 58%;
height: 100%;
}
you can use project.activeLayer.removeChildren(); for clear entire layer,
or you can add your new paths to group and remove all childrens in group
var myPath;
var group = new Group();
function onMouseDown(event) {
myPath = new Path();
}
function onMouseDrag(event) {
myPath.add(event.point);
}
function onMouseUp(event) {
var myCircle = new Path.Circle({
center: event.point,
radius: 10
});
myCircle.strokeColor = 'black';
myCircle.fillColor = 'red';
group.addChild(myCircle);
}
// connect your undo function and button
document.getElementById('clearbutton').onclick = btnClear;
function btnClear(){
group.removeChildren();
}
c.width = c.width; ctx.clearRect(0,0,c.width,c.height); should be a good catchall if you've not tried it.
Beware however - setting canvas width will reset the canvas state including any applied transforms.
A quick google took me to https://groups.google.com/forum/#!topic/paperjs/orL7YwBdZq4 which specifies another (more paper.js specific) solution:
project.activeLayer.removeChildren();
Related
This is my easel js function, it draws a red circle and an image, however the circle is showing but the image isn't.
function Start() {
var stage = new createjs.Stage("DogeCanvas");
var dog = new createjs.Bitmap("doge.jpg");
var circle = new createjs.Shape();
circle.graphics.beginFill("red").drawCircle(0, 0, 50);
circle.x = 100;
circle.y = 100;
dog.x=100;
dog.y=100;
stage.addChild(circle, dog);
stage.update();
}
And this is the html file
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<script src="http://code.createjs.com/easeljs-0.7.0.min.js"></script>
<script src="Doge.js"></script>
</head>
<body bgcolor="#C7C7C7" onload="Start();">
<canvas id="DogeCanvas" width="480" height="320"></canvas>
</body>
</html>
Why? help please, seems like in everyones else code this works but why this isn't working for me?
The image is likely not loaded yet.
You can add a Ticker to the stage to constantly update it (which most applications do, since there is other things changing over time)
Example:
createjs.Ticker.on("tick", stage);
// OR
createjs.Ticker.addEventListener("tick", stage);
// OR
createjs.Ticker.on("tick", tick);
function tick(event) {
// Other stuff
stage.update(event);
}
Listen for the onload of the image, and update the stage again
Example:
var bmp = new createjs.Bitmap("path/to/image.jpg");
bmp.image.onload = function() {
stage.update();
}
Preload the image with something like PreloadJS before you draw it to the stage. This is a better solution for a larger app with more assets.
Example:
var queue = new createjs.LoadQueue();
queue.on("complete", function(event) {
var image = queue.getResult("image");
var bmp = new createjs.Bitmap(image);
// Do stuff with bitmap
});
queue.loadFile({src:"path/to/img.jpg", id:"image"});
I tried three different approaches but none worked.
I place two rectangles on the canvas and want to catch the object under the mouse cursor when a mousedown event occurred.
The stagemousedown works, but the objects are not found. Watching the debugger I see that the rectangle has still the drawrect coordinates, not the one that I set later. There is also a 'hitarea' which I don't know how to use since it is checked during hittest and getObjectUnderPoint.
Approach 1: makeButton creates a handler on lines 66ff -> it never fires
Approach 2: getObjectUnderPoint when a mousedown evt happens. -> returns always null
Approach 3: loop through each child and apply the hitttest -> returns always false.
I come from Java and C# and am far from being experienced in JS, but I had hoped that I could catch the mousedown with at least one approach.
What makes me wonder is that the x and y in the rectangle never change from the ones used during creation (0,0). That's not the current position which I set for example in 73 and 74!
I don't seem to find the REAL x and y of the object and neither does approaches 2 and 3. I wished, approach 1 would work since that makes the most sense to me.
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="stylesheet" href="./css/style.css">
<meta charset="utf-8" />
<title></title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/EaselJS/1.0.2/easeljs.js"></script>
<script>
function init() {
var followme = 0;
var canvas = document.getElementById("canvas");
var stage=new createjs.Stage(canvas);
var shape=new createjs.Shape();
var dispO = new createjs.Shape();
makeBtn(3,3);
makeBtn(300,300);
stage.on("stagemousedown", function (evt) {
followme = 1;
found=stage.getObjectUnderPoint(stage.mouseX, stage.mouseY,0)
if(found != null)
{
console.log(found);
}
var xxx=stage.children;
for (i=0; i<xxx.length;i++)
{
if (xxx[i].hitTest(stage.mouseX, stage.mouseY))
{
shape.alpha=1;
}
}
});
stage.on("stagemouseup", function (evt) {
followme = 0;
});
stage.update();
createjs.Ticker.setFPS(30);
createjs.Ticker.addEventListener("tick", handleTick);
function handleTick(event)
{
if ((followme === 1) && (dispO != null))
{
var difX = stage.mouseX - dispO.x - 100;
var difY = stage.mouseY - dispO.y - 50;
dispO.x += difX / 20;
dispO.y += difY / 20;
stage.update();
}
else
if(dispO != null)
{
var dmy=dispO;
}
}
function makeBtn(x,y)
{
shape = new createjs.Shape();
shape.graphics.beginStroke("black").setStrokeStyle(2, 0, 1).drawRect(0, 0, 200, 100);
dispO=shape;
dispO.mouseEventsEnabled = true;
var handler=dispO.on("mousedown",
function(event) {console.log(instance == this); },// true, "on" uses dispatcher scope by default.
null,
once=true,
'theButton',
useCapture=true
);
dispO.x=x;
dispO.y=y;
stage.addChild(dispO);
}
}
</script>
</head>
<body onload="init();">
<div id="outer">
<canvas id="canvas" width="500" height="600">
</canvas>
<menu id="controls">
</menu>
</div>
</body>
</html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/EaselJS/1.0.2/easeljs.js"></script>
Your demo works fine -- its just that your square has no fill, so only the border is clickable. If you add a fill, then it works great:
https://jsfiddle.net/lannymcnie/ozcr6tna/
shape.graphics.beginStroke("black")
.setStrokeStyle(2, 0, 1)
.beginFill("white") // <----- Fill call
.drawRect(0, 0, 200, 100);
If you want the clickable area to be transparent, then you can use a hitArea. Just assign a different shape with a fill as a hitArea (and don't add that shape to the stage). Hit testing in EaselJS uses pixel fill - so if there are no pixels, then there is no hit!
Hope that helps!
I'm going to start this question off by saying that this is 100% working in Firefox (v21.0). For some reason it's not working in Google Chrome (v27.0.1453.94m). It also doesn't work in IE10.
Here is the JavaScript code I'm having issues with:
function canvasDrawBackground(value){
console.log(value);
stage.removeChild(background);
var temp = new createjs.Bitmap("images/bg_" + value +".jpg");
background = new createjs.Container();
background.x = background.y = 0;
background.addChild(temp);
stage.addChild(background);
background.addEventListener("mousedown", function(evt) {
var offset = {x:evt.target.x-evt.stageX, y:evt.target.y-evt.stageY};
evt.addEventListener("mousemove",function(ev) {
ev.target.x = ev.stageX+offset.x;
ev.target.y = ev.stageY+offset.y;
stage.update();
});
});
stage.update();
}
So, in Firefox the above code works, as in the image is added to the canvas and you can drag it around.
In Chrome / IE10 nothing happens - or more simply nothing appears on the canvas. I think the issue is in regards to when I add the image into the container, as I can place other items into the container and it works.
I am using http://code.createjs.com/easeljs-0.6.1.min.js and this code is based off of the "drag" tutorial. Here's the code from the tutorial:
<!DOCTYPE html>
<html>
<head>
<title>EaselJS demo: Dragging</title>
<link href="../../shared/demo.css" rel="stylesheet" type="text/css">
<script src="http://code.createjs.com/easeljs-0.6.0.min.js"></script>
<script>
var stage, output;
function init() {
stage = new createjs.Stage("demoCanvas");
// this lets our drag continue to track the mouse even when it leaves the canvas:
// play with commenting this out to see the difference.
stage.mouseMoveOutside = true;
var circle = new createjs.Shape();
circle.graphics.beginFill("red").drawCircle(0, 0, 50);
var label = new createjs.Text("drag me", "bold 14px Arial", "#FFFFFF");
label.textAlign = "center";
label.y = -7;
var dragger = new createjs.Container();
dragger.x = dragger.y = 100;
dragger.addChild(circle, label);
stage.addChild(dragger);
dragger.addEventListener("mousedown", function(evt) {
var offset = {x:evt.target.x-evt.stageX, y:evt.target.y-evt.stageY};
// add a handler to the event object's onMouseMove callback
// this will be active until the user releases the mouse button:
evt.addEventListener("mousemove",function(ev) {
ev.target.x = ev.stageX+offset.x;
ev.target.y = ev.stageY+offset.y;
stage.update();
});
});
stage.update();
}
</script>
</head>
<body onLoad="init();">
<canvas id="demoCanvas" width="500" height="200">
alternate content
</canvas>
</body>
</html>
To simulate my issue, change "var circle = new createjs.Shape();" into a bitmap / image, createjs.Bitmap("images/bg_" + value +".jpg");. It then doesn't render.
Any help is greatly appreciated! Hopefully I'm just doing it wrong. :P
This is probably because the image is not loaded. If you only update the stage after creating it, the image may not display. I would recommend adding a callback to the image to update the stage after its loaded.
// Simple approach. May not work depending on the scope of the stage.
var temp = new createjs.Bitmap("images/bg_" + value +".jpg");
temp.image.onload = function() { stage.update(); }
It also may make sense to preload the images you intend to use.
I am using FabricJS to develop a simple floor plan editor. When adding a Line (that should be a wall) to the canvas, I want the ability to control only the length of the line, not it's width-height.
I have tried setting lockScalingY: true but the problem is that when adding a line the control handles are so close to each other that I can't interact only with the horizontal control handles... the corner handles actually block the horizontal handles...
How can this be done?
Fine control of adjoining FabricJS lines
The way graphics programs like photoshop deal with this common problem is to let the user position lines near the desired intersection and then use the arrowkeys to "nudge" the line into place pixel one at a time.
The code below illustrates a rough solution that does the same thing for FabricJS lines:
User selects a line.
Turn off the control handles and borders.
Let the user "nudge" the line into perfect alignment (here the line length is increased).
Turn the the control handles and borders back On.
This is just "proof of concept" code. In your production app:
You'll probably want to use arrowkeys instead of buttons to "nudge".
I made nudging go 10px at a time--you might do this 1px at a time.
And when the user starts nudging, you'll automatically turn off the handles and borders for them.
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/dd742/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script type="text/javascript" src="fabric.min.js"></script>
<style>
body{ background-color: ivory; padding:30px; }
canvas{border: 1px solid red; }
</style>
<script>
$(function(){
var canvas = new fabric.Canvas('canvas');
var selectedLine;
var line1=newLine(50,100,150,100,"red");
var line2=newLine(160,50,160,150,"green");
canvas.add(line1,line2);
function newLine(x1,y1,x2,y2,color){
var line=new fabric.Line(
[x1,y1,x2,y2],
{fill:color,strokeWidth:15,selectable:true}
);
return(line);
};
$("#hOff").click(function(){
selectedLine.hasBorders=false;
selectedLine.hasControls=false;
canvas.renderAll();
});
$("#hOn").click(function(){
selectedLine.hasBorders=false;
selectedLine.hasControls=true;
canvas.renderAll();
});
$("#shorter").click(function(){
changeLineLength(selectedLine,-10);
canvas.renderAll();
});
$("#longer").click(function(){
changeLineLength(selectedLine,10);
canvas.renderAll();
});
function changeLineLength(line,adjustment){
if(!selectedLine){return;}
if(line.get("y1")==line.get("y2")){ // line is horizontal
line.set("x2",line.get("x2")+adjustment);
}else
if(line.get("x1")==line.get("x2")){ // line is vertical
line.set("y2",line.get("y2")+adjustment);
}else{ // line is diagonal
line.set("x2",line.get("x2")+adjustment);
line.set("y2",line.get("y2")+adjustment);
}
}
canvas.observe('object:selected', function(eventTarget) {
var event=eventTarget.e;
var target=eventTarget.target;
selectedLine=target;
});
}); // end $(function(){});
</script>
</head>
<body>
<p>Select a line,</p><br/>
<p>Turn handles Off</p><br/>
<p>Make lines intersect by pressing longer/shorter</p><br/>
<canvas id="canvas" width="600" height="200"></canvas>
<button id="hOff">Handles Off</button>
<button id="shorter">Shorter</button>
<button id="longer">Longer</button><br/>
<button id="hOn">Handles On</button>
</body>
</html>
May be helps somebody.
Add handler to event
'object:selected': _objSelected
Then at handler set unneeded control to false.
function _objSelected(e)
{
if(e.target.objectType == 'line')
{
var cv = e.target._controlsVisibility;
// mt - middle top, tl - top left and etc.
cv.mt = cv.mb = cv.tl = cv.bl = cv.tr = cv.br = false;
}
}
Also I added objectType (custom property) and padding (for beauty) to new object Line
var obj = new fabric.Line([50, 50, 150, 50], { padding: 10, objectType: 'line' });
I am making a loading spinner with html5 canvas. I have my graphic on the canvas but when i rotate it the image rotates off the canvas. How do I tell it to spin the graphic on its center point?
<!DOCTYPE html>
<html>
<head>
<title>Canvas test</title>
<script type="text/javascript">
window.onload = function() {
var drawingCanvas = document.getElementById('myDrawing');
// Check the element is in the DOM and the browser supports canvas
if(drawingCanvas && drawingCanvas.getContext) {
// Initaliase a 2-dimensional drawing context
var context = drawingCanvas.getContext('2d');
//Load the image object in JS, then apply to canvas onload
var myImage = new Image();
myImage.onload = function() {
context.drawImage(myImage, 0, 0, 27, 27);
}
myImage.src = "img/loading.png";
context.rotate(45);
}
}
</script>
</head>
<body>
<canvas id="myDrawing" width="27" height="27">
</canvas>
</body>
</html>
Here is the complete working example:)
<!DOCTYPE html>
<html>
<head>
<title>Canvas Cog</title>
<script type="text/javascript">
var cog = new Image();
function init() {
cog.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAYAAACN1PRVAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABK1JREFUeNqMVt1ZGzkUvVfS4IW1l8GO82w6IBXE7mCpAFMB+Pt4Z6iApALcAe4AU0HoAJfg7BPYHinnXmmciX+y0YdmJHnQ0bk/R5cvh5cUyFPwRD4EChgEvGWMB36R3+JaiTkmD5gOs8yNb25uLlerFf1pM2yIGA82TEY7xow1oj4GBU6S6yywPNG4JwDH+XGv0Whs7ndN8n97mmPsLCSYgy7ImPQE/pFDyAF+7L0fgTNFUDBcLal90taD1doQ/T6NT9DnW8zkT+jJuQVYukG3hifCVk/L3JOxMBa8VVlSp9MhHKLaB+zpNo1fdgEpmByuMqUAV5viOQLwXNax9KBAFNEEpN1pUwnQmvl6aTza6zNjrCKaymeyOdYAMgfg18iG4T/qw+AC94zvpzDjcwqOXo3VGH26H0xMZ7jPxgT0R2zUi4BYt6bAfEbJvJFZKA4ODgZ5nhcJLE9mk35X21vWC/TXKmiwr2xszoQd/PQv3t/QCzY2twpqBpb5FKOp+hCgzWaTWq0W1Xx0ij5An9WC5VtiLMwvNBrVaSGMvQk5jHQVPN7sb0HzAtE+QJrNgrcUNEARieWCut0ugR0tl8sKcJ5Ahc3jRviPK8ZGTaaBwGKyT+gTiwM4a3Jrba6MbeVXo5F4kp9shn29ndUYC9vLirGDXzRhrYhD8DME5Hkg22df5rDYS/RXmVIsaP/Q/SXs600YnifTjbeSWliEdTYb3QyTqYfdDKTL4B1KS6tVqf6SgGq3P9BvZGpvNIrPCgVKZlGlCDQDxJiCjVppCab05DJHzb+b1Gm36X80cVjLuzozexs0f6IgRkA5XRhzIixRL1+IzhwdHVHrn1Y9oXe1i10aKT6bGGhg1CKK+cT0zCGCs0oXTIogybJMw/779//o48duMvnO9rzLn+Kz8wgS5Shqo4njpCoOQA5Ajb8adHh4SMvVghaLhYb/HsBip88krNVISSEigOlhjmi0LziNhr6wOsgO9C1339vbGznnNAU2AM9Svk235cqKieKGkldAf7DGvTrjnjJnzyQoMu0ZTuZgUqvmlYR+f39XIE4uqCX1E/rDZpCYmKwOOmivAfYK9KF1AM7EdG4uAMLAOjmQideQXOJQkyUisqYiFRhtSFbxCxj8do0T30dmTvLhC+an0MZZVBHX09tBTG4qFigZEJEChjTIEwtRik81Qa7uOQU0IrYAe7FRjqYw6SlYjgAyN1GmHsFIGPfVnxzFuFITKEkfYK+oWZ5qKlIkcZ7UE92oXBmeIgIxtAO5UtSHqo9uiLW+sme5ejSIRASeAFR4LYy8MMzL1aq3EYWzJF28BgMEzGYpBkrMKelgl+P6uTcVY8NjLYyYPwMTCcufSaouH6al9xNJcjC82vDb9uVZKbrWIumNO+waVsu1TCC+Wxcg6xaSpsZSYM2wLO9/U8qZWH+wztQnsfAxV/E3MIKZVf1FsmJVV8mamhEmxZ0X7sSsABsGv1tZJGejmptU7FBUDYzPAXQBwFEEl+9+stFEroJEci2ELwIMmZuWoSTE9DYYcWVCjlJrZWMpeBhlAEqBiulPE84S3ixU5gSTwGGOdyEVNJXxA8nPevshwABHktBS1YoQ+QAAAABJRU5ErkJggg=='; // Set source path
setInterval(draw,10);
}
var rotation = 0;
function draw(){
var ctx = document.getElementById('myCanvas').getContext('2d');
ctx.globalCompositeOperation = 'destination-over';
ctx.save();
ctx.clearRect(0,0,27,27);
ctx.translate(13.5,13.5); // to get it in the origin
rotation +=1;
ctx.rotate(rotation*Math.PI/64); //rotate in origin
ctx.translate(-13.5,-13.5); //put it back
ctx.drawImage(cog,0,0);
ctx.restore();
}
init();
</script>
</head>
<body>
<canvas width="27" height="27" id="myCanvas"></canvas>
</body>
</html>
rotate turns the canvas(?) around your current position, which is 0, 0 to start. you need to "move" to your desired center point, which you can accomplish with
context.translate(x,y);
after you move your reference point, you want to center your image over that point. you can do this by calling
context.drawImage(myImage, -(27/2), -(27/2), 27, 27);
this tells the browser to start drawing the image from above and to the left of your current reference point, by have the size of the image, whereas before you were starting at your reference point and drawing entirely below and to the right (all directions relative to the rotation of the canvas).
since your canvas is the size of your image, your call to translate will use the same measurement, (27/2), for x and y coordinates.
so, to put it all together
// initialization:
context.translate(27/2, 27/2);
// onload:
context.rotate(Math.PI * 45 / 180);
context.drawImage(myImage, -(27/2), -(27/2), 27, 27);
edit: also, rotation units are radians, so you'll need to translate degrees to radians in your code.
edits for rearranging stuff.
For anyone else looking into something like this, you might want to look at this script which does exactly what was originally being requested:
http://projects.nickstakenburg.com/spinners/
You can find the github source here:
https://github.com/staaky/spinners
He uses rotate, while keeping a cache of rectangles which slowly fade out, the older they are.
I find another way to do html loading spinner. You can use sprite sheet animation. This approach can work both by html5 canvas or normal html/javascript/css. Here is a simple way implemented by html/javascript/css.
It uses sprite sheet image as background. It create a Javascript timer to change the background image position to control the sprite sheet animation. The example code is below. You can also check the result here: http://jmsliu.com/1769/html-ajax-loading-spinner.html
<html>
<head><title></title></head>
<body>
<div class="spinner-bg">
<div id="spinner"></div>
</div>
<style>
.spinner-bg
{
width:44px;
height:41px;
background: #000000;
}
#spinner
{
width: 44px;
height: 41px;
background:url(./preloadericon.png) no-repeat;
}
</style>
<script>
var currentbgx = 0;
var circle = document.getElementById("spinner");
var circleTimer = setInterval(playAnimation, 100);
function playAnimation() {
if (circle != null) {
circle.style.backgroundPosition = currentbgx + "px 0";
}
currentbgx -= 44; //one frame width, there are 5 frame
//start from 0, end at 176, it depends on the png frame length
if (currentbgx < -176) {
currentbgx = 0;
}
}
</script>
</body>