--- a/client/js/paper-renderer.js Mon May 13 15:28:52 2013 +0200
+++ b/client/js/paper-renderer.js Tue May 14 12:15:15 2013 +0200
@@ -242,15 +242,14 @@
var square = new paper.Size(this.circle_radius, this.circle_radius),
topleft = this.paper_coords.subtract(square),
bounds = new paper.Rectangle(topleft, square.multiply(2));
- this.circle.fitBounds(bounds);
+ this.circle.scale(this.circle_radius / this.last_circle_radius);
if (this.node_image) {
- this.node_image.fitBounds(bounds);
+ this.node_image.scale(this.circle_radius / this.last_circle_radius);
}
- } else {
- this.circle.position = this.paper_coords;
- if (this.node_image) {
- this.node_image.position = this.paper_coords;
- }
+ }
+ this.circle.position = this.paper_coords;
+ if (this.node_image) {
+ this.node_image.position = this.paper_coords.subtract(this.image_delta.multiply(this.circle_radius));
}
this.last_circle_radius = this.circle_radius;
@@ -299,44 +298,11 @@
this.all_buttons.forEach(function(b) {
b.moveTo(_pc);
});
- var _img = this.model.get("image");
- if (_img && _img !== this.img) {
- var _image = new Image(),
- _this = this;
- _image.onload = function() {
- if (_this.node_image) {
- _this.node_image.remove();
- }
- _this.renderer.node_layer.activate();
- var _ratio = Math.min(2 / _image.width, 2 / _image.height );
- if (!_this.options.show_node_circles) {
- _this.h_ratio = Math.min(1, _image.height / _image.width);
- }
- var _raster = new paper.Raster(_image);
- if (_this.options.clip_node_images) {
- var _clip = new paper.Path.Circle([0, 0], 1);
- _raster.scale(_ratio);
- _this.node_image = new paper.Group(_clip, _raster);
- _this.node_image.opacity = .99;
- /* This is a workaround to allow clipping at group level
- * If opacity was set to 1, paper.js would merge all clipping groups in one (known bug).
- */
- _this.node_image.clipped = true;
- _clip.__representation = _this;
- } else {
- _this.node_image = _raster;
- }
- _this.node_image.__representation = _this;
- var square = new paper.Size(_this.circle_radius, _this.circle_radius),
- topleft = _this.paper_coords.subtract(square),
- bounds = new paper.Rectangle(topleft, square.multiply(2));
- _this.node_image.fitBounds(bounds);
- _this.redraw();
- paper.view.draw();
- };
- _image.src = _img;
+ var lastImage = this.img;
+ this.img = this.model.get("image");
+ if (this.img && this.img !== lastImage) {
+ this.showImage();
}
- this.img = _img;
if (this.node_image && !this.img) {
this.node_image.remove();
delete this.node_image;
@@ -361,6 +327,127 @@
};
+Rkns.Renderer.Node.prototype.showImage = function() {
+ if (typeof this.renderer.image_cache[this.img] === "undefined") {
+ var _image = new Image()
+ this.renderer.image_cache[this.img] = _image;
+ _image.src = this.img;
+ } else {
+ var _image = this.renderer.image_cache[this.img];
+ }
+ if (_image.width) {
+ if (this.node_image) {
+ this.node_image.remove();
+ }
+ this.renderer.node_layer.activate();
+ var width = _image.width,
+ height = _image.height,
+ clipPath = this.model.get("clip-path"),
+ hasClipPath = (typeof clipPath !== "undefined" && clipPath);
+ if (hasClipPath) {
+ var _clip = new paper.Path(),
+ instructions = clipPath.match(/[a-z][^a-z]+/gi) || [],
+ lastCoords = [0,0],
+ minX = Infinity,
+ minY = Infinity,
+ maxX = -Infinity,
+ maxY = -Infinity;
+
+ function transformCoords(tabc, relative) {
+ var newCoords = tabc.slice(1).map(function(v, k) {
+ var res = parseFloat(v),
+ isY = k % 2;
+ if (isY) {
+ res = ( res - .5 ) * height;
+ } else {
+ res = ( res - .5 ) * width;
+ }
+ if (relative) {
+ res += lastCoords[isY];
+ }
+ if (isY) {
+ minY = Math.min(minY, res);
+ maxY = Math.max(maxY, res);
+ } else {
+ minX = Math.min(minX, res);
+ maxX = Math.max(maxX, res);
+ }
+ return res;
+ });
+ lastCoords = newCoords.slice(-2);
+ return newCoords;
+ }
+
+ instructions.forEach(function(instr) {
+ var coords = instr.match(/([a-z]|[0-9.-]+)/ig) || [""];
+ switch(coords[0]) {
+ case "M":
+ _clip.moveTo(transformCoords(coords));
+ break;
+ case "m":
+ _clip.moveTo(transformCoords(coords, true));
+ break;
+ case "L":
+ _clip.lineTo(transformCoords(coords));
+ break;
+ case "l":
+ _clip.lineTo(transformCoords(coords, true));
+ break;
+ case "C":
+ _clip.cubicCurveTo(transformCoords(coords));
+ break;
+ case "c":
+ _clip.cubicCurveTo(transformCoords(coords, true));
+ break;
+ case "Q":
+ _clip.quadraticCurveTo(transformCoords(coords));
+ break;
+ case "q":
+ _clip.quadraticCurveTo(transformCoords(coords, true));
+ break;
+ }
+ });
+
+ var baseScale = Math.max(maxX - minX, maxY - minY) / 2;
+ this.image_delta = new paper.Point((maxX + minX) / (2 * baseScale), (maxY + minY) / (2 * baseScale));
+ if (!this.options.show_node_circles) {
+ this.h_ratio = (maxY - minY) / (2 * baseScale);
+ }
+ } else {
+ var baseScale = Math.max(width, height) / 2;
+ this.image_delta = new paper.Point(0,0);
+ if (!this.options.show_node_circles) {
+ this.h_ratio = height / (2 * baseScale);
+ }
+ }
+ var _raster = new paper.Raster(_image);
+ if (this.options.clip_node_images || hasClipPath) {
+ if (!hasClipPath) {
+ var _clip = new paper.Path.Circle([0, 0], baseScale);
+ }
+ this.node_image = new paper.Group(_clip, _raster);
+ this.node_image.opacity = .99;
+ /* This is a workaround to allow clipping at group level
+ * If opacity was set to 1, paper.js would merge all clipping groups in one (known bug).
+ */
+ this.node_image.clipped = true;
+ _clip.__representation = this;
+ } else {
+ this.node_image = _raster;
+ }
+ this.node_image.__representation = _this;
+ this.node_image.scale(this.circle_radius / baseScale);
+ this.node_image.position = this.paper_coords.subtract(this.image_delta.multiply(this.circle_radius));
+ this.redraw();
+ this.renderer.throttledPaperDraw();
+ } else {
+ var _this = this;
+ Rkns.$(_image).on("load", function() {
+ _this.showImage();
+ });
+ }
+}
+
Rkns.Renderer.Node.prototype.paperShift = function(_delta) {
if (this.options.editor_mode) {
if (!this.renkan.read_only) {
@@ -841,8 +928,9 @@
+ '<% if (options.show_node_editor_size) { %><p><span class="Rk-Editor-Label"><%-renkan.translate("Size:")%></span><a href="#" class="Rk-Edit-Size-Down">-</a><span class="Rk-Edit-Size-Value"><%-node.size%></span><a href="#" class="Rk-Edit-Size-Up">+</a></p><% } %>'
+ '<% if (options.show_node_editor_color) { %><div class="Rk-Editor-p"><span class="Rk-Editor-Label"><%-renkan.translate("Node color:")%></span><div class="Rk-Edit-ColorPicker-Wrapper"><span class="Rk-Edit-Color" style="background:<%-node.color%>;"><span class="Rk-Edit-ColorTip"></span></span><ul class="Rk-Edit-ColorPicker">'
+ '<% _(Rkns.pickerColors).each(function(c) { %><li data-color="<%=c%>" style="background: <%=c%>"></li><% }); %></ul><span class="Rk-Edit-ColorPicker-Text"><%- renkan.translate("Choose color") %></span></div></div><% } %>'
- + '<% if (options.show_node_editor_image) { %><img class="Rk-Edit-ImgPreview" src="<%-node.image || node.image_placeholder%>" />'
- + '<p><label><%-renkan.translate("Image URL:")%></label><input class="Rk-Edit-Image" type="text" value="<%-node.image%>"/></p>'
+ + '<% if (options.show_node_editor_image) { %><div class="Rk-Edit-ImgWrap"><div class="Rk-Edit-ImgPreview"><img src="<%-node.image || node.image_placeholder%>" />'
+ + '<% if (node.clip_path) { %><svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewbox="0 0 1 1" preserveAspectRatio="none"><path style="stroke-width: .02; stroke:red; fill-opacity:.3; fill:red;" d="<%- node.clip_path %>"/></svg><% }%>'
+ + '</div></div><p><label><%-renkan.translate("Image URL:")%></label><input class="Rk-Edit-Image" type="text" value="<%-node.image%>"/></p>'
+ '<p><label><%-renkan.translate("Choose Image File:")%></label><input class="Rk-Edit-Image-File" type="file" accept="image/*"/></p><% } %>'
+ '<% if (options.show_node_editor_creator && node.has_creator) { %><p><span class="Rk-Editor-Label"><%-renkan.translate("Created by:")%></span> <span class="Rk-UserColor" style="background:<%-node.created_by_color%>;"></span><%- Rkns.Renderer.shortenText(node.created_by_title, 25) %></p><% } %>'
);
@@ -873,6 +961,7 @@
image: _model.get("image") || "",
image_placeholder: _image_placeholder,
color: _model.get("color") || _created_by.get("color"),
+ clip_path: _model.get("clip-path") || false,
created_by_color: _created_by.get("color"),
created_by_title: _created_by.get("title"),
size: (_size > 0 ? "+" : "") + _size
@@ -1474,12 +1563,13 @@
_lastTapX,
_lastTapY;
- this.imageCache = {};
+ this.image_cache = {};
+ this.icon_cache = {};
['edit', 'remove', 'link', 'enlarge', 'shrink', 'revert' ].forEach(function(imgname) {
var img = new Image();
img.src = _renkan.options.static_url + 'img/' + imgname + '.png';
- _this.imageCache[imgname] = img;
+ _this.icon_cache[imgname] = img;
});
var throttledMouseMove = _.throttle(function(_event, _isTouch) {
@@ -1853,7 +1943,7 @@
var _options = this.renkan.options,
_startRads = _startAngle * Math.PI / 180,
_endRads = _endAngle * Math.PI / 180,
- _img = this.imageCache[_imgname],
+ _img = this.icon_cache[_imgname],
_span = _endRads - _startRads,
_startdx = - Math.sin(_startRads),
_startdy = Math.cos(_startRads),
@@ -2361,6 +2451,14 @@
}
if (_data["text/html"] || _data["text/x-iri-selected-html"]) {
var snippet = Rkns.$('<div>').html(_data["text/html"] || _data["text/x-iri-selected-html"]);
+ var _svgimgs = snippet.find("image");
+ if (_svgimgs.length) {
+ newNode.image = _svgimgs.attr("xlink:href");
+ }
+ var _svgpaths = snippet.find("path");
+ if (_svgpaths.length) {
+ newNode.clipPath = _svgpaths.attr("d");
+ }
var _imgs = snippet.find("img");
if (_imgs.length) {
newNode.image = _imgs[0].src;
@@ -2389,6 +2487,7 @@
newNode.uri = snippet.find("[data-uri]").attr("data-uri") || newNode.uri;
newNode.title = snippet.find("[data-title]").attr("data-title") || newNode.title;
newNode.description = snippet.find("[data-description]").attr("data-description") || newNode.description;
+ newNode.description = snippet.find("[data-clip-path]").attr("data-clip-path") || newNode.description;
}
}
if (!newNode.title) {
@@ -2418,6 +2517,7 @@
description: newNode.description || "",
image: newNode.image || "",
color: newNode.color || undefined,
+ "clip-path": newNode.clipPath || undefined,
position: {
x: _coords.x,
y: _coords.y