Merge pull request #24 from alexarchambault/develop

Develop
This commit is contained in:
Alexandre Archambault 2015-06-17 20:39:57 +02:00
commit 3bcc99a53a
13 changed files with 81 additions and 10247 deletions

View File

@ -4,8 +4,6 @@ package core
import java.io._
import java.net.URL
import org.http4s.{EntityDecoder, Status, Uri}
import scala.annotation.tailrec
import scala.io.Codec
import scalaz._, Scalaz._
@ -18,7 +16,7 @@ trait ArtifactDownloaderLogger {
def downloadedArtifact(url: String, success: Boolean): Unit
}
case class ArtifactDownloader(root: Uri, cache: File, logger: Option[ArtifactDownloaderLogger] = None) {
case class ArtifactDownloader(root: String, cache: File, logger: Option[ArtifactDownloaderLogger] = None) {
var bufferSize = 1024*1024
def artifact(module: Module,
@ -52,7 +50,7 @@ case class ArtifactDownloader(root: Uri, cache: File, logger: Option[ArtifactDow
// - what if someone is trying to write this file at the same time? (no locking of any kind yet)
// - ...
val urlStr = (root resolve Uri(path = relPath.mkString("./", "/", ""))).renderString
val urlStr = root + relPath.mkString("/")
Task {
try {
@ -107,8 +105,39 @@ trait RemoteLogger {
def puttingInCache(f: File): Unit
}
case class Remote(root: Uri, cache: Option[File] = None, logger: Option[RemoteLogger] = None) extends Repository {
lazy val client = org.http4s.client.blaze.defaultClient
object Remote {
def readFullySync(is: InputStream) = {
val buffer = new ByteArrayOutputStream()
val data = Array.ofDim[Byte](16384)
var nRead = is.read(data, 0, data.length)
while (nRead != -1) {
buffer.write(data, 0, nRead)
nRead = is.read(data, 0, data.length)
}
buffer.flush()
buffer.toByteArray
}
def readFully(is: => InputStream) =
Task {
\/.fromTryCatchNonFatal {
val is0 = is
val b =
try readFullySync(is)
finally is0.close()
new String(b, "UTF-8")
} .leftMap(_.getMessage)
}
}
case class Remote(root: String,
cache: Option[File] = None,
logger: Option[RemoteLogger] = None) extends Repository {
def find(module: Module,
cachePolicy: CachePolicy): EitherT[Task, String, Project] = {
@ -141,19 +170,13 @@ case class Remote(root: Uri, cache: Option[File] = None, logger: Option[RemoteLo
}
def remote = {
val uri = root resolve Uri(path = relPath.mkString("./", "/", ""))
val log = Task(logger.foreach(_.downloading(uri.renderString)))
val get = log.flatMap(_ => client(uri))
val urlStr = root + relPath.mkString("/")
val url = new URL(urlStr)
get.flatMap{ resp =>
val success = resp.status == Status.Ok
logger.foreach(_.downloaded(uri.renderString, success))
def log = Task(logger.foreach(_.downloading(urlStr)))
def get = Remote.readFully(url.openStream())
if (success)
EntityDecoder.text.decode(resp).run.map(_.leftMap(_.sanitized))
else
Task.now(-\/(s"Unhandled or bad status ${resp.status.code} from repository (${resp.status.code} ${resp.status.reason})"))
}
log.flatMap(_ => get)
}
def save(s: String) = {
@ -199,14 +222,10 @@ case class Remote(root: Uri, cache: Option[File] = None, logger: Option[RemoteLo
}
def remote = {
val respTask = client(root resolve Uri(path = relPath.mkString("./", "/", "")))
val urlStr = root + relPath.mkString("/")
val url = new URL(urlStr)
respTask.flatMap{ resp =>
if (resp.status == Status.Ok)
EntityDecoder.text.decode(resp).run.map(_.leftMap(_.sanitized))
else
Task.now(-\/(s"Unhandled or bad status ${resp.status.code} from repository (${resp.status.code} ${resp.status.reason})"))
}
Remote.readFully(url.openStream())
}
def save(s: String) = {

View File

@ -2,9 +2,6 @@ package coursier.core
package object compatibility {
type DateTime = org.http4s.DateTime
val DateTime: org.http4s.DateTime.type = org.http4s.DateTime
implicit class RichChar(val c: Char) extends AnyVal {
def letterOrDigit = c.isLetterOrDigit
def letter = c.isLetter

View File

@ -1,15 +1,13 @@
package coursier
import org.http4s.Http4s._
package object repository {
type Remote = core.Remote
val Remote: core.Remote.type = core.Remote
val mavenCentral = Remote(uri("https://repo1.maven.org/maven2/"))
val mavenCentral = Remote("https://repo1.maven.org/maven2/")
val sonatypeReleases = Remote(uri("https://oss.sonatype.org/content/repositories/releases/"))
val sonatypeSnapshots = Remote(uri("https://oss.sonatype.org/content/repositories/snapshots/"))
val sonatypeReleases = Remote("https://oss.sonatype.org/content/repositories/releases/")
val sonatypeSnapshots = Remote("https://oss.sonatype.org/content/repositories/snapshots/")
}

View File

@ -10,6 +10,14 @@ object Resolver {
/**
* Try to find `module` among `repositories`.
*
* Look at `repositories` from the left, one-by-one, and stop at first success.
* Else, return all errors, in the same order.
*
* The `module` field of the returned `Project` in case of success may not be
* equal to `module`, in case the version of the latter is not a specific
* version (e.g. version interval). Which version get chosen depends on
* the repository implementation.
*/
def find(repositories: Seq[Repository],
module: Module): EitherT[Task, List[String], (Repository, Project)] = {
@ -126,6 +134,7 @@ object Resolver {
.map(v => v -> Parse.versionConstraint(v))
.partition(_._2.isEmpty)
// FIXME Report this in return type, not this way
if (nonParsedConstraints.nonEmpty)
Console.err.println(s"Ignoring unparsed versions: ${nonParsedConstraints.map(_._1)}")
@ -139,7 +148,7 @@ object Resolver {
/**
* Merge several dependencies, solving version constraints of duplicated modules.
* Returns the conflicted dependencies, and the (solved) others.
* Returns the conflicted dependencies, and the (merged) others.
*/
def merge(dependencies: TraversableOnce[Dependency]): (Seq[Dependency], Seq[Dependency]) = {
val m = dependencies
@ -370,7 +379,7 @@ object Resolver {
/**
* State of a dependency resolution.
*
* Done if `isDone` is `true`.
* Done if method `isDone` returns `true`.
*
* @param dependencies: current set of dependencies
* @param conflicts: conflicting dependencies

View File

@ -72,7 +72,7 @@ object CoursierBuild extends Build {
.settings(commonSettings ++ commonCoreSettings: _*)
.settings(
libraryDependencies ++= Seq(
"org.http4s" %% "http4s-blazeclient" % "0.7.0",
"org.scalaz" %% "scalaz-concurrent" % "7.1.2",
"com.lihaoyi" %% "utest" % "0.3.0" % "test"
) ++ {
if (scalaVersion.value.startsWith("2.10.")) Seq()
@ -118,8 +118,13 @@ object CoursierBuild extends Build {
libraryDependencies ++= Seq(
"com.github.japgolly.scalajs-react" %%% "core" % "0.9.0"
),
jsDependencies +=
"org.webjars" % "react" % "0.12.2" / "react-with-addons.js" commonJSName "React"
resolvers += "Webjars Bintray" at "https://dl.bintray.com/webjars/maven/",
jsDependencies ++= Seq(
("org.webjars.bower" % "bootstrap" % "3.3.4" intransitive()) / "bootstrap.min.js" commonJSName "Bootstrap",
("org.webjars.bower" % "react" % "0.12.2" intransitive()) / "react-with-addons.js" commonJSName "React",
("org.webjars.bower" % "bootstrap-treeview" % "1.2.0" intransitive()) / "bootstrap-treeview.min.js" commonJSName "Treeview",
("org.webjars.bower" % "raphael" % "2.1.4" intransitive()) / "raphael-min.js" commonJSName "Raphael"
)
)
.enablePlugins(ScalaJSPlugin)

View File

@ -23,20 +23,17 @@ function isMaster() {
[ "$TRAVIS_BRANCH" = "master" ]
}
# web sub-project doesn't compile in 2.10 (no scalajs-react)
if echo "$TRAVIS_SCALA_VERSION" | grep -q "^2\.10"; then
if isNotPr && isJdk7 && isMaster; then
EXTRA_SBT_ARGS="core-jvm/publish core-js/publish cli/publish"
else
EXTRA_SBT_ARGS=""
fi
sbt ++${TRAVIS_SCALA_VERSION} core-jvm/test core-js/test cli/test $EXTRA_SBT_ARGS
SBT_COMMANDS="cli/compile"
else
if isNotPr && isJdk7 && isMaster; then
EXTRA_SBT_ARGS="publish"
else
EXTRA_SBT_ARGS=""
fi
sbt ++${TRAVIS_SCALA_VERSION} test $EXTRA_SBT_ARGS
SBT_COMMANDS="compile"
fi
SBT_COMMANDS="$SBT_COMMANDS core-jvm/test core-js/test"
if isNotPr && isJdk7 && isMaster; then
SBT_COMMANDS="$SBT_COMMANDS core-jvm/publish core-js/publish cli/publish"
fi
sbt ++${TRAVIS_SCALA_VERSION} $SBT_COMMANDS

View File

@ -7,6 +7,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<!-- FIXME Get from WebJar -->
<link rel="stylesheet" href="css/bootstrap-treeview.css">
<style>
@ -106,6 +107,8 @@
}
</script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<!-- during dev -->
<script type="text/javascript" src="../web-jsdeps.js"></script>
<script type="text/javascript" src="../web-fastopt.js"></script>
@ -113,20 +116,13 @@
<script type="text/javascript" src="web-jsdeps.js"></script>
<script type="text/javascript" src="web-fastopt.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<script src="js/bootstrap-treeview.js"></script>
<script type="text/javascript" src="js/raphael.js"></script>
<script type="text/javascript" src="js/dracula_graph.js"></script>
<script type="text/javascript" src="js/dracula_graffle.js"></script>
<script type="text/javascript" src="https://raw.githubusercontent.com/strathausen/dracula/26010eb3b0df037cf507886897e20c02c4ec041b/lib/dracula_graph.js"></script>
<script type="text/javascript" src="https://raw.githubusercontent.com/strathausen/dracula/26010eb3b0df037cf507886897e20c02c4ec041b/lib/dracula_graffle.js"></script>
<script>
// From http://www.bootply.com/VQqzOawoYc
// Javascript to enable link to tab
var hash = document.location.hash;
console.log(hash);
if (hash) {
console.log('match');
// $('.nav-tabs a[href='+hash+']').tab('show');

File diff suppressed because it is too large Load Diff

View File

@ -1,128 +0,0 @@
/**
* Originally grabbed from the official RaphaelJS Documentation
* http://raphaeljs.com/graffle.html
* Adopted (arrows) and commented by Philipp Strathausen http://blog.ameisenbar.de
* Licenced under the MIT licence.
*/
/**
* Usage:
* connect two shapes
* parameters:
* source shape [or connection for redrawing],
* target shape,
* style with { fg : linecolor, bg : background color, directed: boolean }
* returns:
* connection { draw = function() }
*/
Raphael.fn.connection = function Connection(obj1, obj2, style) {
var selfRef = this;
/* create and return new connection */
var edge = {/*
from : obj1,
to : obj2,
style : style,*/
draw : function() {
/* get bounding boxes of target and source */
var bb1 = obj1.getBBox();
var bb2 = obj2.getBBox();
var off1 = 0;
var off2 = 0;
/* coordinates for potential connection coordinates from/to the objects */
var p = [
/* NORTH 1 */
{ x: bb1.x + bb1.width / 2, y: bb1.y - off1 },
/* SOUTH 1 */
{ x: bb1.x + bb1.width / 2, y: bb1.y + bb1.height + off1 },
/* WEST */
{ x: bb1.x - off1, y: bb1.y + bb1.height / 2 },
/* EAST 1 */
{ x: bb1.x + bb1.width + off1, y: bb1.y + bb1.height / 2 },
/* NORTH 2 */
{ x: bb2.x + bb2.width / 2, y: bb2.y - off2 },
/* SOUTH 2 */
{ x: bb2.x + bb2.width / 2, y: bb2.y + bb2.height + off2 },
/* WEST 2 */
{ x: bb2.x - off2, y: bb2.y + bb2.height / 2 },
/* EAST 2 */
{ x: bb2.x + bb2.width + off2, y: bb2.y + bb2.height / 2 }
];
/* distances between objects and according coordinates connection */
var d = {}, dis = [], dx, dy;
/*
* find out the best connection coordinates by trying all possible ways
*/
/* loop the first object's connection coordinates */
for (var i = 0; i < 4; i++) {
/* loop the seond object's connection coordinates */
for (var j = 4; j < 8; j++) {
dx = Math.abs(p[i].x - p[j].x);
dy = Math.abs(p[i].y - p[j].y);
if ((i === j - 4) || (((i !== 3 && j !== 6) || p[i].x < p[j].x) &&
((i !== 2 && j !== 7) || p[i].x > p[j].x) &&
((i !== 0 && j !== 5) || p[i].y > p[j].y) &&
((i !== 1 && j !== 4) || p[i].y < p[j].y)))
{
dis.push(dx + dy);
d[dis[dis.length - 1].toFixed(3)] = [i, j];
}
}
}
var res = dis.length === 0 ? [0, 4] : d[Math.min.apply(Math, dis).toFixed(3)];
/* bezier path */
var x1 = p[res[0]].x,
y1 = p[res[0]].y,
x4 = p[res[1]].x,
y4 = p[res[1]].y;
dx = Math.max(Math.abs(x1 - x4) / 2, 10);
dy = Math.max(Math.abs(y1 - y4) / 2, 10);
var x2 = [ x1, x1, x1 - dx, x1 + dx ][res[0]].toFixed(3),
y2 = [ y1 - dy, y1 + dy, y1, y1 ][res[0]].toFixed(3),
x3 = [ 0, 0, 0, 0, x4, x4, x4 - dx, x4 + dx ][res[1]].toFixed(3),
y3 = [ 0, 0, 0, 0, y1 + dy, y1 - dy, y4, y4 ][res[1]].toFixed(3);
/* assemble path and arrow */
var path = [ "M" + x1.toFixed(3), y1.toFixed(3),
"C" + x2, y2, x3, y3, x4.toFixed(3), y4.toFixed(3) ].join(",");
/* arrow */
if(style && style.directed) {
// magnitude, length of the last path vector
var mag = Math.sqrt((y4 - y3) * (y4 - y3) + (x4 - x3) * (x4 - x3));
// vector normalisation to specified length
var norm = function(x,l){return (-x*(l||5)/mag);};
// calculate array coordinates (two lines orthogonal to the path vector)
var arr = [
{ x:(norm(x4-x3)+norm(y4-y3)+x4).toFixed(3),
y:(norm(y4-y3)+norm(x4-x3)+y4).toFixed(3) },
{ x:(norm(x4-x3)-norm(y4-y3)+x4).toFixed(3),
y:(norm(y4-y3)-norm(x4-x3)+y4).toFixed(3) }
];
path = path + ",M" + arr[0].x + "," + arr[0].y + ",L" + x4 + "," +
y4 + ",L" + arr[1].x + "," + arr[1].y;
}
/* function to be used for moving existent path(s), e.g. animate() or attr() */
var move = "attr";
/* applying path(s) */
edge.fg && edge.fg[move]({path:path}) ||
(edge.fg = selfRef.path(path)
.attr({ stroke: style && style.stroke || "#000", fill: "none" })
.toBack());
edge.bg && edge.bg[move]({path:path}) ||
style && style.fill && (edge.bg = style.fill.split &&
selfRef.path(path)
.attr({ stroke: style.fill.split("|")[0], fill: "none",
"stroke-width": style.fill.split("|")[1] || 3 }).toBack());
/* setting label */
style && style.label &&
(edge.label && edge.label.attr({x:(x1+x4)/2, y:(y1+y4)/2}) ||
(edge.label = selfRef.text((x1+x4)/2, (y1+y4)/2, style.label)
.attr({fill: "#000", "font-size": style["font-size"] || "12px"})));
style && style.label && style["label-style"] && edge.label &&
edge.label.attr(style["label-style"]);
style && style.callback && style.callback(edge);
}
};
edge.draw();
return edge;
};

View File

@ -1,685 +0,0 @@
/*
* Dracula Graph Layout and Drawing Framework 0.0.3alpha
* (c) 2010 Johann Philipp Strathausen <strathausen@gmail.com>
* http://strathausen.eu
*
* Contributions by Jake Stothard <stothardj@gmail.com>.
*
* based on the Graph JavaScript framework, version 0.0.1
* (c) 2006 Aslak Hellesoy <aslak.hellesoy@gmail.com>
* (c) 2006 Dave Hoover <dave.hoover@gmail.com>
*
* Ported from Graph::Layouter::Spring in
* http://search.cpan.org/~pasky/Graph-Layderer-0.02/
* The algorithm is based on a spring-style layouter of a Java-based social
* network tracker PieSpy written by Paul Mutton <paul@jibble.org>.
*
* This code is freely distributable under the MIT license. Commercial use is
* hereby granted without any cost or restriction.
*
* Links:
*
* Graph Dracula JavaScript Framework:
* http://graphdracula.net
*
/*--------------------------------------------------------------------------*/
/*
* Dracula
*/
var Dracula = function() {
this.nodes = {};
this.edges = [];
this.snapshots = []; // previous graph states TODO to be implemented
};
var Graph = Dracula;
Dracula.prototype = {
/*
* add a node
* @id the node's ID (string or number)
* @content (optional, dictionary) can contain any information that is
* being interpreted by the layout algorithm or the graph
* representation
*/
addNode: function(id, content) {
/* testing if node is already existing in the graph */
if(this.nodes[id] === undefined) {
this.nodes[id] = new Dracula.Node(id, content);
}
return this.nodes[id];
},
addEdge: function(source, target, style) {
var s = this.addNode(source);
var t = this.addNode(target);
var edge = new Dracula.Edge({ source: s, target: t, style: style });
s.edges.push(edge);
this.edges.push(edge);
// NOTE: Even directed edges are added to both nodes.
t.edges.push(edge);
return edge;
},
/* TODO to be implemented
* Preserve a copy of the graph state (nodes, positions, ...)
* @comment a comment describing the state
*/
snapShot: function(comment) {
// FIXME
//var graph = new Dracula();
//graph.nodes = jQuery.extend(true, {}, this.nodes);
//graph.edges = jQuery.extend(true, {}, this.edges);
//this.snapshots.push({comment: comment, graph: graph});
},
removeNode: function(id) {
if (this.nodes[id] && this.node[id].shape) {
this.nodes[id].shape.remove();
delete this.nodes[id];
}
for(var i = 0; i < this.edges.length; i++) {
if (this.edges[i].source.id == id || this.edges[i].target.id == id) {
this.edges[i].connection.fg.remove();
this.edges[i].connection.label.remove();
this.edges.splice(i, 1);
i--;
}
}
}
};
/*
* Edge
*/
Dracula.Edge = function DraculaEdge(opts) {
this.source = opts.source;
this.target = opts.target;
if (opts.style) {
this.style = jQuery.extend(true, {}, Dracula.Edge.style, opts.style);
} else {
this.style = jQuery.extend(true, {}, Dracula.Edge.style);
}
};
Dracula.Edge.style = {
directed: false
};
Dracula.Edge.prototype = {
weight: 0,
hide: function hideEdge() {
this.connection.fg.hide();
this.connection.bg && this.bg.connection.hide();
}
};
/*
* Node
*/
Dracula.Node = function DraculaNode(id, node){
var i;
node = node || {};
node.id = id;
node.edges = [];
node.hide = function() {
var i;
this.hidden = true;
this.shape && this.shape.hide(); /* FIXME this is representation specific code and should be elsewhere */
for(i in this.edges)
(this.edges[i].source.id == id || this.edges[i].target == id) && this.edges[i].hide && this.edges[i].hide();
};
node.show = function() {
var i;
this.hidden = false;
this.shape && this.shape.show();
for(i in this.edges)
(this.edges[i].source.id == id || this.edges[i].target == id) &&
this.edges[i].show && this.edges[i].show();
};
return node;
};
Dracula.Node.prototype = {
};
/*
* Renderer Base Class
*/
Dracula.Renderer = {};
/*
* Renderer implementation using RaphaelJS
*/
Dracula.Renderer.Raphael = function(element, graph, width, height) {
this.width = width || 400;
this.height = height || 400;
this.r = Raphael(element, this.width, this.height);
this.radius = 40; /* max dimension of a node */
this.graph = graph;
this.mouse_in = false;
/* TODO default node rendering function */
if(!this.graph.render) {
this.graph.render = function() {
return;
};
}
this.draw();
};
/* Moved this default node renderer function out of the main prototype code
* so it can be override by default */
Dracula.Renderer.defaultRenderFunc = function(r, node) {
/* the default node drawing */
var color = Raphael.getColor();
var ellipse = r.ellipse(0, 0, 30, 20).attr({
fill: node.fill || color,
stroke: node.stroke || color,
"stroke-width": 2
});
/* set DOM node ID */
ellipse.node.id = node.id || node.label;
if(node.class)ellipse.node.classList.add(node.class);
shape = r.set().push(ellipse).push(r.text(0, 30, node.label || node.id));
return shape;
};
Dracula.Renderer.Raphael.prototype = {
translate: function(point) {
return [
(point[0] - this.graph.layoutMinX) * this.factorX + this.radius,
(point[1] - this.graph.layoutMinY) * this.factorY + this.radius
];
},
rotate: function(point, length, angle) {
var dx = length * Math.cos(angle);
var dy = length * Math.sin(angle);
return [point[0]+dx, point[1]+dy];
},
draw: function() {
var i;
this.factorX = (this.width - 2 * this.radius) / (this.graph.layoutMaxX - this.graph.layoutMinX);
this.factorY = (this.height - 2 * this.radius) / (this.graph.layoutMaxY - this.graph.layoutMinY);
for (i in this.graph.nodes) {
this.drawNode(this.graph.nodes[i]);
}
for (i = 0; i < this.graph.edges.length; i++) {
this.drawEdge(this.graph.edges[i]);
}
},
drawNode: function(node) {
var point = this.translate([node.layoutPosX, node.layoutPosY]);
node.point = point;
var r = this.r;
var graph = this.graph;
/* if node has already been drawn, move the nodes */
if(node.shape) {
var oBBox = node.shape.getBBox();
var opoint = {
x: oBBox.x + oBBox.width / 2,
y: oBBox.y + oBBox.height / 2
};
node.shape.translate(
Math.round(point[0] - opoint.x), Math.round(point[1] - opoint.y)
);
this.r.safari();
return node;
}/* else, draw new nodes */
var shape;
/* if a node renderer function is provided by the user, then use it
or the default render function instead */
if(!node.render) {
node.render = Dracula.Renderer.defaultRenderFunc;
}
/* or check for an ajax representation of the nodes */
if(node.shapes) {
// TODO ajax representation evaluation
}
var selfRef = this;
shape = node.render(this.r, node).hide();
shape.attr({"fill-opacity": 0.6});
/* re-reference to the node an element belongs to, needed for dragging all elements of a node */
shape.items.forEach(function(item) {
item.set = shape;
item.node.style.cursor = "move";
});
shape.drag(
function dragMove(dx, dy, x, y) {
dx = this.set.ox;
dy = this.set.oy;
var bBox = this.set.getBBox();
var newX = x - dx + (bBox.x + bBox.width / 2);
var newY = y - dy + (bBox.y + bBox.height / 2);
var clientX =
x - (newX < 20 ? newX - 20 : newX > r.width - 20 ? newX - r.width + 20 : 0);
var clientY =
y - (newY < 20 ? newY - 20 : newY > r.height - 20 ? newY - r.height + 20 : 0);
this.set.translate(clientX - Math.round(dx), clientY - Math.round(dy));
for (var i in selfRef.graph.edges) {
selfRef.graph.edges[i] &&
selfRef.graph.edges[i].connection && selfRef.graph.edges[i].connection.draw();
}
r.safari();
this.set.ox = clientX;
this.set.oy = clientY;
},
function dragEnter(x, y) {
this.set.ox = x;
this.set.oy = y;
this.animate({ 'fill-opacity': 0.2 }, 500);
},
function dragOut() {
this.animate({ 'fill-opacity': 0.6 }, 500);
}
);
var box = shape.getBBox();
shape.translate(
Math.round(point[0] - (box.x + box.width / 2)),
Math.round(point[1] - (box.y + box.height / 2))
);
node.hidden || shape.show();
node.shape = shape;
},
drawEdge: function(edge) {
/* if this edge already exists the other way around and is undirected */
if(edge.backedge)
return;
if(edge.source.hidden || edge.target.hidden) {
edge.connection && edge.connection.fg.hide();
edge.connection.bg && edge.connection.bg.hide();
return;
}
/* if edge already has been drawn, only refresh the edge */
if(!edge.connection) {
edge.style && edge.style.callback && edge.style.callback(edge); // TODO move this somewhere else
edge.connection = this.r.connection(edge.source.shape, edge.target.shape, edge.style);
return;
}
//FIXME showing doesn't work well
edge.connection.fg.show();
edge.connection.bg && edge.connection.bg.show();
edge.connection.draw();
}
};
Dracula.Layout = {};
Dracula.Layout.Spring = function(graph) {
this.graph = graph;
this.iterations = 500;
this.maxRepulsiveForceDistance = 6;
this.k = 2;
this.c = 0.01;
this.maxVertexMovement = 0.5;
this.layout();
};
Dracula.Layout.Spring.prototype = {
layout: function() {
this.layoutPrepare();
for (var i = 0; i < this.iterations; i++) {
this.layoutIteration();
}
this.layoutCalcBounds();
},
layoutPrepare: function() {
var i;
for (i in this.graph.nodes) {
var node = this.graph.nodes[i];
node.layoutPosX = 0;
node.layoutPosY = 0;
node.layoutForceX = 0;
node.layoutForceY = 0;
}
},
layoutCalcBounds: function() {
var minx = Infinity, maxx = -Infinity,
miny = Infinity, maxy = -Infinity;
var i;
for (i in this.graph.nodes) {
var x = this.graph.nodes[i].layoutPosX;
var y = this.graph.nodes[i].layoutPosY;
if(x > maxx) maxx = x;
if(x < minx) minx = x;
if(y > maxy) maxy = y;
if(y < miny) miny = y;
}
this.graph.layoutMinX = minx;
this.graph.layoutMaxX = maxx;
this.graph.layoutMinY = miny;
this.graph.layoutMaxY = maxy;
},
layoutIteration: function() {
// Forces on nodes due to node-node repulsions
var prev = [];
for(var c in this.graph.nodes) {
var node1 = this.graph.nodes[c];
for (var d in prev) {
var node2 = this.graph.nodes[prev[d]];
this.layoutRepulsive(node1, node2);
}
prev.push(c);
}
// Forces on nodes due to edge attractions
for (var i = 0; i < this.graph.edges.length; i++) {
var edge = this.graph.edges[i];
this.layoutAttractive(edge);
}
// Move by the given force
for (i in this.graph.nodes) {
var node = this.graph.nodes[i];
var xmove = this.c * node.layoutForceX;
var ymove = this.c * node.layoutForceY;
var max = this.maxVertexMovement;
if(xmove > max) xmove = max;
if(xmove < -max) xmove = -max;
if(ymove > max) ymove = max;
if(ymove < -max) ymove = -max;
node.layoutPosX += xmove;
node.layoutPosY += ymove;
node.layoutForceX = 0;
node.layoutForceY = 0;
}
},
layoutRepulsive: function(node1, node2) {
if (typeof node1 == 'undefined' || typeof node2 == 'undefined')
return;
var dx = node2.layoutPosX - node1.layoutPosX;
var dy = node2.layoutPosY - node1.layoutPosY;
var d2 = dx * dx + dy * dy;
if(d2 < 0.01) {
dx = 0.1 * Math.random() + 0.1;
dy = 0.1 * Math.random() + 0.1;
d2 = dx * dx + dy * dy;
}
var d = Math.sqrt(d2);
if(d < this.maxRepulsiveForceDistance) {
var repulsiveForce = this.k * this.k / d;
node2.layoutForceX += repulsiveForce * dx / d;
node2.layoutForceY += repulsiveForce * dy / d;
node1.layoutForceX -= repulsiveForce * dx / d;
node1.layoutForceY -= repulsiveForce * dy / d;
}
},
layoutAttractive: function(edge) {
var node1 = edge.source;
var node2 = edge.target;
var dx = node2.layoutPosX - node1.layoutPosX;
var dy = node2.layoutPosY - node1.layoutPosY;
var d2 = dx * dx + dy * dy;
if(d2 < 0.01) {
dx = 0.1 * Math.random() + 0.1;
dy = 0.1 * Math.random() + 0.1;
d2 = dx * dx + dy * dy;
}
var d = Math.sqrt(d2);
if(d > this.maxRepulsiveForceDistance) {
d = this.maxRepulsiveForceDistance;
d2 = d * d;
}
var attractiveForce = (d2 - this.k * this.k) / this.k;
if(edge.attraction === undefined) edge.attraction = 1;
attractiveForce *= Math.log(edge.attraction) * 0.5 + 1;
node2.layoutForceX -= attractiveForce * dx / d;
node2.layoutForceY -= attractiveForce * dy / d;
node1.layoutForceX += attractiveForce * dx / d;
node1.layoutForceY += attractiveForce * dy / d;
}
};
Dracula.Layout.Ordered = function(graph, order) {
this.graph = graph;
this.order = order;
this.layout();
};
Dracula.Layout.Ordered.prototype = {
layout: function() {
this.layoutPrepare();
this.layoutCalcBounds();
},
layoutPrepare: function(order) {
var node, i;
for (i in this.graph.nodes) {
node = this.graph.nodes[i];
node.layoutPosX = 0;
node.layoutPosY = 0;
}
var counter = 0;
for (i in this.order) {
node = this.order[i];
node.layoutPosX = counter;
node.layoutPosY = Math.random();
counter++;
}
},
layoutCalcBounds: function() {
var minx = Infinity, maxx = -Infinity,
miny = Infinity, maxy = -Infinity;
var i;
for (i in this.graph.nodes) {
var x = this.graph.nodes[i].layoutPosX;
var y = this.graph.nodes[i].layoutPosY;
if(x > maxx) maxx = x;
if(x < minx) minx = x;
if(y > maxy) maxy = y;
if(y < miny) miny = y;
}
this.graph.layoutMinX = minx;
this.graph.layoutMaxX = maxx;
this.graph.layoutMinY = miny;
this.graph.layoutMaxY = maxy;
}
};
Dracula.Layout.OrderedTree = function(graph, order) {
this.graph = graph;
this.order = order;
this.layout();
};
/*
* OrderedTree is like Ordered but assumes there is one root
* This way we can give non random positions to nodes on the Y-axis
* it assumes the ordered nodes are of a perfect binary tree
*/
Dracula.Layout.OrderedTree.prototype = {
layout: function() {
this.layoutPrepare();
this.layoutCalcBounds();
},
layoutPrepare: function(order) {
var node, i;
for (i in this.graph.nodes) {
node = this.graph.nodes[i];
node.layoutPosX = 0;
node.layoutPosY = 0;
}
//to reverse the order of rendering, we need to find out the
//absolute number of levels we have. simple log math applies.
var numNodes = this.order.length;
var totalLevels = Math.floor(Math.log(numNodes) / Math.log(2));
var counter = 1;
for (i in this.order) {
node = this.order[i];
//rank aka x coordinate
var rank = Math.floor(Math.log(counter) / Math.log(2));
//file relative to top
var file = counter - Math.pow(rank, 2);
node.layoutPosX = totalLevels - rank;
node.layoutPosY = file;
counter++;
}
},
layoutCalcBounds: function() {
var minx = Infinity, maxx = -Infinity,
miny = Infinity, maxy = -Infinity;
var i;
for (i in this.graph.nodes) {
var x = this.graph.nodes[i].layoutPosX;
var y = this.graph.nodes[i].layoutPosY;
if(x > maxx) maxx = x;
if(x < minx) minx = x;
if(y > maxy) maxy = y;
if(y < miny) miny = y;
}
this.graph.layoutMinX = minx;
this.graph.layoutMaxX = maxx;
this.graph.layoutMinY = miny;
this.graph.layoutMaxY = maxy;
}
};
Dracula.Layout.TournamentTree = function(graph, order) {
this.graph = graph;
this.order = order;
this.layout();
};
/*
* TournamentTree looks more like a binary tree
*/
Dracula.Layout.TournamentTree.prototype = {
layout: function() {
this.layoutPrepare();
this.layoutCalcBounds();
},
layoutPrepare: function(order) {
var node, i;
for (i in this.graph.nodes) {
node = this.graph.nodes[i];
node.layoutPosX = 0;
node.layoutPosY = 0;
}
//to reverse the order of rendering, we need to find out the
//absolute number of levels we have. simple log math applies.
var numNodes = this.order.length;
var totalLevels = Math.floor(Math.log(numNodes) / Math.log(2));
var counter = 1;
for (i in this.order) {
node = this.order[i];
var depth = Math.floor(Math.log(counter) / Math.log(2));
var xpos = counter - Math.pow(depth, 2);
var offset = Math.pow(2, totalLevels - depth);
var final_x = offset + (counter - Math.pow(2, depth)) *
Math.pow(2, (totalLevels - depth) + 1);
node.layoutPosX = final_x;
node.layoutPosY = depth;
counter++;
}
},
layoutCalcBounds: function() {
var minx = Infinity, maxx = -Infinity,
miny = Infinity, maxy = -Infinity;
var i;
for (i in this.graph.nodes) {
var x = this.graph.nodes[i].layoutPosX;
var y = this.graph.nodes[i].layoutPosY;
if(x > maxx) maxx = x;
if(x < minx) minx = x;
if(y > maxy) maxy = y;
if(y < miny) miny = y;
}
this.graph.layoutMinX = minx;
this.graph.layoutMaxX = maxx;
this.graph.layoutMinY = miny;
this.graph.layoutMaxY = maxy;
}
};
/*
* Raphael Tooltip Plugin
* - attaches an element as a tooltip to another element
*
* Usage example, adding a rectangle as a tooltip to a circle:
*
* paper.circle(100,100,10).tooltip(paper.rect(0,0,20,30));
*
* If you want to use more shapes, you'll have to put them into a set.
*
*/
Raphael.el.tooltip = function (tp) {
this.tp = tp;
this.tp.o = {x: 0, y: 0};
this.tp.hide();
this.hover(
function(event){
this.mousemove(function(event){
this.tp.translate(event.clientX -
this.tp.o.x,event.clientY - this.tp.o.y);
this.tp.o = {x: event.clientX, y: event.clientY};
});
this.tp.show().toFront();
},
function(event){
this.tp.hide();
this.unmousemove();
});
return this;
};
/* For IE */
if (!Array.prototype.forEach)
{
Array.prototype.forEach = function(fun /*, thisp*/)
{
var len = this.length;
if (typeof fun != "function")
throw new TypeError();
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in this)
fun.call(thisp, this[i], i, this);
}
};
}

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +0,0 @@
/*!
* routie - a tiny hash router
* v0.3.2
* http://projects.jga.me/routie
* copyright Greg Allen 2013
* MIT License
*/
(function(n){var e=[],t={},r="routie",o=n[r],i=function(n,e){this.name=e,this.path=n,this.keys=[],this.fns=[],this.params={},this.regex=a(this.path,this.keys,!1,!1)};i.prototype.addHandler=function(n){this.fns.push(n)},i.prototype.removeHandler=function(n){for(var e=0,t=this.fns.length;t>e;e++){var r=this.fns[e];if(n==r)return this.fns.splice(e,1),void 0}},i.prototype.run=function(n){for(var e=0,t=this.fns.length;t>e;e++)this.fns[e].apply(this,n)},i.prototype.match=function(n,e){var t=this.regex.exec(n);if(!t)return!1;for(var r=1,o=t.length;o>r;++r){var i=this.keys[r-1],a="string"==typeof t[r]?decodeURIComponent(t[r]):t[r];i&&(this.params[i.name]=a),e.push(a)}return!0},i.prototype.toURL=function(n){var e=this.path;for(var t in n)e=e.replace("/:"+t,"/"+n[t]);if(e=e.replace(/\/:.*\?/g,"/").replace(/\?/g,""),-1!=e.indexOf(":"))throw Error("missing parameters for url: "+e);return e};var a=function(n,e,t,r){return n instanceof RegExp?n:(n instanceof Array&&(n="("+n.join("|")+")"),n=n.concat(r?"":"/?").replace(/\/\(/g,"(?:/").replace(/\+/g,"__plus__").replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g,function(n,t,r,o,i,a){return e.push({name:o,optional:!!a}),t=t||"",""+(a?"":t)+"(?:"+(a?t:"")+(r||"")+(i||r&&"([^/.]+?)"||"([^/]+?)")+")"+(a||"")}).replace(/([\/.])/g,"\\$1").replace(/__plus__/g,"(.+)").replace(/\*/g,"(.*)"),RegExp("^"+n+"$",t?"":"i"))},s=function(n,r){var o=n.split(" "),a=2==o.length?o[0]:null;n=2==o.length?o[1]:o[0],t[n]||(t[n]=new i(n,a),e.push(t[n])),t[n].addHandler(r)},h=function(n,e){if("function"==typeof e)s(n,e),h.reload();else if("object"==typeof n){for(var t in n)s(t,n[t]);h.reload()}else e===void 0&&h.navigate(n)};h.lookup=function(n,t){for(var r=0,o=e.length;o>r;r++){var i=e[r];if(i.name==n)return i.toURL(t)}},h.remove=function(n,e){var r=t[n];r&&r.removeHandler(e)},h.removeAll=function(){t={},e=[]},h.navigate=function(n,e){e=e||{};var t=e.silent||!1;t&&l(),setTimeout(function(){window.location.hash=n,t&&setTimeout(function(){p()},1)},1)},h.noConflict=function(){return n[r]=o,h};var f=function(){return window.location.hash.substring(1)},c=function(n,e){var t=[];return e.match(n,t)?(e.run(t),!0):!1},u=h.reload=function(){for(var n=f(),t=0,r=e.length;r>t;t++){var o=e[t];if(c(n,o))return}},p=function(){n.addEventListener?n.addEventListener("hashchange",u,!1):n.attachEvent("onhashchange",u)},l=function(){n.removeEventListener?n.removeEventListener("hashchange",u):n.detachEvent("onhashchange",u)};p(),n[r]=h})(window);