# HG changeset patch # User veltr # Date 1368526515 -7200 # Node ID f636e2dcfb2c31f881de08a8f1e3931c2011fa5b # Parent 756cfa6570d2de3dceaae111424b5003af509b07 eGonomy image fragments support diff -r 756cfa6570d2 -r f636e2dcfb2c client/css/renkan.css --- a/client/css/renkan.css Mon May 13 15:28:52 2013 +0200 +++ b/client/css/renkan.css Tue May 14 12:15:15 2013 +0200 @@ -286,9 +286,26 @@ font-size: 12px; width: 230px; } +.Rk-Edit-ImgWrap { + text-align: center; +} + .Rk-Edit-ImgPreview { - border: 1px solid #666; margin: 5px auto; display: block; - max-width: 253px !important; max-height: 200px !important; + display: inline-block; + border: 1px solid #666; margin: 5px auto; + position: relative; +} + +.Rk-Edit-ImgPreview img { + display: inline-block; max-width: 253px !important; max-height: 200px !important; +} + +.Rk-Edit-ImgPreview svg { + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; } .Rk-Editor textarea { diff -r 756cfa6570d2 -r f636e2dcfb2c client/js/defaults.js --- a/client/js/defaults.js Mon May 13 15:28:52 2013 +0200 +++ b/client/js/defaults.js Tue May 14 12:15:15 2013 +0200 @@ -28,7 +28,7 @@ force_resize: false, allow_double_click: true, /* Allows Double Click to create a node on an empty background */ - element_delete_delay: 8000, + element_delete_delay: 5000, /* Delay between clicking on the bin on an element and really deleting it Set to 0 for delete confirm */ autoscale_padding: 50, diff -r 756cfa6570d2 -r f636e2dcfb2c client/js/models.js --- a/client/js/models.js Mon May 13 15:28:52 2013 +0200 +++ b/client/js/models.js Tue May 14 12:15:15 2013 +0200 @@ -90,7 +90,8 @@ image: this.get("image"), color: this.get("color"), created_by: this.get("created_by") ? this.get("created_by").get("_id") : null, - size: this.get("size") + size: this.get("size"), + "clip-path": this.get("clip-path") }; }, }); diff -r 756cfa6570d2 -r f636e2dcfb2c client/js/paper-renderer.js --- 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) { %>
<%-renkan.translate("Size:")%>-<%-node.size%>+
<% } %>' + '<% if (options.show_node_editor_color) { %><%-renkan.translate("Created by:")%> <%- Rkns.Renderer.shortenText(node.created_by_title, 25) %>
<% } %>' ); @@ -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.$('