Raphael path 拖动实现

让 Raphael 的 Path 动起来

Raphaël 是一个很实用的线上矢量图操作 Javascript 库。使用简单,一个值得一提的卖点是通过抽象出共同的接口屏蔽了 SVG 和 VML 之间的差异,做到了对主流浏览器的支持,包括很不给力的 IE6。(很可惜,并不支持手机 UC 浏览器)

Raphael 对于交互事件也有一定的支持,比如常用的鼠标的拖放操作(Drag and Drop)。在官方网站上也有拖放操作的例子。可惜的是,官方的这个例子的写法只对 Circle,Rect 等有效,但对于 Path 却不起作用。经过一番实践,终于了解了 Raphaël 对于拖放支持的原理,想出了一个通用的拖放操作的写法,支持所有的 Raphael 矢量对象,包括 path。

官方例子之所以不能让 Path 动起来是因为:Path 没有象 Circle 里面的 cx 和 cy 属性,要移动 Path,只能使用 Path.translate() 方法。还有一点要注意的是,Path 必须要先 fill 才能移动。

仿照官方的例子,下面是一个 Path 移动的代码示例:

var R = Raphael("paper", 400, 300);
var p = R.path('M0 0L100 0L50 80Z');
 
p.attr({"fill":"green", 'opacity':0.8});
 
var start = function (x, y) {
  this.attr({opacity: 1});
  this.lastX = x;
  this.lastY = y;
},
move = function (dx, dy, x, y) {
  var deltaX = x - this.lastX;
  var deltaY = y - this.lastY;
  this.translate(deltaX, deltaY);
  this.lastX = x;
  this.lastY = y;
},
up = function () {
  this.attr({opacity: 0.8});
}; 
 
p.drag(move, start, up);

运行效果如下

上面的例子有几点要说明一下

  • 回调函数 move 的第一个和第二个参数永远是鼠标所在的点距移动初始时的鼠标位置的相对位移值。而不是距离上次 move 回调时鼠标位置的相对位移值
  • 我们在 start 和 move 中记录并不断更新相对上次鼠标位置的相对位移值,并保存在 this.lastX 和 this.lastY 中
  • 我们通过 this.translate() 进行实际的移动操作
  • 在一开始,要设置 fill 属性,否则就不能进行移动操作

这个例子不但能工作,更好的是,因为所有的 Raphael 矢量对象都有 translate 方法。所以,它不仅对 path 有效,也对所有的 Raphael 矢量对象有效。那么,是不是能做出来类似 jQuery.ui 里面的 draggble 的函数呢。下面就是一个简单的扩展,为 Raphael 对象加入了 draggable 方法。

(function(R) {
    R.el.draggable = function(move, start, up) {
        this._ui = this._ui || {};
 
        var that = this;
 
        this._ui.onMove = R.is(move, 'function') ?
        move : function(distanceX, distanceY, x, y, deltaX, deltaY) {
            that.translate(deltaX, deltaY);
        };
 
        this._ui.onStart = R.is(start, 'function') ? start : function(x, y) {
        };
 
        function onMove(distanceX, distanceY, x, y) {
            var deltaX = x - that._ui.lastX;
            var deltaY = y - that._ui.lastY;
            that._ui.lastX = x;
            that._ui.lastY = y;
            that._ui.onMove(distanceX, distanceY, x, y, deltaX, deltaY);
            that.paper.safari();
        };
 
        function onStart(x, y) {
            that._ui.lastX = x;
            that._ui.lastY = y;
            that._ui.onStart(x, y);
        };
 
        return this.drag(onMove, onStart, up);
    };
})(Raphael);

上面的一段代码,扩展了 Raphael 对象的方法,让它们拥有了类似 jquery.ui 里 draggable 的能力。下面是用利用这个扩展重新写的拖放 Path 的例子。

var R = Raphael("paper", 400, 300);
R.rect(0, 0, 400, 300);
 
var p = R.path('M0 0L100 0L50 80Z');
 
p.attr({"fill":"green", 'opacity':0.5});
p.draggable();

可以看到,像 jquery.ui 提供的功能一样,只需要简单的调用 .draggable() 就可以让对象被鼠标拖拽

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏大内老A

The .NET of Tomorrow

Ed Charbeneau(http://developer.telerik.com/featured/the-net-of-tomorrow/) Exciti...

30910
来自专栏我和未来有约会

Kit 3D 更新

Kit3D is a 3D graphics engine written for Microsoft Silverlight. Kit3D was inita...

2506
来自专栏一个会写诗的程序员的博客

Spring Reactor 项目核心库Reactor Core

Non-Blocking Reactive Streams Foundation for the JVM both implementing a Reactiv...

2132
来自专栏跟着阿笨一起玩NET

c#实现打印功能

2632
来自专栏Ceph对象存储方案

Luminous版本PG 分布调优

Luminous版本开始新增的balancer模块在PG分布优化方面效果非常明显,操作也非常简便,强烈推荐各位在集群上线之前进行这一操作,能够极大的提升整个集群...

3095
来自专栏陈仁松博客

ASP.NET Core 'Microsoft.Win32.Registry' 错误修复

今天在发布Asp.net Core应用到Azure的时候出现错误InvalidOperationException: Cannot find compilati...

4818
来自专栏芋道源码1024

熔断器 Hystrix 源码解析 —— 断路器 HystrixCircuitBreaker

本文主要基于 Hystrix 1.5.X 版本 1. 概述 2. HystrixCircuitBreaker 3. HystrixCircuitBreaker....

5287
来自专栏闻道于事

js登录滑动验证,不滑动无法登陆

js的判断这里是根据滑块的位置进行判断,应该是用一个flag判断 <%@ page language="java" contentType="text/html...

6688
来自专栏杨龙飞前端

scrollto 到指定位置

2494
来自专栏hbbliyong

WPF Trigger for IsSelected in a DataTemplate for ListBox items

<DataTemplate DataType="{x:Type vm:HeaderSlugViewModel}"> <vw:HeaderSlug...

4054

扫码关注云+社区