FabricJS - add line to canvas and control only it's length - javascript

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' });

Related

Issues in design/implementation of a software with kineticjs

I want to create an application that the user will have the ability to click on a picture add points and for each (certain) pairs of points the software will draw a line between those two. The points are draggable so the line must be able to readjust itself to the new position of its two ancors. The points are pre-specified and more than 5 or 6 (it can be 10 or more)
So my design so far.
One kinetic stage
One backgroundLayer which will have the following children:
backgournImage (will hodl the image to click on)
The points aded
the lines between the points
I guess for each of the lines I will have to use a group that will contain the two ancors and the line. My problem is the following: Is there a convenient way to make sure a group is allready created for a certain pair of points so as not to create a new one when clicking on picture to add a new point?
stage.('contentClick', function(event){
//create a new point
// if a group for the specific pair of ancors exists
//add the point and draw the line
// else this is the first point of the pair we are talking about
// so create the group
//and add the new point
// add the group on the backgroundLayer
//redraw stage
);
All points can have a specific id the name of the point.
I know the code for creating points groups adding them removing them checking parents etc, just don't know how could I do it with the least manual method. I mean it's not very productive checking each and every one of the points right?
Hope I am making some sense...
One way is to track pairs of anchors that must be connected & reset their connecting lines when an anchor is dragged:
Create a Line to act as a connector.
Create a js object that holds references to the 2 anchors and the line connecting them.
Add the connection-object in an array.
When any anchor is dragged, iterate the array & reset the connectors for the anchor that was dragged.
Example code and a Demo: http://jsfiddle.net/m1erickson/b7h5dfg5/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Prototype</title>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.0.1.min.js"></script>
<style>
body{padding:20px;}
#container{
border:solid 1px #ccc;
margin-top: 10px;
width:350px;
height:350px;
}
</style>
<script>
$(function(){
var stage = new Kinetic.Stage({
container: 'container',
width: 350,
height: 350
});
var layer = new Kinetic.Layer();
stage.add(layer);
var connectors=[];
var a1=addAnchor(50,50,'one');
var a2=addAnchor(150,50,'two');
var a3=addAnchor(100,100,'three');
addConnection(a1,a3);
addConnection(a2,a3);
function resetConnections(id){
for(var i=0;i<connectors.length;i++){
var c=connectors[i];
if(c.id1==id || c.id2==id){
c.line.points([
c.anchor1.x(),
c.anchor1.y(),
c.anchor2.x(),
c.anchor2.y()
]);
}
}
layer.draw();
}
function addAnchor(x,y,id){
var anchor=new Kinetic.Circle({
id:id,
x:x,
y:y,
radius: 10,
fill: 'red',
stroke: 'black',
strokeWidth:2,
draggable: true
});
anchor.on('dragstart',function(){
stage.find(".connector").each(function(n){ n.hide(); });
layer.draw();
})
anchor.on('dragend',function(){
stage.find(".connector").each(function(n){ n.show(); });
resetConnections(this.id());
})
layer.add(anchor);
layer.draw();
return(anchor);
}
function addConnection(anchor1,anchor2){
var line=new Kinetic.Line({
name:'connector',
points:[anchor1.x(),anchor1.y(),anchor2.x(),anchor2.y()],
stroke:'black'
});
layer.add(line);
line.moveToBottom();
layer.draw();
connectors.push({
line:line,
id1:anchor1.id(),
id2:anchor2.id(),
anchor1:anchor1,
anchor2:anchor2
});
}
}); // end $(function(){});
</script>
</head>
<body>
<h4>Drag red anchors and connectors will follow</h4>
<div id="container"></div>
</body>
</html>

Using Raphaël from a jQuery call

I'm trying to create a simple application for drawing a graph based on user input. I'm using Raphaël and jQuery. I'd like to have the user give their input on a form, and then draw the SVG graphic. The problem I'm having is that when I call the draw function from within a jQuery click event, the SVG object flickers and then disappears. There's a MWE below. (Perhaps it could be more minimal.) How can I make sure that the graphic stays there after the button click?
<!doctype html>
<html>
<head>
<title>Example</title>
<meta charset="utf-8"/>
<script type="text/javascript" src="jquery-ui-1.10.4/jquery-1.10.2.js"></script>
<script type="text/javascript" src="jquery-ui-1.10.4/ui/jquery-ui.js"></script>
<link rel="stylesheet" href="jquery-ui-1.10.4/themes/base/jquery-ui.css" />
<script type="text/javascript" src="raphael-min.js"></script>
</head>
<body>
<form>
<button id="generate-button">Generate</button>
</form>
<div id="canvas"/>
<script>
function CustomObject() {
this.draw = function() {
// Creates canvas 320 × 200 at 10, 50
paper = Raphael("canvas", 100, 100 );
boundary = window.paper.rect( 5, 5, 25, 25 );
boundary.attr("stroke-dasharray" , "--" );
// Creates circle at x = 50, y = 40, with radius 10
circle = paper.circle(50, 40, 10);
// Sets the fill attribute of the circle to red (#f00)
circle.attr("fill", "#f00");
// Sets the stroke attribute of the circle to white
circle.attr("stroke", "#fff");
}
}
var plot = new CustomObject();
// plot.draw(); // if I call it here, the scene is drawn "normally"
$( "#generate-button" )
.button()
.click(function() {
plot.draw(); // when I call it here, the SVG flickers and disappears
});
</script>
</body>
</html>
The default type for a button is submit and when inside a form will try to submit the form.
Your click handler is executing and then submitting the form which is causing the flicker.
Either take the button out of the form or return false from the click event handler as this will disable the browsers default action.

Canvas, disable image download [duplicate]

This question already has answers here:
Disable to download image from canvas
(4 answers)
Closed 8 years ago.
I'm making a game in html5/js, there is a map with a fog of war on it.
When you right click on the canvas you can save the canvas as an image and so, you can have the whole map in a jpg, but that map need to be hidden.
Is there any trick to disable this ?
I tried to create my fog of war in the same canvas than the map, it works but it's harder to move the fog since i need to create for every move the entire map.
Thank you.
Here’s how to moderately obfuscate your image:
It works by scrambling your map so the casual user cannot easily view it.
Slice your image vertically and horizontally into many pieces.
Scramble all those pieces and create a new scrambled image from them.
Serve that scrambled image to the web page (this scrambled image is unrecognizable to the user).
Save the scrambling order in a JSON array so you can later descramble the image.
Obfuscating Demo: http://jsfiddle.net/m1erickson/wWbt5/
When you need the image, unscramble it into an in-memory canvas that the user can’t see, but which you can programatically use in your game.
De-obfuscating Demo: http://jsfiddle.net/m1erickson/UtN6g/
Code for obfuscating
<!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>
<style>
body{ background-color: ivory; padding:20px;}
#obfuscated{border:1px solid blue;}
#canvas{border:1px solid red;}
</style>
<script>
$(function(){
var img=new Image();
img.onload=start;
img.crossOrigin="anonymous";
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/obfuscated.png";
var verticalSlices=60;
var horizontalSlices=60;
var sliceCount=verticalSlices*horizontalSlices;
var sliceWidth,sliceHeight;
var slices=[];
var json;
function start(){
// vars for slice sizes
sliceWidth=img.width/verticalSlices;
sliceHeight=img.height/horizontalSlices;
// create a slices array to be used to scramble our image
for(var i=0;i<sliceCount;i++){ slices.push(i); }
slices=shuffle(slices);
// scramble the original image
var $obfuscatedImage=document.getElementById("obfuscated");
$obfuscatedImage.src=obfuscate(img,slices);
// create a JSON array used to descramble the image
slices.unshift(verticalSlices,horizontalSlices);
json=JSON.stringify(slices);
}
function obfuscate(img,slices){
var tempCanvas=document.createElement("canvas");
var tempCtx=tempCanvas.getContext('2d');
tempCanvas.width=img.width;
tempCanvas.height=img.height;
for(var i=0;i<slices.length;i++){
var s=slices[i];
var row=parseInt(s/verticalSlices);
var col=s-row*verticalSlices;
var x=col*sliceWidth;
var y=row*sliceHeight;
var canvasRow=parseInt(i/verticalSlices);
var canvasCol=i-canvasRow*verticalSlices;
var canvasX=canvasCol*sliceWidth;
var canvasY=canvasRow*sliceHeight;
tempCtx.drawImage(img,
x,y,sliceWidth,sliceHeight,
canvasX,canvasY,sliceWidth,sliceHeight);
}
return(tempCanvas.toDataURL());
}
function shuffle(array) {
var currentIndex = array.length,temporaryValue,randomIndex;
while (0 !== currentIndex) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
}); // end $(function(){});
</script>
</head>
<body>
<p>Before scrambling</p>
<img src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/koolaidman.png"><br>
<p>After scrambling</p>
<img id="obfuscated" width=300 height=300>
</body>
</html>
Code for de-obfuscating
<!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>
<style>
body{ background-color: ivory; padding:20px; }
#obfuscated{border:1px solid red;}
#clarify{margin:10px;}
canvas{border:1px solid blue;}
p{margin:10px;}
</style>
<script>
$(function(){
// this json would be downloaded from the server
// first 2 elements are images width,height
// next 2 elements are #vertical,#horizontal slices
var json="[60,60,734,418,14,393,2863,1779,3555,1208,1300,2715,2380,130,2082,2004,2882,2610,2816,2537,1578,815,571,1188,806,2554,2115,683,923,2049,2180,2429,1799,1185,1827,522,3061,1856,554,1455,1731,3140,831,2022,2983,3203,2350,1586,2320,3494,1946,2628,1424,1900,1027,791,1373,257,3501,1094,1458,3419,2122,858,2515,2312,3521,2795,224,2711,77,2885,1239,2035,1545,1370,2787,468,3579,780,504,2070,2584,1698,2652,898,2111,2305,2901,2929,2482,2193,725,134,2781,2871,2342,2621,2930,3370,169,3107,2695,2862,963,1099,2775,997,2850,1252,2667,1782,1917,61,2645,2788,879,1377,1663,2522,517,2595,166,2815,2510,2835,2538,3551,2011,2942,30,3308,285,2933,1758,2029,2569,220,1105,445,931,2017,153,1728,3407,1057,2163,1636,296,920,2663,995,51,1840,25,1030,3117,1935,840,986,1387,1084,1832,728,37,1551,3361,533,1927,2771,109,3428,2123,2265,277,2643,3587,2764,549,65,785,2943,1643,2453,2467,2906,2335,540,626,3021,1802,2984,1547,284,2125,860,383,2292,2264,350,3141,2670,1722,1440,203,250,2813,1470,1901,2893,1197,2206,3535,2583,1787,1659,1130,541,2524,1435,380,770,161,3038,1607,3257,2240,1175,3176,2750,3304,759,67,993,2964,1497,173,2155,2948,1695,384,472,991,838,1798,977,334,219,2425,2030,269,3206,2423,1925,2202,2099,2721,1087,3508,635,3078,2987,2045,292,3029,2279,2845,2659,2379,492,523,674,1825,887,2169,1328,81,2585,382,2572,2793,1464,3590,453,1134,2067,949,983,1620,2818,6,1820,821,295,1116,2976,544,1913,2562,3406,864,675,2002,967,2985,2710,1784,427,2495,1590,1721,3381,610,3373,3339,1803,1041,2087,1465,1390,1014,1289,1868,2221,1068,2498,183,1680,805,1703,3504,2656,894,1671,2928,3595,825,3068,1053,2109,1292,691,2271,1100,3578,2451,1344,771,3384,2526,692,2336,2037,570,1233,2566,1477,3192,479,3353,1639,1378,3447,2973,3136,2148,588,3042,131,3070,2574,214,2743,3239,1058,1844,1019,3041,656,1893,3193,1902,2065,1449,3470,2608,2655,1708,1374,987,3166,3055,2327,1234,1678,1980,71,807,2228,3033,779,218,1625,405,215,3253,652,3086,1810,1602,1536,2174,2371,1916,2219,3151,410,1683,2442,1195,1141,54,532,3479,1319,733,3365,762,2680,3536,3507,117,1701,68,3148,1904,2782,320,1706,1078,629,2727,3275,649,268,625,885,2796,2660,2358,3177,2962,458,2594,2903,1056,1872,1499,1970,2545,1808,2294,1236,3548,902,3028,2797,3005,1801,3040,3254,1610,2245,2196,695,3322,696,3224,3344,198,901,2431,1657,2323,1486,1874,727,835,355,2322,2356,29,2534,1736,3114,2809,2046,3415,2458,366,3152,2508,2803,1050,2950,2077,409,1525,2108,1073,2939,2470,3489,2722,553,3268,2927,3269,338,3119,1682,477,1543,3238,1841,247,3318,1245,1444,3472,2066,1419,2829,3292,1885,2814,2178,2536,3460,524,1022,1745,2870,3414,2746,196,3534,2765,503,2776,2398,1474,3382,1290,1381,3232,459,1488,1018,63,3317,2159,2491,1186,2246,332,3082,3399,2191,152,828,2755,3106,2034,2484,2044,837,3486,2095,1760,1672,3511,667,737,1270,489,3410,2958,1459,1447,658,2365,1155,406,2000,339,236,560,870,1855,984,1386,158,1230,1170,1184,3226,1190,2063,1986,3185,1365,1988,457,1069,1472,699,959,682,3374,665,1329,1891,331,713,1923,3325,133,801,1366,1354,1569,2362,1272,2587,2926,814,755,768,883,1691,3334,604,2657,1985,636,434,412,2133,3503,3433,359,3319,498,2786,1198,1015,596,2521,1003,443,1000,231,154,2306,1253,86,3490,347,2532,3385,341,1220,2339,115,221,2303,3455,87,2089,2837,1786,973,5,3026,2003,1582,3309,2623,1293,2644,439,2101,681,2579,2205,2907,992,2284,487,1035,3050,841,969,1127,786,2898,1807,1759,1392,563,2661,2839,1738,1911,2598,1598,1751,1132,2079,243,2844,2401,2434,2461,1644,1775,1107,619,2249,2040,2578,738,547,1343,1400,53,1221,1043,1651,140,3024,1737,3518,3421,3549,1360,1081,3083,2773,1243,3337,888,631,1023,240,505,416,2728,2188,904,1550,2696,2647,1984,72,2406,108,606,2481,3444,1249,804,2996,3388,2410,1850,1158,3454,3506,1238,2236,589,1422,1847,2293,2724,3347,1567,3483,2812,849,899,941,2462,2091,537,2012,632,543,594,1306,132,546,1060,2223,3516,1697,816,3345,2145,1848,436,2671,155,1889,2048,2262,3559,3532,138,1299,2020,1957,2974,1715,643,3487,1317,2714,2162,1355,1067,926,732,1924,2783,1712,2636,3393,3112,2672,3499,2998,1726,3517,1594,3378,494,2059,1282,372,3313,0,1217,469,47,2445,1573,3459,2673,2273,249,2924,3529,2653,1397,2993,2506,810,2033,1049,2607,736,3429,1498,3403,162,265,1036,297,2260,3163,2447,659,2408,1148,146,1336,2678,3002,3048,288,1382,1597,1596,1969,1313,1681,35,1570,1445,3289,1363,2693,1561,3446,988,1968,2274,426,317,151,2945,435,283,3213,2697,1304,915,2332,3488,1987,3052,3411,1599,2509,1884,2730,2143,2444,2965,209,2131,2217,597,2438,2717,2593,1476,874,1714,844,471,1711,2076,2861,730,2698,2136,1965,3044,2914,2010,395,2396,342,176,2208,404,2254,702,2860,1656,3387,1906,3165,2549,1990,402,2421,233,2977,1260,3181,668,1140,177,3510,2051,1244,1818,2119,276,1858,2807,1146,739,1725,689,1092,1205,62,1646,1061,2552,21,69,2347,2649,3074,763,3266,1291,2539,1592,2126,2156,85,1314,124,1413,1574,2859,2798,1418,255,262,3231,1534,2307,2602,3496,1066,703,129,990,976,3121,293,3178,2016,3586,1664,690,3564,3214,2664,2235,2469,1839,1468,1817,2688,3364,2519,1266,2075,280,2142,1052,1806,3468,3354,1204,2875,2616,2542,2426,462,767,1504,1967,186,1031,139,2455,1296,2094,748,181,3098,2369,962,3283,160,2770,2085,608,2681,637,1608,2684,1909,2194,333,421,1380,542,3270,502,3375,3088,3102,163,1702,1849,3079,241,2800,3592,2856,1614,2441,2792,362,3219,1833,1187,871,839,2904,377,2256,1177,1966,1432,407,223,3199,1750,3130,2128,3563,1995,3227,851,2955,1091,1206,1631,796,1804,1202,758,2517,892,583,534,3583,1405,2280,2096,996,707,2392,44,2233,708,1136,2646,2551,687,797,1108,1013,345,1478,206,3440,1615,2309,1042,3157,1368,414,1796,2211,2505,371,3366,2734,3204,1974,303,99,306,2622,1326,2759,3527,3060,1978,335,1516,3515,456,1025,2784,1944,1364,84,2824,1951,3331,2269,3229,440,3047,1527,2889,721,475,107,1033,1286,3442,290,1420,1649,1743,2563,2507,2560,447,2113,302,3105,394,1193,2995,793,1515,1753,1151,1961,776,3552,1934,3560,520,3127,2285,2372,1268,526,1626,2921,2573,2525,1017,679,2165,488,575,1992,2872,1182,3222,2118,200,2605,2344,3149,2780,2514,38,3343,2036,1757,2104,2489,2527,924,830,3260,2141,1879,2090,189,1425,968,323,45,2757,91,3402,1149,2544,907,519,3228,3320,2283,1189,3252,3296,929,98,2638,3473,1788,1568,254,1676,3377,803,2112,3565,650,1150,3220,389,159,3197,2922,777,1448,513,3108,2880,677,630,3174,1780,1496,1414,1771,2580,2114,3383,2363,1080,1345,1214,386,180,267,3427,1996,216,829,3333,1226,433,1399,551,1852,3543,1032,3080,1137,446,856,743,2502,211,3072,2042,2978,2589,896,1145,357,572,2459,18,424,1029,1218,611,2247,3312,3004,275,1938,2706,2951,2504,914,535,3264,3430,530,3567,697,2400,1886,3233,3056,2952,1932,2940,301,2762,3135,882,184,704,460,3404,1274,1859,419,3537,2319,126,210,2716,1223,1873,1383,2881,1687,2377,64,3299,2234,3371,2259,3491,2548,3216,3288,2864,2902,2412,1020,1789,1960,309,1822,989,3420,246,3550,94,3208,391,3066,694,567,2637,3110,3316,2232,1265,1878,1686,179,940,1231,197,2097,3310,1560,1555,1085,820,2308,1617,2739,1724,1371,1950,2994,1860,2912,745,2760,2842,1353,116,1929,2026,586,2740,644,654,222,1861,43,698,360,1410,1242,2752,2272,2954,516,2105,3011,2449,432,827,593,1263,2794,685,1521,672,1595,2050,282,1823,1907,2869,1532,964,1542,614,2361,673,1275,1295,1585,1423,370,194,1653,934,3327,3525,935,2375,500,978,1871,753,1143,2625,2226,2464,3512,686,3360,2250,2949,3104,859,3417,579,1501,788,3462,1310,2516,1369,2997,1830,2528,2705,576,1393,1097,1843,3568,2386,1979,3054,142,3432,11,1408,834,167,3182,919,2513,1565,2543,1396,289,846,3071,2190,2634,2890,1654,308,798,385,3300,847,2541,2222,1972,1064,3363,2183,1717,3392,1704,1997,3025,2330,2383,1046,510,3505,506,75,2189,59,234,2149,1908,425,1460,1763,917,1732,3037,2957,600,73,2021,639,4,2853,2956,1228,581,235,2577,897,3241,1010,3096,1669,2446,843,2744,1006,1247,298,318,590,1790,356,3556,2291,2052,455,950,928,2758,1748,832,558,1642,2735,373,1429,3195,3261,2774,1494,2564,3175,2990,3293,2820,2150,710,648,483,792,281,112,932,688,740,3009,980,2873,1120,884,1735,2936,1926,1919,1028,2296,528,826,2650,495,143,1710,3546,1142,1628,2238,1342,2691,1070,1538,1037,765,2738,3146,3243,582,1931,192,3031,1503,3596,340,1461,3582,3443,1021,592,2268,1240,947,3089,103,3425,1510,605,2328,2887,2171,1495,2062,187,1083,1835,1869,1674,2834,316,1616,664,3513,2290,3408,1887,2501,1153,263,1059,213,274,2179,1684,1766,878,1427,3523,3207,3187,165,3035,1943,56,1215,2354,2316,2699,1606,312,3372,2935,2821,105,2198,313,3217,2346,1385,1320,624,3201,607,819,1008,3120,2100,2364,1200,3557,2028,1635,701,1809,3014,2685,2486,2209,1795,128,3533,1707,2215,2353,1566,2281,2941,2687,3581,2056,3321,2960,3542,2025,2700,60,1584,1857,662,1696,3302,2008,2001,2999,2895,2415,3018,367,2253,1918,3113,1755,199,974,1912,1685,1655,775,2005,2405,239,3476,408,1530,444,756,813,2590,2499,2018,122,1211,365,2606,3013,3391,2060,430,1350,1783,3409,55,3158,259,811,1005,1248,188,794,1009,2391,42,19,3094,1739,1524,3368,817,3223,2015,324,1580,651,3335,1101,550,1241,2586,3524,812,1442,2753,3395,2480,1279,1824,1854,1553,464,1508,3099,1764,32,2175,1159,1256,481,3457,40,2258,3156,1587,1312,1109,2614,1890,3520,3526,3294,1229,2846,913,2243,2763,3190,2475,3036,2676,655,1002,952,3179,90,862,1630,319,2761,569,2531,1216,2932,17,2503,800,1601,3458,1308,1398,2210,754,2822,3186,1139,1791,1446,2098,1727,33,3336,387,2106,773,229,2629,1430,1668,3423,1777,2134,8,2843,2959,2966,1993,3017,2944,2666,508,3142,2511,3445,1451,938,3531,1471,865,3281,1409,2785,343,2874,1812,195,2443,2799,2823,1040,1624,1981,1939,2277,633,2195,48,1280,3019,2212,562,1883,3084,2754,3144,3356,2988,2729,2014,3092,3218,1894,1352,1881,2876,2185,353,3541,2737,3032,1104,354,272,304,66,521,3075,1741,125,1358,3405,3237,2231,3128,3528,726,2418,2278,3295,2298,2474,3451,2244,3064,12,1514,2867,1255,2806,2064,2216,2384,1115,201,411,3398,2747,975,82,3571,930,1431,1112,212,1834,599,2310,909,615,620,1346,1641,1752,3396,1761,906,718,1517,2313,2550,3477,2349,2337,328,2257,2953,1562,463,2027,2092,2239,1039,363,757,536,149,1716,1746,3129,2603,1088,1914,1942,1920,135,2170,706,3150,2991,3081,305,1921,3389,1133,886,2352,2896,1123,2766,2838,670,2255,958,2261,653,2512,1571,1401,2397,869,2967,3180,1520,1165,3154,13,921,1619,3262,774,1492,2810,1126,1540,3173,2424,3212,1340,2732,2640,2329,2718,912,548,2289,2769,2225,3593,3562,2242,641,3251,1774,1507,3561,557,2600,1335,3452,999,2200,1307,722,2385,3573,512,1347,1880,465,3340,1324,480,3397,1947,1489,939,2229,2132,2472,2615,3030,2378,617,1537,2460,2970,484,2227,908,3509,256,3171,2620,1160,2493,2127,315,2428,731,3122,1318,127,3456,3111,242,1191,1095,2751,1899,781,3514,1800,3413,2868,556,2897,1453,3500,1167,2547,2686,2158,417,3100,2124,3126,2057,3067,3095,1544,1634,3589,2963,3475,1456,2341,3247,3244,193,1176,1034,2571,3077,174,2355,1793,1161,3230,1156,2043,3161,1232,2931,3282,1213,119,2858,2479,2971,1093,57,1720,1756,482,2599,2852,337,3278,93,2731,1278,1618,1379,1679,848,497,1327,1166,2402,3245,1235,1637,1331,3118,3301,3390,2009,3519,1152,1838,1563,3449,3478,1183,3349,2961,1341,3467,2448,1439,3277,3352,2888,397,486,2662,2144,1518,751,2604,2690,714,299,3246,172,2172,1945,2302,3545,2778,27,1633,2866,2567,2854,1315,3159,741,1867,118,442,120,2749,2918,3012,2989,352,1124,145,1322,660,618,1225,31,1281,876,943,3341,1949,1001,861,1103,2836,1846,2184,2613,3437,2492,1533,1754,3191,110,3324,2849,2490,3291,3093,3287,2756,3139,1044,1224,2708,2478,1194,1388,3039,3438,364,609,3234,3279,3290,3553,1482,3436,1851,228,3020,2237,1539,2840,1303,1403,2588,1956,2617,3285,1391,2768,2177,1121,1250,971,3001,2083,1958,1402,1837,2831,2910,1473,3394,1826,1487,1237,245,1273,2207,822,49,953,782,399,552,1119,3085,1321,1892,428,1222,1467,2427,2597,1842,3027,3103,1588,1209,3065,2630,3116,1147,783,3087,3584,2160,237,390,3357,1259,2833,1792,1576,3485,2804,2435,538,1948,136,1098,2468,501,1012,3131,3376,168,853,1660,2972,529,202,1629,2376,3284,711,420,3069,866,3,3265,2315,1662,602,1898,2203,438,2031,3259,3386,3539,2192,1558,1433,1438,1173,2683,1074,1375,1122,351,2382,2665,329,2032,16,1575,2674,3591,3298,616,1129,944,2791,1814,555,717,2825,346,545,2023,2618,3057,2287,875,1316,2168,1897,3062,647,1111,392,83,1667,3401,1484,1062,1666,1700,880,2321,1079,3481,2635,1862,3205,2173,89,2387,2072,248,1131,1048,3424,1169,584,2357,3492,2393,3000,3585,3091,836,833,1276,7,966,190,1125,2404,123,2317,1816,369,3314,2805,2137,927,2399,2071,1954,661,1600,1928,3183,1277,2633,2592,1729,1251,2340,1876,628,401,1612,2624,2969,561,872,1661,752,1593,2324,2161,595,693,3273,1463,1180,1579,1529,2186,2726,3271,720,750,2851,933,3023,2601,2982,1411,2288,1933,2692,1941,700,3015,2345,2947,1264,121,141,2556,2120,719,2409,2440,577,448,603,1246,1485,3169,3016,1577,2359,207,1016,2078,2916,2038,291,1513,70,2301,705,1797,2886,2024,2394,1457,2654,2934,2456,2197,3125,2351,646,2865,2039,2658,2373,3090,799,3097,2166,1936,114,3577,678,3572,1767,2553,2923,2827,2500,621,2979,2454,2847,585,2980,937,769,3249,3569,2925,1287,784,2789,893,1096,2367,2102,1407,2086,809,3184,881,2167,330,1971,1778,3359,3346,2275,954,3530,645,2748,1613,1940,1903,2801,2333,910,1367,1953,2187,3123,2299,2414,2214,936,2152,3200,3358,1583,3101,1301,2463,1977,1718,3580,1813,2381,965,3034,877,2055,1603,2709,1416,3576,226,1535,2619,922,1384,3422,2436,3155,1528,1658,3297,1768,3196,1437,78,790,1026,2248,1853,3426,1434,747,2477,3305,2533,2295,3453,2675,1421,1011,2325,1311,3272,1611,2297,1552,1689,461,449,2736,956,2857,3469,3006,787,657,92,3172,3342,527,217,1297,2596,2992,1910,850,15,1,2314,2520,2892,2088,3380,2213,3330,9,287,3276,3326,310,400,1284,1404,178,2819,749,1082,1922,3493,3463,1271,2848,1483,863,2061,3497,942,985,2631,574,1794,1086,204,2331,244,1212,1475,422,573,3441,104,566,634,97,1135,2390,205,1323,3188,1955,423,41,1436,2366,981,273,666,171,3306,1509,3362,2570,1359,2103,1983,2334,2832,845,2006,1522,2712,1866,3209,2703,1332,52,1412,873,1339,1075,1045,22,3147,3058,2266,1815,150,3124,378,3597,1334,191,322,1719,1179,2286,321,258,1090,1454,2891,2627,1181,1203,314,1531,1749,474,1462,311,2130,1877,39,3109,1744,2074,3221,3307,2450,2841,1976,2007,2884,3482,2073,1007,2485,684,2487,185,1638,1690,80,1652,175,2466,2407,1650,957,2081,2720,2612,451,1875,3225,3598,478,948,1937,490,824,868,358,1962,2968,2981,2154,1362,3133,466,2121,945,1994,2779,2557,2611,325,2725,3435,2915,2370,1915,2138,3202,1267,1819,1443,2058,1077,2181,2304,1773,1071,2374,1288,627,2591,715,111,3594,3168,3007,2555,3003,476,1785,1895,260,336,2439,709,766,1210,772,916,671,1675,467,3143,3137,2182,1227,1452,2348,2053,1394,587,1257,1554,101,3329,1376,1609,2641,2911,1357,1441,398,1479,1038,3063,2201,2080,2609,2420,2719,2360,3544,182,2668,925,2,327,271,1258,2224,2937,1480,2559,2437,3484,3132,1178,998,3369,3242,2494,266,96,2772,2252,3049,1219,34,1709,2877,3461,3022,1110,2855,1171,960,403,1964,890,1905,2777,1623,2395,3043,137,1930,3051,2069,3348,2338,1677,1648,3211,1742,1294,1556,746,415,1772,3502,1113,3498,2054,994,3400,1762,1734,441,3236,1076,2430,58,50,1506,1673,36,1469,1559,2117,3073,2452,156,1828,3465,3053,3566,2639,1500,344,1262,1428,1254,1157,1557,1163,1870,3547,431,493,1882,1694,2241,3522,2701,3194,1776,2311,2518,2084,539,1349,3045,452,1298,2389,2626,663,742,2689,955,1831,23,979,1836,642,1581,3323,509,716,429,1426,496,1589,1888,591,3540,348,157,1333,764,802,1963,2476,2733,1269,1283,413,1999,2568,1692,867,1829,559,106,2135,3554,2019,3418,2808,3570,28,2826,2648,1505,454,2047,2632,1647,2417,1481,3059,2107,1330,1138,1491,2679,905,2218,1896,1199,564,2811,1406,1564,450,3153,2270,680,2068,951,601,1054,808,2830,1548,1765,3170,113,3367,2116,565,2326,3160,2497,1730,88,1863,2878,1989,24,375,294,278,2529,2013,1781,232,1733,2742,580,2457,3332,26,1490,3115,1309,1065,598,3351,1770,3466,970,1395,1821,3350,3167,514,735,3046,3255,2905,1348,1172,1747,2920,147,2471,1769,2790,2139,2041,20,1952,891,2300,795,1864,1285,613,2176,638,2388,1196,1622,2473,676,612,2582,623,1811,2416,1670,396,2413,1356,1572,74,2157,3558,2411,3338,2707,2682,2110,2318,1337,918,2561,1519,1705,669,2164,1351,1604,2432,3416,1207,982,1665,2151,1063,3138,1523,2713,3235,1024,3575,972,2642,2879,3448,3495,3328,1982,2530,1627,1959,744,3240,3434,2129,1805,1723,1417,3280,2723,1493,2894,1713,76,900,2975,2433,854,10,760,100,3355,568,2546,1089,2147,2909,789,531,1415,46,307,3480,507,3164,2677,2419,3189,622,895,2488,2704,1174,3471,2465,1975,485,3248,3379,300,279,3474,1688,1192,170,286,2986,903,3303,3263,1128,2220,712,3315,2828,1621,1144,2343,491,2565,1305,578,729,3076,251,2483,1302,2767,818,3574,1164,2919,2946,1640,3267,525,1526,961,1004,857,2576,2917,470,2913,437,2496,723,144,1973,3210,2368,2282,2741,2651,2694,1512,2263,518,1605,381,3008,1201,95,225,2899,761,1699,368,1632,2251,2745,1502,3134,1991,640,1072,349,1511,1102,778,2802,852,388,1338,1051,1740,3450,1325,1114,1162,2153,2276,1845,3439,227,3464,3588,1549,252,2908,2669,2204,3286,1372,2540,2883,2523,3145,2146,946,1047,326,2558,238,724,889,3250,230,823,1154,2140,2199,1450,2575,511,1106,499,1361,1118,1389,3599,270,3538,3010,3256,253,2900,911,1865,102,515,1261,3311,3162,2093,1117,3431,264,3412,361,2230,2817,2403,208,3198,1693,1998,3274,2938,2267,473,3258,1055,842,2581,1541,148,2422,164,2702,379,79,1168,3215,1546,2535,1645,1466,261,855,1591,376,374]";
var keys=JSON.parse(json);
$button=document.getElementById("clarify");
$button.style.display="none";
var img=new Image();
img.onload=function(){
$button.style.display="block";
}
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/obfuscated.png";
function deobfuscate(obfuscatedImage,keys){
var tempCanvas=document.createElement("canvas");
var tempCtx=tempCanvas.getContext('2d');
tempCanvas.width=obfuscatedImage.width;
tempCanvas.height=obfuscatedImage.height;
var verticalSlices=keys.shift();
var horizontalSlices=keys.shift();
var sliceWidth=tempCanvas.width/verticalSlices;
var sliceHeight=tempCanvas.height/horizontalSlices;
for(var i=0;i<keys.length;i++){
var s=keys[i];
var row=parseInt(s/verticalSlices);
var col=s-row*verticalSlices;
var x=col*sliceWidth;
var y=row*sliceHeight;
var canvasRow=parseInt(i/verticalSlices);
var canvasCol=i-canvasRow*verticalSlices;
var canvasX=canvasCol*sliceWidth;
var canvasY=canvasRow*sliceHeight;
tempCtx.drawImage(obfuscatedImage,
canvasX,canvasY,sliceWidth,sliceHeight,
x,y,sliceWidth,sliceHeight);
}
return(tempCanvas);
}
$("#clarify").click(function(){
var canvas=deobfuscate(img,keys);
document.body.appendChild(canvas);
});
}); // end $(function(){});
</script>
</head>
<body>
<button id="clarify">De-obfuscate</button>
<p>The obfuscated image</p>
<img id="obfuscated" src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/obfuscated.png">
<p>The de-obfuscated canvas</p><br>
</body>
</html>
This code may help:
document.body.addEventListener('contextmenu', function(e) {
e.preventDefault();
});
This will disable context menu on a page. Instead of document.body you can write your canvas element:
document.getElementById('map_element').addEventListener('contextmenu', function(e) {
e.preventDefault();
});
where map_element is ID of the canvas element
UPDATE:
but even this protection might be broken by executing in browser console:
document.getElementById('map_element').toDataURL('image/jpeg');
I think the right decision is to download from server small regions of the map part by part
The first and the very simple way of doing that, would be the usage of HTML5
element {
background-image: url('../link/to_image.png');
}
Which won't be saved if the user right-clicks the image and clicks Save Image as...But still remember that the user can get the image from Inspector!
This way, the image won't be saved through right click atleast! And your map will be saved.
Second method is to use return of JS and stopping the event from occuring.
$('img').mousedown(function (e) { // mouse down on the image
if(e.button == '2') { // if right click
return false; // return nothing! :)
}
}
This is the easy way, since you won't be require to update the background-image everytime! But, use what you like! :)
No, there is no way you can prevent a user from saving what is already been downloaded to the browser.
You can make it "harder" for the user by adding a div on top over your canvas element and set its background to the image (or if possible just apply a css background to the canvas element itself).
You can disable the context menu as mentioned in another answer but the user can override this or use a browser that doesn't care (not sure if Opera has fixed this at the moment..).
You can also generate a bunch of layers and split your map file into many tiles, download those to the browser and draw a tile on separate layers. This is more complicated and makes it a bit more boring for the user to have to download all tiles and stitch them together.
But conclusively, no you can't prevent this - the user only need to go to console and network to find the downloaded image and save it out to the disk.

Using AngularJS with KineticJS

How can we bind (two-way) KineticJS Objects to some data with AngularJS ?
For example, bind a Kinetic Shape's position to a variable or textbox.
I've figured out how to do this without AngularJS :
(using KineticJS with jQuery)
box.on('dragmove', function() {
$('#pos_x').val( myShape.getX() );
$('#pos_y').val( myShape.getY() );
});
$('#pos_x').change(function() {
var x = parseInt( $('#pos_x').val() );
var y = parseInt( $('#pos_x').val() );
box.setPosition( x, y );
});
// and the same for $('#pos_y');
Code explanation:
There are a box and two textboxes.
When the box is dragged, box's coordinates will show on both textboxes.
When both textboxes' values are changed, the box's position will also change
but I wanted to know how to do that with AngularJS
(IMO, it will be much easier when you have a large number of objects, each with its own textboxes)
You have a few integration problems when trying to combine KineticJS with AngularJS
AngularJS is great at binding DOM elments.
But KineticJS objects are not DOM elements—they are just pixels on the canvas.
So AngularJS can’t control Kinetic objects directly.
To get Kinetic objects to move in response to text-input changes, you could use an AngularJS controller and make calls to the Kinetic object’s setX/setY.
To get text-input values to change as Kinetic objects are dragged, you might call the AngularJS controller from within a Kinetic dragmove event handler.
A complication is that by default, both Angular and Kinetic will want to control mouse events for their own purposes.
I'm not saying it can't be done, but...
Integrating KineticJS + AngularJS is more complicated than the Kinetic + jQuery method you’ve already got.
Before you give up on Kinetic + jQuery
Check out this code that integrates your Kinetic object and text-inputs.
You can quickly create as many shape+text pairs as you need.
And each pair is automatically integrated so that either dragging or text-input will move the shape and will show the current position in the text-input.
BTW, I used jQuery here for convenience, but you could very easily convert this to pure javascript and not need any external library at all.
Here’s code and a Fiddle: http://jsfiddle.net/m1erickson/X9QsU/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Prototype</title>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.7.0.min.js"></script>
<style>
body{background:ivory; padding:10px;}
#container{
border:solid 1px #ccc;
margin-top: 10px;
width:300px;
height:300px;
}
.boundXY{
width:105px;
height:23px;
color:white;
padding:5px;
border:2px solid lightgray;
}
</style>
<script>
$(function(){
var stage = new Kinetic.Stage({
container: 'container',
width: 300,
height: 300
});
var layer = new Kinetic.Layer();
stage.add(layer);
// each rect,textX,textY gets a unique id
var nextId=0;
// create some rect-textInput pairs in random colors
for(var i=0;i<6;i++){
randomPair();
}
function randomPair(){
var x=parseInt(Math.random()*250);
var y=parseInt(Math.random()*250);
var w=parseInt(Math.random()*40)+10;
var h=parseInt(Math.random()*40)+10;
addRectTextPair(nextId++,x,y,w,h,randomColor(),"lightgray");
}
function addRectTextPair(id,x,y,w,h,fill,stroke){
// new kinetic rect
var rect = new Kinetic.Rect({
id:"rect"+id,
x: x,
y: y,
width: w,
height: h,
fill: fill,
stroke: stroke,
strokeWidth: 3,
draggable:true
});
rect.on('dragmove', function() {
var id=this.getId().slice(4);
$('#x'+id).val( parseInt(this.getX()) );
$('#y'+id).val( parseInt(this.getY()) );
});
layer.add(rect);
// new div with same color as kinetic rect
var div = document.createElement("div");
div.id="div"+id;
div.className="boundXY";
div.style.background = fill;
div.innerHTML = "X/Y:";
// add xy text inputs
div.appendChild(newTextInput("x"+id,x));
div.appendChild(newTextInput("y"+id,y));
// add div to body
document.body.appendChild(div);
// change rect's X when the textInputX changes
$('#x'+id).change(function(e) {
var id=e.target.id.slice(1);
var rect=layer.get("#rect"+id)[0];
rect.setX( parseInt($(this).val()) );
layer.draw();
});
// change rect's Y when the textInputY changes
$('#y'+id).change(function(e) {
var id=e.target.id.slice(1);
var rect=layer.get("#rect"+id)[0];
rect.setY( parseInt($(this).val()) );
layer.draw();
});
layer.draw();
}
function randomColor(){
return('#'+Math.floor(Math.random()*16777215).toString(16));
}
function newTextInput(id,value){
var input=document.createElement("input");
input.id=id;
input.value=value;
input.type="text";
input.style.width="25px";
input.style.marginLeft="5px";
return(input);
}
$("#oneMore").click(function(){ randomPair(); });
}); // end $(function(){});
</script>
</head>
<body>
<p>Reposition rectangles by dragging or changing X/Y</p>
<button id="oneMore">Add another Rect and TextInput pair</button>
<div id="container"></div>
</body>
</html>

Canvas Clear in Paper.js

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();

Categories

Resources