绘画板 10——多选元素

本贴最后更新于 3100 天前,其中的信息可能已经水流花落

github 地址: https://github.com/wangyuheng/painter

DEMO 地址: http://painter.crick.wang/

多选元素

原理

在选择按钮状态下,可以绘制一个曲线矩形,遍历所有元素判断,如果当前元素在矩形的坐标范围内,则元素被选中。

矩形四个点的坐标范围为 x,x+width,y,y+height

变更 element click 事件

选择元素时,需要触发元素选中事件。如果触发 click,会增加额外判断,并延时。所以单独抽离 pick 事件,将 click 中的事件处理指向 pick

_ele.on("click", function() { if (GlobalStatus.isPreFilled()) { if ($("#fill_color").hasClass("active")) { _ele.fill(GlobalStatus.getFillColor()); _ele.style("fill-opacity", GlobalStatus.getFillOpacity()); } else { _ele.style("stroke", GlobalStatus.getFontColor()); } } else if (GlobalStatus.isPicked()) { _ele.fire("pick"); } else if (GlobalStatus.isRecycle()) { _ele.remove(); } }); _ele.on("pick", function() { if (_ele.attr("picked")) { _ele.attr("picked", null); _ele.handleBorder && _ele.handleBorder.hideShade(_ele); GlobalStatus.removePicked(_ele); } else { _ele.attr("picked", true); _ele.handleBorder = _ele.handleBorder || new HandleBorder(svgDoc); _ele.handleBorder.showShade(_ele); GlobalStatus.pushPicked(_ele); } });

新增 draw.tool.pick.js

新增 DrawTool.Pick,操作与 Rect 类似,唯一的区别在于 mouseup 时判断元素是否在绘制的虚线矩形范围内,并对应触发 pick 事件。

(function() { var parent = null; var drawing = false; var element = null; var startPoint = null; function mousedown(event) { console.log('pick mousedown'); drawing = true; startPoint = svgDoc.transformPoint(event); element = parent.rect(0, 0).fill(GlobalStatus.getFillColor()).style({ "fill-opacity": GlobalStatus.getFillOpacity(), "stroke-dasharray": "13 10" }).stroke({ width: "1", color: "grey" }); return false; } function mousemove(event) { console.log('pick mousemove'); if (drawing) { var svgPoint = svgDoc.transformPoint(event); var x = svgPoint.x; var y = svgPoint.y; var newWidth = x - startPoint.x; var newHeight = y - startPoint.y; var startX = startPoint.x; var startY = startPoint.y; if (newWidth < 0) { startX += newWidth; } if (newHeight < 0) { startY += newHeight; } newWidth = Math.abs(newWidth); newHeight = Math.abs(newHeight); element.x(startX).y(startY).width(newWidth).height(newHeight); } return false; }; function mouseup(event) { console.log('pick mouseup ' + element); drawing = false; if (element.attr("width") > 0) { var sx = element.x(); var ex = element.x() + element.width(); var sy = element.y(); var ey = element.y() + element.height(); $(GlobalStatus.getAllElements()).each(function() { console.log(this.x(), this.y(), sx < this.x() && this.x() < ex && sy < this.y() && this.y() < ey); if (sx < this.x() && this.x() < ex && sy < this.y() && this.y() < ey) { if (!this.attr("picked")) { this.fire("pick"); } } else if (this.attr("picked")) { this.fire("pick"); } }) } parent.removeElement(element); return false; } var listener = { mousedown: mousedown, mousemove: mousemove, mouseup: mouseup, }; var Pick = function(parentEle) { parent = parentEle; console.log(parent); svgDoc = parent.doc(); DrawTool.init(svgDoc, listener); this.stop = function() { DrawTool.stop(svgDoc, listener); }; }; this.DrawTool.Pick = Pick; })();

首页监听选择按钮

在首页监听选择按钮,被选中时,创建 DrawTool.Pick 对象

$("#tool_pick").on("click", function() { resetCurrentDrawTool(); currentDrawTool = new DrawTool.Pick(svgDoc); });

弊端

有一个不足的地方,元素必须全在范围内,才能被选中。如果被选中部分,则无法选中。没想到好的解决方案。

bug 修复

picked 状态混乱

click 和 mouseup 互相冲突,导致选中状态丢失。

将 pick 拆分为 pick 和 unPick 两个事件,分别处理选中状态,而不进行判断。将判断交给上层调用方法

_ele.on("click", function() { console.log("click"); if (GlobalStatus.isPreFilled()) { if ($("#fill_color").hasClass("active")) { _ele.fill(GlobalStatus.getFillColor()); _ele.style("fill-opacity", GlobalStatus.getFillOpacity()); } else { _ele.style("stroke", GlobalStatus.getFontColor()); } } else if (GlobalStatus.isPicked()) { if (_ele.attr("picked")) { _ele.fire("unPick"); } else { _ele.fire("pick"); } } else if (GlobalStatus.isRecycle()) { _ele.remove(); } }); _ele.on("pick", function() { console.log("pick"); _ele.attr("picked", true); _ele.handleBorder = _ele.handleBorder || new HandleBorder(svgDoc); _ele.handleBorder.showShade(_ele); GlobalStatus.pushPicked(_ele); }); _ele.on("unPick", function() { console.log("unPick"); _ele.attr("picked", null); _ele.handleBorder && _ele.handleBorder.hideShade(_ele); GlobalStatus.removePicked(_ele); });

Pick 中

function mouseup(event) { console.log('pick mouseup ' + element); if (drawing) { drawing = false; if (element && element.attr("width") > 20) { var sx = element.x(); var ex = element.x() + element.width(); var sy = element.y(); var ey = element.y() + element.height(); $(GlobalStatus.getAllElements()).each(function() { console.log(this.x(), this.y(), sx < this.x() && this.x() < ex && sy < this.y() && this.y() < ey); if (sx < this.x() && this.x() < ex && sy < this.y() && this.y() < ey) { if (!this.attr("picked")) { this.fire("pick"); } } else if (this.attr("picked")) { this.fire("unPick"); } }) } element && element.remove(); } return false; }

Pick 拥有背景色

修改 Pick 的 mousedown 方法,独立设置 style,不关联颜色选择器

function mousedown(event) { console.log('pick mousedown'); if (!drawing) { drawing = true; startPoint = svgDoc.transformPoint(event); element = parent.rect(0, 0).style({ "fill-opacity": "0.0", "stroke-dasharray": "10" }).stroke({ width: "1", color: "grey" }); } return false; }

mousedown 状态鼠标移出画板范围,松开鼠标,再次回到画板范围内,导致状态丢失

再回到画板时,鼠标已经移开,但是并未执行 mouseup 方法,因为时间的监听范围为画板内。所以 mouseover 事件继续执行,导致多生成了一个 element。为了避免此问题,在 mouse 事件中增加 drawing 状态判断,以 Rect 为例

(function() { var parent = null; var drawing = false; var element = null; var startPoint = null; function mousedown(event) { console.log('rect mousedown'); if (!drawing) { drawing = true; startPoint = svgDoc.transformPoint(event); element = parent.rect(0, 0).fill(GlobalStatus.getFillColor()).style("fill-opacity", GlobalStatus.getFillOpacity()).stroke({ width: GlobalStatus.getLineSize(), color: GlobalStatus.getFontColor() }); } return false; } function mousemove(event) { console.log('rect mousemove'); if (drawing) { var svgPoint = svgDoc.transformPoint(event); var x = svgPoint.x; var y = svgPoint.y; var newWidth = x - startPoint.x; var newHeight = y - startPoint.y; var startX = startPoint.x; var startY = startPoint.y; if (newWidth < 0) { startX += newWidth; } if (newHeight < 0) { startY += newHeight; } newWidth = Math.abs(newWidth); newHeight = Math.abs(newHeight); element.x(startX).y(startY).width(newWidth).height(newHeight); } return false; }; function mouseup(event) { console.log('rect mouseup ' + element); if (drawing) { drawing = false; if (element.attr("width") > 0) { element.pickable(); } else { parent.removeElement(element); } } return false; } var listener = { mousedown: mousedown, mousemove: mousemove, mouseup: mouseup, }; var Rect = function(parentEle) { parent = parentEle; console.log(parent); svgDoc = parent.doc(); DrawTool.init(svgDoc, listener); this.stop = function() { DrawTool.stop(svgDoc, listener); }; }; this.DrawTool.Rect = Rect; })();

所有 DrawTool 类方法都要增加此

bug 修复

选择其他 DrawTool 后,选中状态不丢失。

在 GlobalStatus 增加清除所有选中状态的方法

unPickAll() { $(GlobalStatus.getPickeds()).each(function() { this.fire("unPick"); }); return this; }

在 index 的 resetCurrentDrawTool 方法中调用执行

function resetCurrentDrawTool() { currentDrawTool && currentDrawTool.stop(); GlobalStatus.unPickAll(); $("#svgPanel").css("cursor", "default"); }

同时给右键的取消按钮增加此方法调用

label: ' 取消', action: function () { GlobalStatus.unPickAll(); return false; }
  • 开源

    Open Source, Open Mind, Open Sight, Open Future!

    409 引用 • 3587 回帖 • 1 关注
  • SVG
    24 引用 • 73 回帖
  • Painter
    14 引用 • 31 回帖
  • 多选
    1 引用 • 2 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • relyn

    前端真好玩

  • 其他回帖
  • 714593351

    ]ۣۣۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖ[]ۣۣۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖۖ