###自定义拖动插件
之前学习了canvas标签以及它自带的一些api,发现其实这个东西有点类似与android里的canvas,不过用法上区别还是很大的,但是在实现自定义控件/插件时候,其实原来都是一样的。
当然,我这个web的插件需要用到jquery,参考bootstrap插件开发方式,总结出有如下固定模式或者说模版
(function ($) {//闭包限定命名空间,防止全局污染
var canvasBox = { //定义插件名称
//初始化
init: function (target) {
var $target = $(target);//调用插件的标签层
if ($target.hasClass("canvas-box")) {//增加一个自定义类
$target.html("");
} else {
$target.addClass("canvas-box");
}
var options = $target.data("canvas-box").options;
canvasBox.loadData($target, options.data);
canvasBox.bindEvent($target);
},
//加载数据
loadData: function ($target, data) {
//do something
},
//获取数据
getData: function (target) {
//return something....
},
//绑定事件
bindEvent: function ($target) {
//do something...
}
//其他一些会用到的事件方法....
};
//定义插件
$.fn.canvasBox = function (options, param) {
if (typeof options === "string") {
return $.fn.canvasBox.methods[options](this, param);
} else {
$.each(this, function (index, el) {
var opt = {};
$.extend(opt, $.fn.canvasBox.default);
$.extend(opt, options);
$(this).data("canvas-box", {options: opt});
canvasBox.init(this);
});
}
};
//插件默认属性参数
$.fn.canvasBox.defaults = {
width: 100,
height: 100,
data: []
// ....一些属性参数
};
//插件对外提供的方法
$.fn.canvasBox.methods = {
getData: function (target) {
var data = canvasBox.getData(target);
return data;
},
setData: function (target, data) {
var $target = $(target);
canvasBox.loadData($target, data);
}
//可以自行增加删减需要用到的方法
};
})(jQuery);
如上,有此固定格式,开发一些简单的插件/控件是没有什么问题的。
那么实现了插件/控件,外部调用的示例如下
html增加一div层
<div id="canvas_box"></div>
js代码中,获取该节点
var $canvasBox = $("#canvas_box");
然后实例化插件
var data = {
width:600,
height:200,
data:data//其他数据,比如数组坐标等。。。
};
$canvasBox.canvasBox(data);//实例化插件
知道固定的套路之后,我们就可以尝试着写一个简单的插件了
下面,我们要实现一个利用canvas拖动画布上的点,并且画布上有多个点且是一条连起来的线,拖动点时,与其相连的线也要跟着动起来。
如上图
我们需要实现的是,拖动五个红点中的其中一个,线也要跟着动起来,其实要实现这样效果的原理就是清空画布,重新绘制。这样,不停的清空和绘制,你就会发现,画布上的图是可以动起来的。
如此,知道原理了,我们就可以开始写代码了。
//插件初始化
init: function (target) {
var $target = $(target);//调用插件的标签层
if ($target.hasClass("canvas-box")) {
$target.html("");
} else {
$target.addClass("canvas-box");
}
var options = $target.data("canvas-box").options;
var $container = $("<canvas class='canvas-container'></canvas>").appendTo($target);//嵌套一层canvas
options.container = $container;
$container[0].width = options.width;//获取参数的宽高值,并设置给canvas
$container[0].height = options.height;
if (options.backgroundImg) {//如果有背景图片
$container.css({
"background-image": url(options.backgroundImg)
})
} else {//设置背景颜色
$container.css({
"background-color": options.backgroundColor
});
}
canvasBox.loadData($target, options.data);//加载数据
canvasBox.bindEvent($target);//绑定事件
}
实现加载方法
//加载数据
loadData: function ($target, data) {
var options = $target.data("canvas-box").options;
options.data = data;
var $container = options.container;
var context = $container.get(0).getContext("2d");
context.fillStyle = "red";//点颜色
canvasBox.drawLine(context, data);//初始绘制点和线
}
实现获取数据方法
//获取数据
getData: function (target) {
var $target = $(target);
var options = $target.data("canvas-box").options;
var data = options.data;
return data;
}
实现绑定事件
这里,我们需要绑定鼠标的点击事件,鼠标的移动事件以及鼠标的释放事件的监听,然后根据不同的鼠标事件来绘制我们的画布
//绑定事件
bindEvent: function ($target) {
var options = $target.data("canvas-box").options;
var points = options.data;
var $container = options.container;
var context = $container.get(0).getContext("2d");//获取画笔
context.fillStyle = "red";//点颜色
//点击监听
$container.on("mousedown", function (e) {
var location = canvasBox.getLocation($container.get(0), e.clientX, e.clientY);//因为鼠标点击事件获取到的坐标与canvas绘图坐标不是同一个坐标系,所以需要转换一下
var _x = location.x;
var _y = location.y;
var p = {x: _x, y: _y};
console.log("鼠标点击了 " + "x:" + _x + ",y:" + _y);
console.log("鼠标点击了2 " + "x:" + e.clientX + ",y:" + e.clientY);
var num = canvasBox.IsOnPoint(p, points);//判断鼠标是否点击在了红点上
var draw = false;
if (num !== -1) {
draw = true;
//拖动监听
$container.on("mousemove mouseup", function (e) {
if (!draw) {
return;
}
//清空画布
context.clearRect(0, 0, $container.get(0).width, $container.get(0).height);
var location = canvasBox.getLocation($container.get(0), e.clientX, e.clientY);
points[num].x = location.x;
points[num].y = location.y;
canvasBox.drawLine(context, points);//重新绘制点和线
if (e.type === "mouseup") {
draw = false;
$container.off("mousemove mouseup");
}
});
$("body").on("mouseup", function (e) {//鼠标在cavas外部up后取消监听
draw = false;
$container.off("mousemove mouseup");
});
}
});
}
其实主要的代码就这些
这样交互式的插件,实现起来的原理都差不多,可能还有许多优化的空间。
完整的demo
可以在这里下载
https://download.csdn.net/download/lakebobo/10616796
欢迎留言交流