343 lines
11 KiB
JavaScript
343 lines
11 KiB
JavaScript
define(function(){
|
|
/*
|
|
return the list of points ([ ['c', [x1, y1], [x2, y2] ], ...]) composing the path
|
|
*/
|
|
function analyse_path(path){
|
|
|
|
var returnValue = [];
|
|
for(var i = 0; i < path.length; i++){
|
|
var pat = path[i];
|
|
switch(pat[0]){
|
|
case 'a':
|
|
{
|
|
//elliptical arc
|
|
break;
|
|
}
|
|
case 't':
|
|
{
|
|
//Shorthand/smooth quadratic Bezier curveto
|
|
break;
|
|
}
|
|
case 'q':
|
|
{
|
|
//Quadratic Bezier curveto
|
|
break;
|
|
}
|
|
case 's':
|
|
{
|
|
//shorthand/smooth curveto
|
|
break;
|
|
}
|
|
case 'c':
|
|
{
|
|
//curveto
|
|
break;
|
|
}
|
|
case 'v':
|
|
{
|
|
//vertical lineto
|
|
throw 'file path "v" not supported yet.';
|
|
break;
|
|
}
|
|
case 'V':
|
|
{
|
|
//vertical lineto
|
|
throw 'file path "V" not supported yet.';
|
|
break;
|
|
}
|
|
case 'h':
|
|
{
|
|
//horizontal lineto
|
|
throw 'file path "h" not supported yet.';
|
|
break;
|
|
}
|
|
case 'H':
|
|
{
|
|
//horizontal lineto
|
|
throw 'file path "H" not supported yet.';
|
|
break;
|
|
}
|
|
case 'l':
|
|
{
|
|
//lineto
|
|
throw 'file path "l" not supported yet.';
|
|
break;
|
|
}
|
|
case 'L':
|
|
{
|
|
//lineto
|
|
returnValue.push({'x' : pat[1], 'y' : pat[2]});
|
|
break;
|
|
}
|
|
case 'Z':
|
|
case 'z':
|
|
{
|
|
//close path
|
|
//x1 = current point, x2 = first point
|
|
throw 'file path "Z" not supported yet.';
|
|
break;
|
|
}
|
|
case 'm':
|
|
case 'M':
|
|
{
|
|
//moveto
|
|
returnValue.push({'x' : pat[1], 'y' : pat[2]});
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return returnValue;
|
|
}
|
|
|
|
function parseVmlPathString(pathStr){
|
|
var matches = pathStr.match(/[A-z]?([^A-z\s])+\s([^A-z\s])+/g);
|
|
delete matches['input'];
|
|
delete matches['index'];
|
|
delete matches['lastIndex'];
|
|
var len = matches.length;
|
|
var path = [];
|
|
for(var i = 0; i < len; i++){
|
|
var pointStr = matches[i];
|
|
var replaced = false;
|
|
pointStr = pointStr.replace(/^[A-z]{1}/ig, function($0){
|
|
replaced = true;
|
|
return $0 + ' ';
|
|
});
|
|
var point = [];
|
|
if(!replaced){
|
|
point.push('L');
|
|
}
|
|
var coords = pointStr.split(' ');
|
|
for(var j = 0; j < coords.length; j++){
|
|
point.push(coords[j]);
|
|
}
|
|
path.push(point);
|
|
}
|
|
return path;
|
|
}
|
|
|
|
function visit_vml(element){
|
|
|
|
var store = new Array();
|
|
if((typeof(element) === 'object') && (element.length)){
|
|
for(var i = 0; i < element.length; i++){
|
|
store = store.concat(visit_vml(element[i]));
|
|
}
|
|
}else{
|
|
switch(element.type){
|
|
case 'path':
|
|
{
|
|
var pathString = element.attrs.path;
|
|
var pathArray = parseVmlPathString(pathString);
|
|
store.push(['path_s', analyse_path(pathArray), element]);
|
|
break;
|
|
}
|
|
case 'circle':
|
|
{
|
|
store.push(['circle', {
|
|
radius : element.attrs.r,
|
|
cx : element.attrs.cx,
|
|
cy : element.attrs.cy
|
|
}, element]);
|
|
break;
|
|
}
|
|
case 'ellipse':
|
|
{
|
|
store.push(['ellipse', {
|
|
rx : element.attrs.rx,
|
|
ry : element.attrs.ry,
|
|
cx : element.attrs.cx,
|
|
cy : element.attrs.cy
|
|
}, element]);
|
|
break;
|
|
}
|
|
case 'rect':
|
|
{
|
|
var point_list = [{
|
|
x : element.attrs.x,
|
|
y : element.attrs.y
|
|
}, {
|
|
x : element.attrs.x + element.attrs.width,
|
|
y : element.attrs.y
|
|
},
|
|
{
|
|
x : element.attrs.x + element.attrs.width,
|
|
y : element.attrs.y + element.attrs.height
|
|
}, {
|
|
x : element.attrs.x,
|
|
y : element.attrs.y + element.attrs.height
|
|
}, ];
|
|
//store.push(['rect',[s1,s2,s3,s4],point_list,element]);
|
|
store.push(['rect', point_list, element]);
|
|
break;
|
|
}
|
|
}//end switch
|
|
}
|
|
return store;
|
|
}
|
|
|
|
|
|
function find_curves_in_path(path)
|
|
{
|
|
var found = false;
|
|
var i = 0;
|
|
var l = path.length;
|
|
while((!found) && (i < l)){
|
|
if(path[i][0] in ['a', 'A', 'c', 'C', 's', 'S', 'q', 'Q', 't', 'T']){
|
|
}
|
|
i++;
|
|
}
|
|
return found;
|
|
}
|
|
|
|
|
|
function visit_svg(element){
|
|
|
|
var store = [];
|
|
if((typeof(element) == 'object') && (element.length)){
|
|
for(var i = 0; i < element.length; i++){
|
|
store = store.concat(visit_svg(element[i]));
|
|
}
|
|
}else{
|
|
switch(element.type){
|
|
case 'path':
|
|
{
|
|
var path = analyse_path(element.attrs.path);
|
|
if(find_curves_in_path(element.attrs.path)){//path with curves
|
|
store.push(['path_c', path, element]);
|
|
}else{//path only made of segments (polygon)
|
|
store.push(['path_s', path, element]);
|
|
}
|
|
break;
|
|
}
|
|
case 'circle':
|
|
{
|
|
store.push(['circle', {
|
|
radius : element.attrs.r,
|
|
cx : element.attrs.cx,
|
|
cy : element.attrs.cy
|
|
}, element]);
|
|
break;
|
|
}
|
|
case 'ellipse':
|
|
{
|
|
store.push(['ellipse', {
|
|
rx : element.attrs.rx,
|
|
ry : element.attrs.ry,
|
|
cx : element.attrs.cx,
|
|
cy : element.attrs.cy
|
|
}, element]);
|
|
break;
|
|
}
|
|
case 'image':
|
|
case 'rect':
|
|
{
|
|
var point_list = [
|
|
{x : element.attrs.x, y : element.attrs.y},
|
|
{x : element.attrs.x + element.attrs.width, y : element.attrs.y},
|
|
{x : element.attrs.x + element.attrs.width, y : element.attrs.y + element.attrs.height},
|
|
{x : element.attrs.x, y : element.attrs.y + element.attrs.height}
|
|
];
|
|
store.push(['rect', point_list, element]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
return store;
|
|
}
|
|
|
|
function populate_polygons(raph, element_list)
|
|
{
|
|
var polygons = new Array();
|
|
if(raph.raphael.svg){//svg
|
|
polygons = visit_svg(element_list);
|
|
}else{//vml
|
|
polygons = visit_vml(element_list);
|
|
}
|
|
return polygons;
|
|
}
|
|
|
|
|
|
var raphaelcollision = function raphaelcollision(raph, element_list, x, y)
|
|
{
|
|
var ret = [];
|
|
|
|
var polygons = populate_polygons(raph, element_list);
|
|
|
|
var l = polygons.length;
|
|
for(var f = 0; f < l; f++){
|
|
|
|
var poly = polygons[f];
|
|
switch(poly[0]){//type
|
|
case 'circle':
|
|
{
|
|
if(collide_circle(poly[1], x, y)){//shapeData
|
|
ret.push(poly);
|
|
}
|
|
break;
|
|
}
|
|
case 'ellipse':
|
|
{
|
|
if(collide_ellipse(poly[1], x, y)){
|
|
ret.push(poly);
|
|
}
|
|
break;
|
|
}
|
|
case 'path_s':
|
|
case 'rect':
|
|
{
|
|
if(collide_polygon(poly[1], x, y)){//poly[1] : point list
|
|
ret.push(poly);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
throw 'unknown type : ' + poly[0];
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
poly = list of points : [{x:2,y:4}, {x:5,y:1}, ...]
|
|
poly.length = number of segments
|
|
*/
|
|
function collide_polygon(poly, x, y){
|
|
|
|
var c = false;
|
|
var points = [];
|
|
var l = poly.length;
|
|
for(var i = 0; i < l; i++){
|
|
if(poly[i] != null){
|
|
points.push(poly[i]);
|
|
}
|
|
}
|
|
|
|
l = points.length;
|
|
var j = l - 1;
|
|
for(var i = -1; ++i < l; j = i){
|
|
var cond1 = (points[i].y <= y && y < points[j].y);
|
|
var cond2 = (points[j].y <= y && y < points[i].y);
|
|
var cond3right = parseInt((points[j].x - points[i].x) * (y - points[i].y) / (points[j].y - points[i].y)) + parseInt(points[i].x);
|
|
var cond3 = (x < cond3right);
|
|
if((cond1 || cond2) && cond3){
|
|
c = !c;
|
|
}
|
|
}
|
|
|
|
return c;
|
|
}
|
|
|
|
function collide_circle(circle, x, y){
|
|
return (circle.radius > Math.sqrt(Math.pow((circle.cx - x), 2) + Math.pow((circle.cy - y), 2)));
|
|
}
|
|
|
|
function collide_ellipse(ellipse, x, y){
|
|
return (Math.pow((x - ellipse.cx), 2) / Math.pow(ellipse.rx, 2) + Math.pow((y - ellipse.cy), 2) / Math.pow(ellipse.ry, 2) <= 1);
|
|
}
|
|
|
|
return raphaelcollision;
|
|
}); |