Draw on top of an image using javascript - javascript

For a certain image I have a list containing the pixel coordinates of all the points in a polygon segmenting all the objects it contains (look at the image below).
For instance, for the person I have a list l1 = [x0,y0,x1,y1,...,xn,yn], for the cat a list l2 = [x0',y0',x1',y1',...,xk',yk'], and similarly for all the objects.
I have 2 questions:
What is the best javascript library to use to draw on top of an image? Given the raw image I would like to obtain the result seen below.
I would like each segmentation to be visualized only when the mouse hovers on top of it. For this I believe I should bind this drawing function to the mouse position.
I'm thinking at something with the structure below but don't know how to fill the gaps, could you please give me some indication?
$(.container).hover( function(e) {
//get coordinates of mouse
//if mouse is over one object
//draw on top of image the segmentation for that object
});
container is the class of the div containing the image so I should be able to get the coordinates of the mouse since the image starts at the top left corner of the container div.

Simply rebuild the polygons from each array and do a hit test using the mouse position.
First: If you have many arrays defining the shapes it could be smarter to approach it in a more general way instead of using variables for each array as this can soon be hard to maintain. Better yet, an object holding the array and for example id could be better.
Using an object you could do - example:
function Shape(id, points, color) {
this.id = id;
this.points = points;
this.color = color;
}
// this will build the path for this shape and do hit-testing:
Shape.prototype.hitTest = function(ctx, x, y) {
ctx.beginPath();
// start point
ctx.moveTo(this.points[0], this.points[1]);
// build path
for(var i = 2, l = this.points.length; i < l; i += 2) {
ctx.lineTo(this.points[i], this.points[i+1]);
}
ctx.closePath();
return ctx.isPointInPath(x, y);
};
Now you can create new instances with the various point arrays like this:
var shapes = [];
shapes.push(new Shape("Cat", [x0,y0,x1,y1, ...], "rgba(255,0,0,0.5)");
shapes.push(new Shape("Woman", [x0,y0,x1,y1, ...], "rgba(0,255,0,0.5)"));
...
When you get a mouse position simply hit-test each shape:
$(".container").hover( function(e) {
//get corrected coordinates of mouse to x/y
// redraw canvas without shapes highlighted
for(var i = 0, shape; shape = shapes[i]; i++) { // get a shape from array
if (shape.hitTest(ctx, x, y)) { // is x/y inside shape?
ctx.fillStyle = shape.color; // we already have a path
ctx.fill(); // when testing so just fill
// other tasks here...
break;
}
}
});

check this Link it might be slow your problem.
Include necessary javascript library files
jquery.min.js,raphael.min.js,json2.min.js,raphael.sketchpad.js
To create an editor
<div id="editor"></div>
<form action="save.php" method="post">
<input type="hidden" name="data" />
<input type="submit" value="Save" />
</form>
<script type="text/javascript">
var sketchpad = Raphael.sketchpad("editor", {
width: 400,
height: 400,
editing: true
});
// When the sketchpad changes, update the input field.
sketchpad.change(function() {
$("#data").val(sketchpad.json());
});
</script>

Related

Find an image in a canvas by coordinates

Edit:
1) basically I would like to know if there is a way to know if in an html canvas there is an image in a given point.
var point = [5, 8]
there is an image on that point? there is a command for find out?
2) the canvas is an hex map so the images are on regular positions in the grid. They can't be halfway. So a generic point can be brought back to the insertion point for the image and the question become: there is a (fast) way to know if in an html canvas there is an image with a given insertion point?
3) can help if I'm using Raphael?
4) I have a working solution: to confront the (x, y) attributes (insertion point) of ALL the images with the coordinates of point, but it's very slow. I'm looking for something faster. If you are interessed in my solution, read below. Comment and improvement on my solution are welcome but my question is different: I'm looking for a different solution and specifically I'm looking for the answers to my questions above.
/edit
I have an hex map and I want to find which images are in an exe given the exe coordinates.
My code is working but I hope for something more efficient.
To be precise when i click on an exe I want to know if in the six border exes there is a specific image. Read the comment in the code
My javascript:
var paper_map = Raphael(canvas_map, '100%', '100%');
var Image = paper_map.image(path_image, x-16, y-14, width, high);
[...]
var border_list=find_border_list(col, row)
//find_border_list function gives a list of coordinates for the 6 border exes [[c1, r1], ... [c6, r6]]
var my_exe_list=[];
for (var i=0; i<border_list.length; i++ ) {
var coord = number_to_coord(border_list[i][0], border_list[i][1]);
//number_to_coord function transforms coordinates (column, row) in (x,y)
var x = coord[0]-16; //I find the coordinates of the 'corner' of the exe
var y = coord[1]-14;
//each image is drawed starting from a 'corner' of an exe
var child_list=canvas_map.lastElementChild.childNodes;
//here's my problem: this list is huge because it contains all the images of the canvas!!
for (var j=2; j<child_list.length; j++){
if (child_list[j].tagName == 'image') {
if (child_list[j].attributes.x.value==x &&
child_list[j].attributes.y.value==y &&
child_list[j].href.baseVal.slice(child_list[j].href.baseVal.lastIndexOf('/')+1).startsWith('mystring')) {
//the first two conditions find all the images on my exe, the third find which I'm interessed in (based on the name)
my_exe_list.push(child_list[j])
};
};
};
};
My html:
<div id='canvas_map' class='canvas can_map' style='position:absolute; left:133px; top:0px;'></div>
console.log(canvas_map) = <div id="canvas_map" class="canvas can_map" style="position: absolute; left: 133px; top: 0px; height: 520px; width: 1371px;">
console.log(child_list) = NodeList [ <desc>, <defs>, <image>, <image>, <image> ... ]
console.log(child_list[j]) = <image x="53" y="56" width="33" height="27" preserveAspectRatio="none" href="/my/path/image_name.png">
So the problem is I cycle six times in a very long list (could be some thousands of images):
var child_list=canvas_map.lastElementChild.childNodes;
Just to know I draw the images with Raphael and I can use jquery.

Leaflet: Fading in/out layer groups efficiently

I've got a Leaflet map with a single tile layer and then a LayerGroup (densityLayer) consisting of many (typically a few hundred) Rectangle layers, each of which is a semitransparent filled overlay with its fillColor based on population density for a particular year.
Based on a user action, the contents of densityLayer change. Pretty trivial to just run densityLayer.clearLayers() then generate all the new Rectangle layers and densityLayer.addLayer(aRectangle) for each of them.
What I want to do, though, is to animate a fade from the old to the new data: i.e., generate all the new Rectangle layers and put them in a new LayerGroup (newDensityLayer), and simultaneously fade out the original oldDensityLayer and fade in the newDensityLayer, and when the fade is complete, then clear out and remove oldDensityLayer and replace it with newDensityLayer.
My current solution is hideously inefficient:
var oldDensityLayer = densityLayer
var newDensityLayer = {...create new density layer here, add polygons, etc...}
oldDensityLayer.eachLayer(function(l) {
$(l._path).fadeOut(1000) // 1000ms animation time
})
setTimeout(function() {
oldDensityLayer.clearLayers()
myLeafletMap.removeLayer(oldDensityLayer)
oldDensityLayer = null
}, 1000)
myLeafletMap.addLayer(newDensityLayer)
// now fade in all the new polygons
newDensityLayer.eachLayer(function(l) {
$(l._path).hide() // so they start out invisible
$(l._path).fadeIn(1000)
})
densityLayer = newDensityLayer
This basically works, but gets pretty choppy and slow on anything but a very fast machine.
Is there some way to fade in/out an entire LayerGroup, or perhaps some option I haven't considered...?
This is critical functionality, so if adding another js library would help, that's fine. Also, SVG-specific answers are fine, as that's what I've got Leaflet using for its drawing functions, and cross-browser compatibility isn't a concern in this application.
Is there some way to fade in/out an entire LayerGroup, or perhaps some option I haven't considered...?
There is, in fact, an option which you haven't considered: manipulate the L.Renderer which actually draws the geometries as an HTML element. This means manipulating the actual <canvas> of a L.Canvas, or the actual <svg> of a L.SVG.
Remember any subclass of L.Path (Polygons, Polylines and such) can have its own renderer. Leaflet, by default, creates just one instance of L.Renderer and reuses it in all L.Paths unless told otherwise - this means less HTML elements and (in 99% of use cases) better performance.
So it should look something like:
var rendererA = L.canvas();
var rendererB = L.canvas();
var groupA = L.layerGroup().addTo(map);
var layerA1 = L.polygon(…, {renderer: rendererA}).addTo(groupA);
var layerA2 = L.polygon(…, {renderer: rendererA}).addTo(groupA);
var groupB = L.layerGroup().addTo(map);
var layerB1 = L.polygon(…, {renderer: rendererB}).addTo(groupB);
var layerB2 = L.polygon(…, {renderer: rendererB}).addTo(groupB);
// Here comes the magic - using the *undocumented*, *private* _container
// property of L.Canvas to access the <canvas> HTML element itself
rendererA._container.style.opacity = 0.5;
The code is obviously incomplete, but it should illustrate the idea properly.
That will create two different <canvas> in the browser, and changing the opacity of the HTML element itself will bypass re-rendering the features. There should be an analogous solution using L.SVG instead, but I'm not sure how browsers composite the opacity of SVG containers.
There are obvious disadvantages for this method - like losing any z-ordering (bringToFront, etc) if geometries from both groups should be intertwined.
Also, please remember: Using undocumented, private properties of leaflet objects is not recommended unless you really really really know what you're doing and are willing to see your code break in API changes or rare circumstances.
You could include an SVG layer populated with your shapes. Below in an example that fades out 500 svg shapes, then builds a new bunch of SVG shapes and fades them in. (Edited to zoom shapes at their locations)
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Fade Out/In SVG Elements in Leaflet World Map</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src='https://api.tiles.mapbox.com/mapbox.js/v2.1.5/mapbox.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox.js/v2.1.5/mapbox.css' rel='stylesheet' />
</head>
<body style='font-family:arial'>
<center><h4>Fade Out/In SVG Elements in Leaflet World Map</h4>
<div style='width:90%;background-color:gainsboro;text-align:justify;padding:10px;border-radius:6px;'>
This adds 500 svg elements(circles, ellipses, rects, polygons) to the SVG layer in the world map. The map's mouse wheel zoom remains smooth in IE/CH/FF. Each element has a lat/lng value, converted to the needed x,y values to translate each symbol to the desired point.
During map zoom level changes, the symbols are automatically scaled and translated, maintaining their original size and position.
</div>
<br />
<table border=1>
<tr>
<td>
<b>Scenerio:</b><br />
1). The map is placed into its DIV (width:800px, height:400px).<br />
2). The map is centered at Lat/Lng (0,0) at zoom level 1.<br />
3.) The SVG element is added via <b>initPathRoot.</b><br />
4.) 500 SVG elements are added, randomly place about the world.<br />
5.) The svg <b>viewBox</b> is computed, used to create x,y values for the symbols.<br />
6.)Each element is translated/scaled when the map is zoomed, using the <b>viewreset</b> event.<br /> This calls the map method <b>latLngToLayerPoint(MyLatLng)</b> to accomplish this.
<br>7.) Select <button>fade out/in</button> to fade out the current elements, build a new group, then fade In new group
</td>
</tr>
</table>
<div style='width:800px;height:400px' id='MyMap'></div>
<button onClick=fadeOutIn()>fade out/in</button>
<br />Javascript:<br />
<textarea spellcheck=false id=jsValue style='border-radius:26px;font-size:110%;font-weight:bold;color:midnightblue;padding:16px;background-color:beige;border-width:0px;font-size:100%;font-family:lucida console;width:90%;height:400px'></textarea>
</center>
<script id=myScript>
L.mapbox.accessToken = 'pk.eyJ1IjoiZmhlbXNoZXIiLCJhIjoiODQ5MW9WayJ9.px2P6wVMFucfXHE1zmDA1A';
MyMap = L.mapbox.map('MyMap', 'mapbox.streets', { zoomControl:false,center: new L.latLng(0,0),zoom:1,minZoom:1});
//---zooming the map---
MyMap.on("viewreset", adjustSVGSymbols);
var MySVG
var SymbolG //---<g> element containing all symbols---
var VBw
var VBh
var NS="http://www.w3.org/2000/svg"
//---body onload---
function initSVG()
{
MyMap._initPathRoot() //---creates an svg layer---
MySVG=document.querySelector("svg") //---access svg element---
//---place symbols in here---
SymbolG=document.createElementNS(NS,"g")
SymbolG.setAttribute("id","symbolG")
MySVG.appendChild(SymbolG)
//---create random svg elements, place in SymbolG--
getViewBox()//---used to place svg random elements
//---create 500 symbols at size 10 pixels--
svgGLOB(500,10)
}
//--- on map zoom - fired via map event: viewreset---
function adjustSVGSymbols()
{
var symbols=SymbolG.childNodes
for(var k=0;k<symbols.length;k++)
{
var symbol=symbols.item(k)
//---initial lat/lng for symbol---
var lat=parseFloat(symbol.getAttribute("lat"))
var lng=parseFloat(symbol.getAttribute("lng"))
var latLng= new L.latLng(lat, lng)
var transX=MyMap.latLngToLayerPoint(latLng).x
var transY=MyMap.latLngToLayerPoint(latLng).y
//---scale---
var initZoom=parseFloat(symbol.getAttribute("initZoom"))
var scale = (Math.pow(2, MyMap.getZoom())/2)/(Math.pow(2, initZoom)/2);
//---trash previous transform---
symbol.setAttribute("transform","")
symbol.removeAttribute("transform")
var transformRequestObj=MySVG.createSVGTransform()
var animTransformList=symbol.transform
//---get baseVal to access/place object transforms
var transformList=animTransformList.baseVal
//---translate----
transformRequestObj.setTranslate(transX,transY)
transformList.appendItem(transformRequestObj)
transformList.consolidate()
//---scale---
transformRequestObj.setScale(scale,scale)
transformList.appendItem(transformRequestObj)
transformList.consolidate()
}
}
//---needed for random symbol placement: create x,y values---
function getViewBox()
{
vb=MySVG.viewBox.baseVal
VBw=vb.width
VBh=vb.height
}
//---compute svg elems: circles, rects, ellipses, polygons---
function svgGLOB(elems,elemSize)
{
//---note: each browser creates a different sized svg layer---
var svgWidth=VBw
var svgHeight=VBh
//---obtain a random whole number from a thru b---
function rdm(a,b)
{
return a + Math.floor(Math.random()*(b-a+1));
}
function randomPoints(elems,svgWidth,svgHeight,elemSize)
{
//--return format:[ [x,y],[x,y],,, ]
//---Generate random points---
function times(n, fn)
{
var a = [], i;
for (i = 0; i < n; i++)
{
a.push(fn(i));
}
return a;
}
var width=svgWidth-2*elemSize //---offset from edge---
var height=svgHeight-2*elemSize //---offset from edge---
return RandomPnts = times(elems, function() { return [Math.floor(width * Math.random()) + elemSize, Math.floor(height * Math.random()) + elemSize] });
}
//---random color---
function rcolor()
{
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++ )
{
color += letters[Math.round(Math.random() * 15)];
}
return color;
}
function polygon(vCnt,radius,centerX,centerY)
{
var myPoints=[]
var polyXPts = Array(vCnt);
var polyYPts = Array(vCnt);
var vertexAngle = 360/vCnt;
//---init polygon points processor---
for(var v=0; v<vCnt; v++)
{
theAngle = (v*vertexAngle)*Math.PI/180;
polyXPts[v] = radius*Math.cos(theAngle);
polyYPts[v] = -radius*Math.sin(theAngle);
}
//--note points are CCW---
for(var v=0;v<vCnt; v++)
{
var point=[centerX+polyXPts[v],centerY+polyYPts[v]]
myPoints.push(point)
}
return myPoints
}
var Points=randomPoints(elems,svgWidth,svgHeight,elemSize)
var n=Points.length
var circleCnt=0
var ellipseCnt=0
var rectCnt=0
var polygonCnt=0
var RandomElems=[]
RandomElems[0]="circle"
RandomElems[1]="rect"
RandomElems[2]="ellipse"
RandomElems[3]="polygon_3"
RandomElems[4]="polygon_4"
RandomElems[5]="polygon_5"
RandomElems[6]="polygon_6"
RandomElems[7]="polygon_7"
RandomElems[8]="polygon_8"
RandomElems[9]="polygon_9"
RandomElems[10]="polygon_10"
RandomElems[11]="polygon_11"
RandomElems[12]="polygon_12"
//---create all at center(0,0), then translate---
for(var k=0;k<n;k++)
{
var rand=rdm(0,12)
var elemStr=RandomElems[rand]
if(!elemStr.indexOf("_"))
var elemSt=elemStr
else
var elemSt=elemStr.split("_")[0]
//var elem=document.createElementNS(NS,elemSt)
var x=Points[k][0]
var y=Points[k][1]
var lng=((x * 360 / VBw) - 180)
var lat= (90 - (y * 180 / VBh))
var id="symbol"+k
var fill=rcolor()
var elem=document.createElementNS(NS,elemSt)
elem.setAttribute("id",id)
elem.setAttribute("cursor","default")
elem.setAttribute("fill",fill)
elem.setAttribute("lat",lat)
elem.setAttribute("lng",lng)
if(elemSt=="circle")
{
var r=elemSize
elem.setAttribute("r",r)
}
else if(elemSt=="ellipse")
{
var rx=elemSize
var ry=elemSize/2
elem.setAttribute("rx",rx)
elem.setAttribute("ry",ry)
}
else if(elemSt=="rect")
{
var width=elemSize
var height=elemSize
//---center at 0,0---
var x=-elemSize/2
var y=-elemSize/2
elem.setAttribute("width",width)
elem.setAttribute("height",height)
elem.setAttribute("x",x)
elem.setAttribute("y",y)
}
else if(elemSt=="polygon")
{
var pgonSides=parseInt(elemStr.split("_")[1])
var pgonPnts=polygon(pgonSides,elemSize,0,0)
var points=pgonPnts.join()
elem.setAttribute("points",points)
}
elem.setAttribute("initZoom",1)
SymbolG.appendChild(elem)
}
//---initialize locations---
adjustSVGSymbols()
}
//---fade out/In button----
function fadeOutIn()
{
$("#symbolG").fadeOut(1000, function(){
createAnotherGlob()
});
}
function createAnotherGlob()
{
var symbols=SymbolG.childNodes
for(var k=symbols.length-1;k>=0;k--)
SymbolG.removeChild(symbols.item(k))
svgGLOB(500,10,true)
$("#symbolG").fadeIn(1500)
}
</script>
<script>
document.addEventListener("onload",init(),false)
function init()
{
jsValue.value=myScript.text
initSVG()
}
</script>
</body>
</html>

Drawing a timeline from div to div with canvas

I have the following div markup
<div data-x="-1000" data-y="-1500">
// content
</div>
<div data-x="0" data-y="-1500">
// content
</div>
And I have many of this divs with different data-x and data-y value depending on their position.
What I want to achieve here is to draw something like a timeline between the divs so div1 line to div2 line to div 3 etc,,
I want this to be done automatically So I am trying to make a loop for it but my javascript/jquery knowledge is not that good. Could someone point me in the good direction?
what I have now is
function drawTimeline() {
var divs = document.getElementsByTagName('div');
var canvas = document.getElementById('timeline');
// Make sure we don't execute when canvas isn't supported
if (canvas.getContext){
// use getContext to use the canvas for drawing
var ctx = canvas.getContext('2d');
var prevCoord = {};
for (var i = -1; div = divs[++i]; ) {
if (div.dataset.x && div.dataset.y) {
var x = parseInt(div.dataset.x);
var y = parseInt(div.dataset.y);
if ({} !== prevCoord) {
ctx.beginPath();
ctx.lineWidth="5";
ctx.strokeStyle="purple"; // Purple path
ctx.moveTo(prevCoord.x, prevCoord.y);
ctx.lineTo(x, y);
ctx.closePath();
ctx.stroke()
}
prevCoord.x = x;
prevCoord.y = y;
}
}
} else {
alert('You need Safari or Firefox 1.5+ to see this.');
}
}
unfortunately the line is not correct its like a linear line and thats it.. can someone help me out with this?
You have the right idea, but your problem is that canvas does not draw at negative coordinates.
Therefore, you must map all your data-x and data-y into positive coordinates.
Here's a function that maps your negative values into positive values:
function mapRange(value, sourceLow, sourceHigh, mappedLow, mappedHigh) {
return mappedLow + (mappedHigh - mappedLow) * (value - sourceLow) / (sourceHigh - sourceLow);
}
So in your example to map a data-x value of -300 into an onscreen range of 0-1000 can do this:
var x = mapRange(-300, -1500,0, 0,1000); // The mapped x is 466.66.
You must reposition your divs to the mapped x,y coordinates which you can do with CSS.
An alternative is to use SVG which creates actual DOM elements that can be positioned at negative coordinates.

Canvas and objects

I'm experimenting with canvas and javascript and was wondering if there was a way to group objects together so they can be treated as a single object within one canvas. So, as a very simple example, say I have a filled circle surrounded by a larger unfilled circle. Now, assume I have 10 of these. I want to move each set separately so is there a way to group each set together as a single object? I don't want to have to make a call to move each object separately.
My example above is a little simple as I actually have 10 or 11 objects grouped together in each cluster. Moving each object in the cluster separately is a pain so I'd like to be able to be able to group them together and make one call to move them.
Any suggestions would be appreciated!
You can use canvas’ “translate” function to draw your circle-group without recalculating!
Location is made simpler for groups when you use a “tranlslate”.
A translate is just the “behind-the-scenes” math that drags your entire group to a new location on the canvas.
You don’t have to do separate calculations for each of your circles. Instead you just do a translate and then draw your circles as if they were in their starting positions.
This is how to impliment translate:
// do a translate to mouseX,mouseY
// all draws will be now be done RELATIVE to mouseX,mouseY
// so if we ctx.translate(100,100)
// then a ctx.rect(0,0,10,10) will actually be drawn at 100,100
ctx.translate(mouseX,mouseY);
// draw the ball group
// notice we didn't have to calculate ANY new positions!!
drawBallGroup();
// translate back after we're done
ctx.translate(-mouseX,-mouseY);
Here’s code and a Fiddle: http://jsfiddle.net/m1erickson/4rJgw/
<!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:10px; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
drawBallGroup();
function drawBallGroup(){
drawBall(8,10,5,"red");
drawBall(20,15,10,"green");
drawBall(25,25,8,"blue");
drawBall(5,22,10,"orange");
drawBall(18,30,10,"black");
}
function drawBall(x,y,radius,color){
ctx.beginPath();
ctx.fillStyle=color;
ctx.arc(x,y,radius, 0, 2 * Math.PI, false);
ctx.fill();
}
function handleMouseDown(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// clear the canvas
ctx.clearRect(0,0,canvas.width,canvas.height);
// do a translate to mouseX,mouseY
// all draws will be now be done RELATIVE to mouseX,mouseY
// so if we ctx.translate(100,100)
// then ctx.rect(0,0,10,10) will actually be drawn at 100,100
ctx.translate(mouseX,mouseY);
// draw the ball group
// notice we didn't have to calculate ANY new positions!!
drawBallGroup();
// translate back after we're done
ctx.translate(-mouseX,-mouseY);
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
}); // end $(function(){});
</script>
</head>
<body>
<p>Click to move the ball group to a new location</p>
<p>WITHOUT recalculating each new ball position!</p><br/>
<canvas id="canvas" width=400 height=500></canvas>
</body>
</html>
As pointed out in the comments, there's nothing in the Canvas API which supports grouping of objects. However, there are various libraries for Canvas which you could look into which support this type of functionality. This stackoverflow question might be a good place to start investigating.
easel.js, for example, supports the nesting and grouping of objects. If you're familiar with the ActionScript displayList you'll find it really intuitive as the API is very similar.
Your example of grouping an outer and inner circle and manipulating it as a single object would look something like this with easel:
// Create a stage by getting a reference to the canvas
var stage = new createjs.Stage("canvas");
// Create a container for the circle.
var circle = new createjs.Container();
// Create the outer circle
var outerCircle = new createjs.Shape();
outerCircle.graphics.beginFill("red").drawCircle(0, 0, 40);
// Create the inner circle
var innerCircle = new createjs.Shape();
innerCircle.graphics.beginFill('green').drawCircle(0, 0, 30);
// Add inner and outer circles instance to circle container
circle.addChild(outerCircle);
circle.addChild(innerCircle);
// Now we can move the circle container and its children as a single object
circle.x = circle.y = 40;
// Add circle container instance to stage display list.
stage.addChild(circle);
// Update stage will render next frame
stage.update();
I did something similar recently and I solved this by drawing the group of objects to an off screen (in memory) canvas. Moving this canvas essentially moves the "group".
Depending on what your actual goal is, this may be inflexible - but it's another option to consider.
Well, you could put all your objects in one array and then make a loop, like this:
var objects = [
{x: 200, y: 130, radius: 36, color: "red"}
,
{x: 150, y: 80, radius: 31, color: "blue"}
,
{x: 20, y: 210, radius: 22, color: "green"}
];
for (var i = 0; i < objects.length; i++) {
context.beginPath();
context.arc(objects[i].x, objects[i].y, objects[i].radius, 0, Math.PI * 2, false);
context.fillStyle = objects[i].color;
context.fill();
context.closePath();
}
:D

With paper.js inserting pointtext to canvas pushes other items away

I'm trying to create a rectangle and a pointtext element, where the rectangle will be the
text element's container.
Without text element, everything works fine. When text element inserted, rectangle is pushed away. Well, rectangle is displayed at the correct position, but the points where it receives the events are pushed away.
Please see http://jsbin.com/abejim/1
Rectangle's visibility should increase when hovered. Hovering does not affect, but when mouse moved to 580,280 and around , it's visibility increases.
Any suggestions?
That jsbin seems to be working fine for me in Firefox. The rectangle is displayed in the correct location and hovering over the rectangle makes it highlight. Possibly the paper.js code has updated since you asked the question.
It looks like you asked the same question on the paper.js mailing list. For future reference here, the response was:
pointtext takes relative coordinates and you r trying to give absolute coordinates.
try this one:
var size = new paper.Size(125, 75); //SM size to paper size
var rectangle = new paper.Rectangle({ x: 0, y: 0 }, size); //(top_left, bottom_right)
var cornerSize = new paper.Size(10, 10); //rounding of edges
var shape = new paper.Path.RoundRectangle(rectangle, cornerSize);
shape.strokeWidth = 3;
shape.strokeColor = '#525252';
shape.fillColor = '#FFFFFF';
shape.name = 'shape';
var stateNameTxt = new paper.PointText(10, 65);
stateNameTxt.content = state_name;
stateNameTxt.name = 'stateNameTxt';
var state = new paper.Group(); //create group
state.name = state_name;
state.opacity = 0.8;
state.addChild(shape); //add shape to grpup
state.addChild(stateNameTxt); //add pointtext to group

Categories