简单的 HTML5 SVG 移动和调整大小工具





5.00/5 (11投票s)
在本文中,我将一步一步地解释如何使用 HTML5 SVG 实现一个简单的 HTML 元素移动和调整大小的工具。
目录
引言
HTML5 为我们提供了两个新元素,可用于在页面上绘制图形:canvas
和 svg
。canvas
绘图和 svg
绘图之间的主要区别在于 svg
绘图实际上是 HTML 元素。本文演示了如何利用这一特性来创建一个交互式边框(svg
绘图),该边框可用于移动和调整 HTML 元素的大小。
在本第 1 部分中,我们将介绍创建“移动和调整大小”边框的步骤。
在本第 2 部分中,我们将把第 1 部分的结果封装到一个对象中,该对象可以用作通用的“移动和调整大小”工具。
背景
本文假设读者对 SVG 和 jQuery 有基本了解。有关更多信息,您可以阅读以下链接
第 1 部分 - 创建一个简单的 SVG 可移动和可调整大小的形状
绘制 SVG 形状
创建 HTML5 SVG 形状
绘制可移动和可调整大小的形状的第一步是创建一个包含该形状的 HTML 文件。
使用 HTML4.01,我们声明文档类型如下
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
使用 HTML5,声明更简洁
<!DOCTYPE html>
创建 HTML5 文档后,我们可以在其中添加一个简单的 SVG 形状
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="width:350px;height:200px"
id="myShape">
<ellipse cx="50%" cy="50%" rx="50%" ry="50%"
stroke="#FF0000" stroke-width="2" fill="#800000" />
</svg>
用调整大小的指示器包装 SVG 形状
为了用调整大小的边框包装我们的形状,我们添加了另一个 SVG 绘图
<div style="left:100px;top:100px;position:relative;width:350px;height:200px" id="wrapper">
<div style="left:0px;top:0px;position:absolute" class="internalWrapper" >
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="width:350px;height:200px"
id="myShape">
<ellipse cx="50%" cy="50%" rx="50%" ry="50%"
stroke="#FF0000" stroke-width="2" fill="#800000" />
</svg>
</div>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
style="left:0px;top:0px;position:relative;width:100%;height:100%" >
<line x1="0" y1="0" x2="100%" y2="0" stroke="#808080"
stroke-width="1" stroke-dasharray="5,5" />
<line x1="0" y1="100%" x2="100%" y2="100%"
stroke="#808080" stroke-width="1" stroke-dasharray="5,5" />
<line x1="0" y1="0" x2="0" y2="100%" stroke="#808080"
stroke-width="1" stroke-dasharray="5,5" />
<line x1="100%" y1="0" x2="100%" y2="100%" stroke="#808080"
stroke-width="1" stroke-dasharray="5,5" />
<circle cx="0" cy="0" r="3" stroke="#0000FF" stroke-width="1" fill="#CCCCFF" />
<circle cx="100%" cy="0" r="3" stroke="#0000FF" stroke-width="1" fill="#CCCCFF" />
<circle cx="0" cy="100%" r="3" stroke="#0000FF" stroke-width="1" fill="#CCCCFF" />
<circle cx="100%" cy="100%" r="3" stroke="#0000FF" stroke-width="1" fill="#CCCCFF" />
</svg>
</div>
在上面的代码中,我们将 SVG 形状用 div
元素包装,并使用另一个 svg
元素绘制调整大小的边框。我们可以通过仅使用同一个 svg
元素绘制形状及其调整大小的边框来达到相同的效果。但是,当事情变得更复杂时,我们将需要这种分离。
应用鼠标操作
包含 jQuery 库
由于我们将在页面中使用一些 jQuery,因此我们包含 jQuery 库
<script type="text/javascript" src="js/jquery-1.9.1.min.js"></script>
在本例中,jQuery 代码位于 js
文件夹下。(jQuery 库的代码可以从以下网址下载:https://jqueryjs.cn/)
为鼠标操作绘制 SVG 形状
如前所述,svg
绘图是 HTML 元素(与 canvas
绘图不同)。因此,为了使用这些元素应用鼠标操作,我们可以简单地处理它们的适当鼠标事件。由于绘制的边框元素太小,我们添加了另一个较大的透明元素,这为我们提供了更大的区域来捕获鼠标事件。
<line x1="0" y1="0" x2="100%" y2="0" stroke="#000" stroke-width="5" opacity="0" />
<line x1="0" y1="100%" x2="100%" y2="100%" stroke="#000" stroke-width="5" opacity="0" />
<line x1="0" y1="0" x2="0" y2="100%" stroke="#000" stroke-width="5" opacity="0" />
<line x1="100%" y1="0" x2="100%" y2="100%" stroke="#000" stroke-width="5" opacity="0" />
<circle cx="0" cy="0" r="8" stroke="#000" stroke-width="0" fill="#000" opacity="0" />
<circle cx="100%" cy="0" r="8" stroke="#000" stroke-width="0" fill="#000" opacity="0" />
<circle cx="0" cy="100%" r="8" stroke="#000" stroke-width="0" fill="#000" opacity="0" />
<circle cx="100%" cy="100%" r="8" stroke="#000" stroke-width="0" fill="#000" opacity="0" />
除了调整大小的边框,我们还添加了一个透明的矩形以启用移动操作
<rect x="0" y="0" width="100%" height="100%" fill-opacity="0.5" opacity="0" />
处理鼠标事件
定义可能的鼠标操作
在处理鼠标事件以对元素应用操作之前,我们定义支持的操作
var ActionsEnum = {
None: 0,
LeftResize: 1,
TopResize: 2,
RightResize: 3,
BottomResize: 4,
TopLeftResize: 5,
BottomLeftResize: 6,
TopRightResize: 7,
BottomRightResize: 8,
Move: 9
}
适当地设置当前鼠标操作
为了存储当前操作,我们为每个操作触发器(激活操作的 SVG 元素)添加 class
。
<rect x="0" y="0" width="100%" height="100%" fill-opacity="0.5" opacity="0"
class="moveActionTrigger" />
<line x1="0" y1="0" x2="100%" y2="0" stroke="#000" stroke-width="5" opacity="0"
class="topActionTrigger" />
<line x1="0" y1="100%" x2="100%" y2="100%" stroke="#000" stroke-width="5" opacity="0"
class="bottomActionTrigger" />
<line x1="0" y1="0" x2="0" y2="100%" stroke="#000" stroke-width="5" opacity="0"
class="leftActionTrigger" />
<line x1="100%" y1="0" x2="100%" y2="100%" stroke="#000" stroke-width="5" opacity="0"
class="rightActionTrigger" />
<circle cx="0" cy="0" r="8" stroke="#000" stroke-width="0" fill="#000" opacity="0"
class="topLeftActionTrigger" />
<circle cx="100%" cy="0" r="8" stroke="#000" stroke-width="0" fill="#000" opacity="0"
class="topRightActionTrigger" />
<circle cx="0" cy="100%" r="8" stroke="#000" stroke-width="0" fill="#000" opacity="0"
class="bottomLeftActionTrigger" />
<circle cx="100%" cy="100%" r="8" stroke="#000" stroke-width="0" fill="#000" opacity="0"
class="bottomRightActionTrigger" />
添加一个变量来存储当前操作
var currentAction = ActionsEnum.None;
处理每个操作触发器的 mousedown
事件以存储适当的操作
var externalWrapperQueryStr = '#wrapper';
// Query strings for the action-triggers.
var moveActionTriggerQueryStr = externalWrapperQueryStr + ' .moveActionTrigger';
var topActionTriggerQueryStr = externalWrapperQueryStr + ' .topActionTrigger';
var bottomActionTriggerQueryStr = externalWrapperQueryStr + ' .bottomActionTrigger';
var leftActionTriggerQueryStr = externalWrapperQueryStr + ' .leftActionTrigger';
var rightActionTriggerQueryStr = externalWrapperQueryStr + ' .rightActionTrigger';
var topLeftActionTriggerQueryStr = externalWrapperQueryStr + ' .topLeftActionTrigger';
var topRightActionTriggerQueryStr = externalWrapperQueryStr + ' .topRightActionTrigger';
var bottomLeftActionTriggerQueryStr = externalWrapperQueryStr + ' .bottomLeftActionTrigger';
var bottomRightActionTriggerQueryStr = externalWrapperQueryStr + ' .bottomRightActionTrigger';
function initializeEventHandlers() {
$(moveActionTriggerQueryStr).mousedown(function (event) {
currentAction = ActionsEnum.Move;
});
$(topActionTriggerQueryStr).mousedown(function (event) {
currentAction = ActionsEnum.TopResize;
});
$(bottomActionTriggerQueryStr).mousedown(function (event) {
currentAction = ActionsEnum.BottomResize;
});
$(leftActionTriggerQueryStr).mousedown(function (event) {
currentAction = ActionsEnum.LeftResize;
});
$(rightActionTriggerQueryStr).mousedown(function (event) {
currentAction = ActionsEnum.RightResize;
});
$(topLeftActionTriggerQueryStr).mousedown(function (event) {
currentAction = ActionsEnum.TopLeftResize;
});
$(topRightActionTriggerQueryStr).mousedown(function (event) {
currentAction = ActionsEnum.TopRightResize;
});
$(bottomLeftActionTriggerQueryStr).mousedown(function (event) {
currentAction = ActionsEnum.BottomLeftResize;
});
$(bottomRightActionTriggerQueryStr).mousedown(function (event) {
currentAction = ActionsEnum.BottomRightResize;
});
}
$(function () {
initializeEventHandlers();
});
并处理文档的 mouseup
事件以清除存储的操作
function initializeEventHandlers() {
// ...
$(document).mouseup(function (event) {
// Clear the current action.
currentAction = ActionsEnum.None;
});
}
应用适当的鼠标操作
为了对我们的形状应用适当的操作,我们处理文档的 mousemove
事件,以执行适当的操作
- 设置适当的事件处理程序
function initializeEventHandlers() { // ... $(document).mousemove(function (event) { onMouseMove(event); }); }
- 计算鼠标位置的增量
function onMouseMove(event) { var currMouseX = event.clientX; var currMouseY = event.clientY; var deltaX = currMouseX - lastMouseX; var deltaY = currMouseY - lastMouseY; applyMouseMoveAction(deltaX, deltaY); lastMouseX = event.pageX; lastMouseY = event.pageY; }
- 根据当前操作适当地更新大小和位置
function applyMouseMoveAction(deltaX, deltaY) { var deltaTop = 0; var deltaLeft = 0; var deltaWidth = 0; var deltaHeight = 0; if (currentAction == ActionsEnum.RightResize || currentAction == ActionsEnum.TopRightResize || currentAction == ActionsEnum.BottomRightResize) { deltaWidth = deltaX; } if (currentAction == ActionsEnum.LeftResize || currentAction == ActionsEnum.TopLeftResize || currentAction == ActionsEnum.BottomLeftResize) { deltaWidth = -deltaX; deltaLeft = deltaX; } if (currentAction == ActionsEnum.BottomResize || currentAction == ActionsEnum.BottomLeftResize || currentAction == ActionsEnum.BottomRightResize) { deltaHeight = deltaY; } if (currentAction == ActionsEnum.TopResize || currentAction == ActionsEnum.TopLeftResize || currentAction == ActionsEnum.TopRightResize) { deltaHeight = -deltaY; deltaTop = deltaY; } if (currentAction == ActionsEnum.Move) { deltaLeft = deltaX; deltaTop = deltaY; } updatePosition(deltaLeft, deltaTop); updateSize(deltaWidth, deltaHeight); adjustWrapper(); }
- 更新包装器的位置
function updatePosition(deltaLeft, deltaTop) { // Calculate the new position. var elemLeft = parseInt($(externalWrapperQueryStr).css('left')); var elemTop = parseInt($(externalWrapperQueryStr).css('top')); var newLeft = elemLeft + deltaLeft; var newTop = elemTop + deltaTop; // Set the new position. $(externalWrapperQueryStr).css('left', newLeft + 'px'); $(externalWrapperQueryStr).css('top', newTop + 'px'); }
- 更新 SVG 形状的大小
function updateSize(deltaWidth, deltaHeight) { // Calculate the new size. var elemWidth = parseInt($("#myShape").width()); var elemHeight = parseInt($("#myShape").height()); var newWidth = elemWidth + deltaWidth; var newHeight = elemHeight + deltaHeight; // Don't allow a too small size. if (newWidth < 0) { newWidth = 0; } if (newHeight < 0) { newHeight = 0; } // Set the new size. $("#myShape").css('width', newWidth + 'px'); $("#myShape").css('height', newHeight + 'px'); }
- 根据 SVG 形状的大小调整包装器的元素
var internalWrapperQueryStr = externalWrapperQueryStr + ' .internalWrapper'; function adjustWrapper() { var elemWidth = $("#myShape").width(); var elemHeight = $("#myShape").height(); $(internalWrapperQueryStr).width(elemWidth); $(internalWrapperQueryStr).height(elemHeight); $(externalWrapperQueryStr).width(elemWidth); $(externalWrapperQueryStr).height(elemHeight); }
与不同浏览器的兼容性
到目前为止,我们已经创建了一个 SVG 形状,并用 SVG 绘图包装了它,以实现该形状的可移动和可调整大小。使用 Internet Explorer 运行它时,结果符合预期
但是,使用 Chrome 或 Firefox 运行时,我们会得到不同的结果(svg
元素边界外的所有 SVG 绘图都不会显示)。
为了修复此行为,我们将调整大小的边框更改为使用适当的固定值(而不是相对值)进行绘制。为此,我们
- 为调整大小的边框的 SVG 绘图提供一个空间,使其位于
svg
元素的边界内- 将内部包装器的位置设置为偏移
8
像素(角操作触发器的半径)。<div style="left:8px;top:8px;position:absolute" class="internalWrapper" > <!-- ... --> </div>
- 将外部包装器的大小设置为比 SVG 形状大小多
16
像素(每边8
像素)。var cornerActionTriggerRadius = 8; function adjustWrapper() { var elemWidth = parseInt($("#myShape").width()); var elemHeight = parseInt($("#myShape").height()); var externalWrapperWidth = (elemWidth + cornerActionTriggerRadius * 2) + 'px'; var externalWrapperHeight = (elemHeight + cornerActionTriggerRadius * 2) + 'px'; $(internalWrapperQueryStr).width($("#myShape").width()); $(internalWrapperQueryStr).height($("#myShape").height()); $(externalWrapperQueryStr).width(externalWrapperWidth); $(externalWrapperQueryStr).height(externalWrapperHeight); }
- 将内部包装器的位置设置为偏移
- 调整调整大小边框的 SVG 绘图,使其适合
svg
元素的边界- 为调整大小边框的每个元素添加一个
class
。<line x1="0" y1="0" x2="100%" y2="0" stroke="#808080" stroke-width="1" stroke-dasharray="5,5" class="topDrawing" /> <line x1="0" y1="100%" x2="100%" y2="100%" stroke="#808080" stroke-width="1" stroke-dasharray="5,5" class="bottomDrawing" /> <line x1="0" y1="0" x2="0" y2="100%" stroke="#808080" stroke-width="1" stroke-dasharray="5,5" class="leftDrawing" /> <line x1="100%" y1="0" x2="100%" y2="100%" stroke="#808080" stroke-width="1" stroke-dasharray="5,5" class="rightDrawing" /> <circle cx="0" cy="0" r="3" stroke="#0000FF" stroke-width="1" fill="#CCCCFF" class="topLeftDrawing" /> <circle cx="100%" cy="0" r="3" stroke="#0000FF" stroke-width="1" fill="#CCCCFF" class="topRightDrawing" /> <circle cx="0" cy="100%" r="3" stroke="#0000FF" stroke-width="1" fill="#CCCCFF" class="bottomLeftDrawing" /> <circle cx="100%" cy="100%" r="3" stroke="#0000FF" stroke-width="1" fill="#CCCCFF" class="bottomRightDrawing" />
- 定义设置
svg
元素适当属性的函数function setRectangleAttributes(rectQueryStr, x, y, width, height) { var rectElem = $(rectQueryStr); rectElem.attr('x', x); rectElem.attr('y', y); rectElem.attr('width', width); rectElem.attr('height', height); } function setLineAttributes(lineQueryStr, x1, y1, x2, y2) { var lineElem = $(lineQueryStr); lineElem.attr('x1', x1); lineElem.attr('y1', y1); lineElem.attr('x2', x2); lineElem.attr('y2', y2); } function setCircleAttributes(circleQueryStr, cx, cy) { var circleElem = $(circleQueryStr); circleElem.attr('cx', cx); circleElem.attr('cy', cy); }
- 根据 SVG 形状的大小设置调整大小边框的元素
// Query strings for the resizing border's drawings. var topDrawingQueryStr = externalWrapperQueryStr + ' .topDrawing'; var bottomDrawingQueryStr = externalWrapperQueryStr + ' .bottomDrawing'; var leftDrawingQueryStr = externalWrapperQueryStr + ' .leftDrawing'; var rightDrawingQueryStr = externalWrapperQueryStr + ' .rightDrawing'; var topLeftDrawingQueryStr = externalWrapperQueryStr + ' .topLeftDrawing'; var topRightDrawingQueryStr = externalWrapperQueryStr + ' .topRightDrawing'; var bottomLeftDrawingQueryStr = externalWrapperQueryStr + ' .bottomLeftDrawing'; var bottomRightDrawingQueryStr = externalWrapperQueryStr + ' .bottomRightDrawing'; function adjustResizingBorder() { var elemWidth = parseInt($("#myShape").width()); var elemHeight = parseInt($("#myShape").height()); // Get the minimum and maximum values for X and Y. var minX = cornerActionTriggerRadius + 'px'; var minY = cornerActionTriggerRadius + 'px'; var maxX = (cornerActionTriggerRadius + elemWidth) + 'px'; var maxY = (cornerActionTriggerRadius + elemHeight) + 'px'; // Adjust moving rectange. setRectangleAttributes(moveActionTriggerQueryStr, minX, minY, elemWidth + 'px', elemHeight + 'px'); // Adjust resizing border lines. setLineAttributes(topDrawingQueryStr, minX, minY, maxX, minY); setLineAttributes(bottomDrawingQueryStr, minX, maxY, maxX, maxY); setLineAttributes(leftDrawingQueryStr, minX, minY, minX, maxY); setLineAttributes(rightDrawingQueryStr, maxX, minY, maxX, maxY); setLineAttributes(topActionTriggerQueryStr, minX, minY, maxX, minY); setLineAttributes(bottomActionTriggerQueryStr, minX, maxY, maxX, maxY); setLineAttributes(leftActionTriggerQueryStr, minX, minY, minX, maxY); setLineAttributes(rightActionTriggerQueryStr, maxX, minY, maxX, maxY); // Adjust resizing border circles. setCircleAttributes(topLeftDrawingQueryStr, minX, minY); setCircleAttributes(topRightDrawingQueryStr, maxX, minY); setCircleAttributes(bottomLeftDrawingQueryStr, minX, maxY); setCircleAttributes(bottomRightDrawingQueryStr, maxX, maxY); setCircleAttributes(topLeftActionTriggerQueryStr, minX, minY); setCircleAttributes(topRightActionTriggerQueryStr, maxX, minY); setCircleAttributes(bottomLeftActionTriggerQueryStr, minX, maxY); setCircleAttributes(bottomRightActionTriggerQueryStr, maxX, maxY); }
- 为调整大小边框的每个元素添加一个
改善用户体验
鼠标悬停效果
为了给操作触发器添加鼠标悬停效果,我们为每个操作触发器的元素添加一个 class
。
<rect x="0" y="0" width="100%" height="100%" fill-opacity="0.5" opacity="0"
class="actionTrigger moveActionTrigger" />
<line x1="0" y1="0" x2="100%" y2="0" stroke="#000" stroke-width="5" opacity="0"
class="actionTrigger topActionTrigger" />
<line x1="0" y1="100%" x2="100%" y2="100%" stroke="#000" stroke-width="5" opacity="0"
class="actionTrigger bottomActionTrigger" />
<line x1="0" y1="0" x2="0" y2="100%" stroke="#000" stroke-width="5" opacity="0"
class="actionTrigger leftActionTrigger" />
<line x1="100%" y1="0" x2="100%" y2="100%" stroke="#000" stroke-width="5" opacity="0"
class="actionTrigger rightActionTrigger" />
<circle cx="0" cy="0" r="8" stroke="#000" stroke-width="0" fill="#000" opacity="0"
class="actionTrigger topLeftActionTrigger" />
<circle cx="100%" cy="0" r="8" stroke="#000" stroke-width="0" fill="#000" opacity="0"
class="actionTrigger topRightActionTrigger" />
<circle cx="0" cy="100%" r="8" stroke="#000" stroke-width="0" fill="#000" opacity="0"
class="actionTrigger bottomLeftActionTrigger" />
<circle cx="100%" cy="100%" r="8" stroke="#000" stroke-width="0" fill="#000" opacity="0"
class="actionTrigger bottomRightActionTrigger" />
并为该类的 hover
状态添加样式
<style type="text/css">
.actionTrigger
{
transition: opacity 0.5s;
opacity: 0;
}
.actionTrigger:hover
{
transition: opacity 0.3s;
opacity: 0.3;
}
</style>
适当的鼠标光标
为了显示操作触发器的适当鼠标光标,我们可以将适当元素的 cursor
样式设置为适当的鼠标光标。
<rect x="0" y="0" width="100%" height="100%" fill-opacity="0.5" opacity="0"
class="actionTrigger moveActionTrigger" style="cursor:move" />
<line x1="0" y1="0" x2="100%" y2="0" stroke="#000" stroke-width="5" opacity="0"
class="actionTrigger topActionTrigger" style="cursor:n-resize" />
<line x1="0" y1="100%" x2="100%" y2="100%" stroke="#000" stroke-width="5" opacity="0"
class="actionTrigger bottomActionTrigger" style="cursor:s-resize" />
<line x1="0" y1="0" x2="0" y2="100%" stroke="#000" stroke-width="5" opacity="0"
class="actionTrigger leftActionTrigger" style="cursor:w-resize" />
<line x1="100%" y1="0" x2="100%" y2="100%" stroke="#000" stroke-width="5" opacity="0"
class="actionTrigger rightActionTrigger" style="cursor:e-resize" />
<circle cx="0" cy="0" r="8" stroke="#000" stroke-width="0" fill="#000" opacity="0"
class="actionTrigger topLeftActionTrigger" style="cursor:nw-resize" />
<circle cx="100%" cy="0" r="8" stroke="#000" stroke-width="0" fill="#000" opacity="0"
class="actionTrigger topRightActionTrigger" style="cursor:ne-resize" />
<circle cx="0" cy="100%" r="8" stroke="#000" stroke-width="0" fill="#000" opacity="0"
class="actionTrigger bottomLeftActionTrigger" style="cursor:sw-resize" />
<circle cx="100%" cy="100%" r="8" stroke="#000" stroke-width="0" fill="#000" opacity="0"
class="actionTrigger bottomRightActionTrigger" style="cursor:se-resize" />
结果是:
第 2 部分 - 将第 1 部分的结果封装到一个对象中
将移动和调整大小的行为封装到一个对象中
用移动和调整大小的行为包装一个 HTML 元素
在本第 1 部分中,我们使用了一些 SVG 元素创建了一个可移动和可调整大小的形状。在本文的这一部分,我们将创建一个可重用对象,该对象可用于将移动和调整大小的行为应用于任何 HTML 元素(受 position
、left
、top
、width
和 height
CSS 属性影响)。
第一步是:创建一个对象来封装移动和调整大小的逻辑
function MoveAndResizeElementWrapper(elementToWrap) {
this.originalElement = elementToWrap;
}
在此对象构造函数中,我们获取一个 HTML DOM 元素,并将其存储在一个属性中以供稍后使用。
此外,我们还添加了属性来存储包装器元素的 HTML 文本(与我们在第 1 部分创建的元素相同)。
var MoveAndResizeTool_ElementWrapper_wrappersCounter = 0;
function MoveAndResizeElementWrapper(elementToWrap) {
// ...
// Since we want a unique id for each wrapper, we add a counter value to the end of each id.
MoveAndResizeTool_ElementWrapper_wrappersCounter++;
this.wrapperId = 'MoveAndResizeTool_ElementWrapper' +
MoveAndResizeTool_ElementWrapper_wrappersCounter.toString();
this.wrapperStr = '<div style="position:relative" id="' + this.wrapperId + '">' +
'<div style="left:8px;top:8px;position:absolute" class="internalWrapper"></div>' +
'</div>';
}
MoveAndResizeElementWrapper.prototype.resizingBorderStr =
'<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
style="left:0px;top:0px;position:relative;width:100%;height:100%" >' +
'<style type="text/css"> .actionTrigger { transition: opacity 0.5s; ' +
'opacity: 0;} .actionTrigger:hover{transition: opacity 0.3s;opacity: 0.3;}</style>' +
'<line x1="0" y1="0" x2="100%" y2="0" stroke="#808080"
stroke-width="1" stroke-dasharray="5,5" class="topDrawing" />' +
'<line x1="0" y1="100%" x2="100%" y2="100%" stroke="#808080"
stroke-width="1" stroke-dasharray="5,5" class="bottomDrawing" />' +
'<line x1="0" y1="0" x2="0" y2="100%" stroke="#808080"
stroke-width="1" stroke-dasharray="5,5" class="leftDrawing" />' +
'<line x1="100%" y1="0" x2="100%" y2="100%" stroke="#808080"
stroke-width="1" stroke-dasharray="5,5" class="rightDrawing" />' +
'<circle cx="0" cy="0" r="3" stroke="#0000FF" stroke-width="1"
fill="#CCCCFF" class="topLeftDrawing" />' +
'<circle cx="100%" cy="0" r="3" stroke="#0000FF" stroke-width="1"
fill="#CCCCFF" class="topRightDrawing" />' +
'<circle cx="0" cy="100%" r="3" stroke="#0000FF" stroke-width="1"
fill="#CCCCFF" class="bottomLeftDrawing" />' +
'<circle cx="100%" cy="100%" r="3" stroke="#0000FF" stroke-width="1"
fill="#CCCCFF" class="bottomRightDrawing" />' +
'<rect x="0" y="0" width="100%" height="100%" fill-opacity="0.5"
opacity="0" class="actionTrigger moveActionTrigger" style="cursor:move" />' +
'<line x1="0" y1="0" x2="100%" y2="0" stroke="#000" stroke-width="5"
opacity="0" class="actionTrigger topActionTrigger" style="cursor:n-resize" />' +
'<line x1="0" y1="100%" x2="100%" y2="100%" stroke="#000" stroke-width="5"
opacity="0" class="actionTrigger bottomActionTrigger" style="cursor:s-resize" />' +
'<line x1="0" y1="0" x2="0" y2="100%" stroke="#000" stroke-width="5"
opacity="0" class="actionTrigger leftActionTrigger" style="cursor:w-resize" />' +
'<line x1="100%" y1="0" x2="100%" y2="100%" stroke="#000" stroke-width="5"
opacity="0" class="actionTrigger rightActionTrigger" style="cursor:e-resize"/>' +
'<circle cx="0" cy="0" r="8" stroke="#000" stroke-width="0" fill="#000"
opacity="0" class="actionTrigger topLeftActionTrigger" style="cursor:nw-resize" />' +
'<circle cx="100%" cy="0" r="8" stroke="#000" stroke-width="0" fill="#000"
opacity="0" class="actionTrigger topRightActionTrigger" style="cursor:ne-resize" />' +
'<circle cx="0" cy="100%" r="8" stroke="#000" stroke-width="0" fill="#000"
opacity="0" class="actionTrigger bottomLeftActionTrigger" style="cursor:sw-resize" />' +
'<circle cx="100%" cy="100%" r="8" stroke="#000" stroke-width="0"
fill="#000" opacity="0" class="actionTrigger
bottomRightActionTrigger" style="cursor:se-resize" />' +
'</svg>';
添加属性以存储包装器元素的查询字符串
function MoveAndResizeElementWrapper(elementToWrap) {
// ...
this.externalWrapperQueryStr = '#' + this.wrapperId;
this.internalWrapperQueryStr = this.externalWrapperQueryStr + ' .internalWrapper';
// Query strings for the action-triggers.
this.moveActionTriggerQueryStr = this.externalWrapperQueryStr + ' .moveActionTrigger';
this.topActionTriggerQueryStr = this.externalWrapperQueryStr + ' .topActionTrigger';
this.bottomActionTriggerQueryStr = this.externalWrapperQueryStr + ' .bottomActionTrigger';
this.leftActionTriggerQueryStr = this.externalWrapperQueryStr + ' .leftActionTrigger';
this.rightActionTriggerQueryStr = this.externalWrapperQueryStr + ' .rightActionTrigger';
this.topLeftActionTriggerQueryStr = this.externalWrapperQueryStr + ' .topLeftActionTrigger';
this.topRightActionTriggerQueryStr = this.externalWrapperQueryStr + ' .topRightActionTrigger';
this.bottomLeftActionTriggerQueryStr = this.externalWrapperQueryStr + ' .bottomLeftActionTrigger';
this.bottomRightActionTriggerQueryStr = this.externalWrapperQueryStr + ' .bottomRightActionTrigger';
// Query strings for the resizing border's drawings.
this.topDrawingQueryStr = this.externalWrapperQueryStr + ' .topDrawing';
this.bottomDrawingQueryStr = this.externalWrapperQueryStr + ' .bottomDrawing';
this.leftDrawingQueryStr = this.externalWrapperQueryStr + ' .leftDrawing';
this.rightDrawingQueryStr = this.externalWrapperQueryStr + ' .rightDrawing';
this.topLeftDrawingQueryStr = this.externalWrapperQueryStr + ' .topLeftDrawing';
this.topRightDrawingQueryStr = this.externalWrapperQueryStr + ' .topRightDrawing';
this.bottomLeftDrawingQueryStr = this.externalWrapperQueryStr + ' .bottomLeftDrawing';
this.bottomRightDrawingQueryStr = this.externalWrapperQueryStr + ' .bottomRightDrawing';
}
并添加一个函数来包装 HTML 元素
MoveAndResizeElementWrapper.prototype.addWrapperElements = function () {
// Wrap the original element with a resizing border.
$(this.originalElement).wrap(this.wrapperStr);
$(this.internalWrapperQueryStr).after(this.resizingBorderStr);
// Set the external wrapper's position to be 8 (the radius of the
// corner action trigger) pixels less than the original element's position.
var elemLeft = parseInt($(this.originalElement).css('left'));
var elemTop = parseInt($(this.originalElement).css('top'));
var wrapperLeft = (elemLeft - this.cornerActionTriggerRadius) + 'px';
var wrapperTop = (elemTop - this.cornerActionTriggerRadius) + 'px';
$(this.externalWrapperQueryStr).css('left', wrapperLeft);
$(this.externalWrapperQueryStr).css('top', wrapperTop);
$(this.externalWrapperQueryStr).css('position', $(this.originalElement).css('position'));
// Set original element's position to be at the top-left corner of the internal wrapper.
$(this.originalElement).css('left', 0);
$(this.originalElement).css('top', 0);
$(this.originalElement).css('position', 'relative');
}
在包装好 HTML 元素后,我们可以以与第 1 部分相同的方式处理移动和调整大小的行为。为了方便起见,这里是这些函数(这些函数与第 1 部分的等效函数相同,但有一个区别 - 这些函数使用对象属性而不是全局变量)。
- 设置适当的事件处理程序
MoveAndResizeElementWrapper.prototype.initializeEventHandlers = function () { var wrapper = this; $(this.moveActionTriggerQueryStr).mousedown(function (event) { wrapper.currentAction = wrapper.ActionsEnum.Move; }); $(this.topActionTriggerQueryStr).mousedown(function (event) { wrapper.currentAction = wrapper.ActionsEnum.TopResize; }); $(this.bottomActionTriggerQueryStr).mousedown(function (event) { wrapper.currentAction = wrapper.ActionsEnum.BottomResize; }); $(this.leftActionTriggerQueryStr).mousedown(function (event) { wrapper.currentAction = wrapper.ActionsEnum.LeftResize; }); $(this.rightActionTriggerQueryStr).mousedown(function (event) { wrapper.currentAction = wrapper.ActionsEnum.RightResize; }); $(this.topLeftActionTriggerQueryStr).mousedown(function (event) { wrapper.currentAction = wrapper.ActionsEnum.TopLeftResize; }); $(this.topRightActionTriggerQueryStr).mousedown(function (event) { wrapper.currentAction = wrapper.ActionsEnum.TopRightResize; }); $(this.bottomLeftActionTriggerQueryStr).mousedown(function (event) { wrapper.currentAction = wrapper.ActionsEnum.BottomLeftResize; }); $(this.bottomRightActionTriggerQueryStr).mousedown(function (event) { wrapper.currentAction = wrapper.ActionsEnum.BottomRightResize; }); $(document).mouseup(function (event) { // Clear the current action. wrapper.currentAction = wrapper.ActionsEnum.None; }); $(document).mousemove(function (event) { wrapper.onMouseMove(event); }); }
- 处理
mousemove
事件- 计算鼠标位置的增量
MoveAndResizeElementWrapper.prototype.onMouseMove = function (event) { var currMouseX = event.clientX; var currMouseY = event.clientY; var deltaX = currMouseX - this.lastMouseX; var deltaY = currMouseY - this.lastMouseY; this.applyMouseMoveAction(deltaX, deltaY); this.lastMouseX = event.pageX; this.lastMouseY = event.pageY; }
- 根据当前操作适当地更新大小和位置
MoveAndResizeElementWrapper.prototype.applyMouseMoveAction = function (deltaX, deltaY) { var deltaTop = 0; var deltaLeft = 0; var deltaWidth = 0; var deltaHeight = 0; if (this.currentAction == this.ActionsEnum.RightResize || this.currentAction == this.ActionsEnum.TopRightResize || this.currentAction == this.ActionsEnum.BottomRightResize) { deltaWidth = deltaX; } if (this.currentAction == this.ActionsEnum.LeftResize || this.currentAction == this.ActionsEnum.TopLeftResize || this.currentAction == this.ActionsEnum.BottomLeftResize) { deltaWidth = -deltaX; deltaLeft = deltaX; } if (this.currentAction == this.ActionsEnum.BottomResize || this.currentAction == this.ActionsEnum.BottomLeftResize || this.currentAction == this.ActionsEnum.BottomRightResize) { deltaHeight = deltaY; } if (this.currentAction == this.ActionsEnum.TopResize || this.currentAction == this.ActionsEnum.TopLeftResize || this.currentAction == this.ActionsEnum.TopRightResize) { deltaHeight = -deltaY; deltaTop = deltaY; } if (this.currentAction == this.ActionsEnum.Move) { deltaLeft = deltaX; deltaTop = deltaY; } this.updatePosition(deltaLeft, deltaTop); this.updateSize(deltaWidth, deltaHeight); this.adjustWrapper(); }
- 更新包装器的位置
MoveAndResizeElementWrapper.prototype.updatePosition = function (deltaLeft, deltaTop) { // Calculate the new position. var elemLeft = parseInt($(this.externalWrapperQueryStr).css('left')); var elemTop = parseInt($(this.externalWrapperQueryStr).css('top')); var newLeft = elemLeft + deltaLeft; var newTop = elemTop + deltaTop; // Set the new position. $(this.externalWrapperQueryStr).css('left', newLeft + 'px'); $(this.externalWrapperQueryStr).css('top', newTop + 'px'); }
- 更新原始元素的大小
MoveAndResizeElementWrapper.prototype.updateSize = function (deltaWidth, deltaHeight) { // Calculate the new size. var elemWidth = parseInt($(this.originalElement).width()); var elemHeight = parseInt($(this.originalElement).height()); var newWidth = elemWidth + deltaWidth; var newHeight = elemHeight + deltaHeight; // Don't allow a too small size. var minumalSize = this.cornerActionTriggerRadius * 2; if (newWidth < minumalSize) { newWidth = minumalSize; } if (newHeight < minumalSize) { newHeight = minumalSize; } // Set the new size. $(this.originalElement).css('width', newWidth + 'px'); $(this.originalElement).css('height', newHeight + 'px'); }
- 根据原始元素的大小调整包装器的元素
MoveAndResizeElementWrapper.prototype.cornerActionTriggerRadius = 8; MoveAndResizeElementWrapper.prototype.adjustWrapper = function () { var elemWidth = parseInt($(this.originalElement).width()); var elemHeight = parseInt($(this.originalElement).height()); var externalWrapperWidth = (elemWidth + this.cornerActionTriggerRadius * 2) + 'px'; var externalWrapperHeight = (elemHeight + this.cornerActionTriggerRadius * 2) + 'px'; $(this.internalWrapperQueryStr).width($(this.originalElement).width()); $(this.internalWrapperQueryStr).height($(this.originalElement).height()); $(this.externalWrapperQueryStr).width(externalWrapperWidth); $(this.externalWrapperQueryStr).height(externalWrapperHeight); // Adjust the resizing border. this.adjustResizingBorder(); }
- 根据原始元素的大小调整调整大小的边框
MoveAndResizeElementWrapper.prototype.adjustResizingBorder = function () { var elemWidth = parseInt($(this.originalElement).width()); var elemHeight = parseInt($(this.originalElement).height()); // Get the minimum and maximum values for X and Y. var minX = this.cornerActionTriggerRadius + 'px'; var minY = this.cornerActionTriggerRadius + 'px'; var maxX = (this.cornerActionTriggerRadius + elemWidth) + 'px'; var maxY = (this.cornerActionTriggerRadius + elemHeight) + 'px'; // Adjust moving rectange. this.setRectangleAttributes(this.moveActionTriggerQueryStr, minX, minY, elemWidth + 'px', elemHeight + 'px'); // Adjust resizing border lines. this.setLineAttributes(this.topDrawingQueryStr, minX, minY, maxX, minY); this.setLineAttributes(this.bottomDrawingQueryStr, minX, maxY, maxX, maxY); this.setLineAttributes(this.leftDrawingQueryStr, minX, minY, minX, maxY); this.setLineAttributes(this.rightDrawingQueryStr, maxX, minY, maxX, maxY); this.setLineAttributes(this.topActionTriggerQueryStr, minX, minY, maxX, minY); this.setLineAttributes(this.bottomActionTriggerQueryStr, minX, maxY, maxX, maxY); this.setLineAttributes(this.leftActionTriggerQueryStr, minX, minY, minX, maxY); this.setLineAttributes(this.rightActionTriggerQueryStr, maxX, minY, maxX, maxY); // Adjust resizing border circles. this.setCircleAttributes(this.topLeftDrawingQueryStr, minX, minY); this.setCircleAttributes(this.topRightDrawingQueryStr, maxX, minY); this.setCircleAttributes(this.bottomLeftDrawingQueryStr, minX, maxY); this.setCircleAttributes(this.bottomRightDrawingQueryStr, maxX, maxY); this.setCircleAttributes(this.topLeftActionTriggerQueryStr, minX, minY); this.setCircleAttributes(this.topRightActionTriggerQueryStr, maxX, minY); this.setCircleAttributes(this.bottomLeftActionTriggerQueryStr, minX, maxY); this.setCircleAttributes(this.bottomRightActionTriggerQueryStr, maxX, maxY); } MoveAndResizeElementWrapper.prototype.setRectangleAttributes = function (rectQueryStr, x, y, width, height) { var rectElem = $(rectQueryStr); rectElem.attr('x', x); rectElem.attr('y', y); rectElem.attr('width', width); rectElem.attr('height', height); } MoveAndResizeElementWrapper.prototype.setLineAttributes = function (lineQueryStr, x1, y1, x2, y2) { var lineElem = $(lineQueryStr); lineElem.attr('x1', x1); lineElem.attr('y1', y1); lineElem.attr('x2', x2); lineElem.attr('y2', y2); } MoveAndResizeElementWrapper.prototype.setCircleAttributes = function (circleQueryStr, cx, cy) { var circleElem = $(circleQueryStr); circleElem.attr('cx', cx); circleElem.attr('cy', cy); }
- 计算鼠标位置的增量
为了实现包装器的显示和隐藏,我们还添加了两个函数。
MoveAndResizeElementWrapper.prototype.showWrapper = function () {
this.addWrapperElements();
this.initializeEventHandlers();
}
MoveAndResizeElementWrapper.prototype.hideWrapper = function () {
// Set original element's position, to be in the same position, after the wrapper is removed.
var wrapperLeft = parseInt($(this.externalWrapperQueryStr).css('left'));
var wrapperTop = parseInt($(this.externalWrapperQueryStr).css('top'));
var elemLeft = (wrapperLeft + this.cornerActionTriggerRadius) + 'px';
var elemTop = (wrapperTop + this.cornerActionTriggerRadius) + 'px';
$(this.originalElement).css('left', elemLeft);
$(this.originalElement).css('top', elemTop);
$(this.originalElement).css('position', $(this.externalWrapperQueryStr).css('position'));
// Put the original element instead of the wrapped element.
$(this.externalWrapperQueryStr).replaceWith(this.originalElement);
}
通过 jQuery 选择器创建移动和调整大小的包装器
为了根据给定的 jQuery 选择器用移动和调整大小的行为包装 HTML 元素,我们添加了另一个对象。
function MoveAndResizeTool(jquerySelector) {
this.wrappedElements = new Array();
this.isShown = false;
var selectedElements = $(jquerySelector);
for (var elementInx = 0; elementInx < selectedElements.length; elementInx++) {
var currElement = selectedElements[elementInx];
this.wrappedElements[elementInx] = new MoveAndResizeElementWrapper(currElement);
}
}
在此对象构造函数中,我们根据给定的选择器查找适当的 DOM 元素,并为每个元素创建一个移动和调整大小的包装器。
为了实现包装器的显示和隐藏,我们还添加了两个函数。
MoveAndResizeTool.prototype.show = function () {
if (this.isShown == false) {
for (var elementInx = 0; elementInx < this.wrappedElements.length; elementInx++) {
var currElement = this.wrappedElements[elementInx];
currElement.showWrapper();
}
this.isShown = true;
}
}
MoveAndResizeTool.prototype.hide = function () {
if (this.isShown == true) {
for (var elementInx = 0; elementInx < this.wrappedElements.length; elementInx++) {
var currElement = this.wrappedElements[elementInx];
currElement.hideWrapper();
}
this.isShown = false;
}
}
最后,我们添加了一个函数来创建和显示 MoveAndResizeTool
。
function WrapWithMoveAndResizeTool(jquerySelector) {
var resizeTool = new MoveAndResizeTool(jquerySelector);
resizeTool.show();
return resizeTool;
}
使用 MoveAndResizeTool
为了演示创建的 MoveAndResizeTool
的用法,我们创建了一个 HTML 文档,该文档将 MoveAndResizeTool
应用于某些元素。在该文档中,我们
- 添加 jQuery 库和我们的
MoveAndResizeTool
的脚本<script type="text/javascript" src="js/jquery-1.9.1.min.js"></script> <script type="text/javascript" src="js/MoveAndResizeTool.js"></script>
- 添加一些元素
- SVG 元素
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="left:20px;top:200px;width:300px;height:200px;position:absolute" class="mySvgs"> <ellipse cx="50%" cy="50%" rx="50%" ry="50%" stroke="#FF0000" stroke-width="2" fill="#800000" /> </svg> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="left:340px;top:200px;width:100px;height:200px;position:absolute;overflow:hidden" class="mySvgs"> <line x1="0" y1="0" x2="100%" y2="100%" stroke="#008000" stroke-width="15" stroke-linecap="round" /> </svg> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="left:460px;top:200px;width:100px;height:200px;position:absolute" class="mySvgs"> <rect x="0" y="0" width="100%" height="100%" stroke="#8000FF" fill="#8080FF" rx="10" ry="10" stroke-width="5" /> </svg>
- 文本
<div style="left:260px;top:20px;width:100px;height:110px; position:absolute;background:#afa;overflow:hidden; text-overflow:ellipsis" id="myParagraph"> Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text </div>
- Image
<img src="img/Hydrangeas.jpg" alt="An image" id="myImage" style="left:380px;top:20px;width:170px;height:150px;position:absolute" />
- Button
<div style="left:260px;top:140px; width:100px;height:40px;position:absolute" id="myButton"> <button style="left:0px;top:0px;width:100%; height:100%;position:absolute">My button</button> </div>
- SVG 元素
- 用
MoveAndResizeTool
对象包装添加的元素var svgResizeTool; var paragraphResizeTool; var imageResizeTool; var buttonResizeTool; $(function () { svgResizeTool = WrapWithMoveAndResizeTool(".mySvgs"); paragraphResizeTool = WrapWithMoveAndResizeTool("#myParagraph"); imageResizeTool = WrapWithMoveAndResizeTool("#myImage"); buttonResizeTool = WrapWithMoveAndResizeTool("#myButton"); });
- 添加一个面板以启用
MoveAndResizeTool
包装器的显示和隐藏- 用于显示和隐藏
MoveAndResizeTool
包装器的函数function showSvgElementsTool() { svgResizeTool.show(); document.getElementById("btnShowSvg").disabled = true; document.getElementById("btnHideSvg").disabled = false; } function hideSvgElementsTool() { svgResizeTool.hide(); document.getElementById("btnShowSvg").disabled = false; document.getElementById("btnHideSvg").disabled = true; } function showParagraphTool() { paragraphResizeTool.show(); document.getElementById("btnShowParagraph").disabled = true; document.getElementById("btnHideParagraph").disabled = false; } function hideParagraphTool() { paragraphResizeTool.hide(); document.getElementById("btnShowParagraph").disabled = false; document.getElementById("btnHideParagraph").disabled = true; } function showImageTool() { imageResizeTool.show(); document.getElementById("btnShowImage").disabled = true; document.getElementById("btnHideImage").disabled = false; } function hideImageTool() { imageResizeTool.hide(); document.getElementById("btnShowImage").disabled = false; document.getElementById("btnHideImage").disabled = true; } function showButtonTool() { buttonResizeTool.show(); document.getElementById("btnShowButton").disabled = true; document.getElementById("btnHideButton").disabled = false; } function hideButtonTool() { buttonResizeTool.hide(); document.getElementById("btnShowButton").disabled = false; document.getElementById("btnHideButton").disabled = true; }
- 用于激活这些函数的按钮
<div style="left:10px;top:10px;width:auto;height:auto;position:absolute" class="operationsPanel"> <div style="text-align:center;color:#080">Toggle MoveAndResizeTool</div> <table> <tr> <td>SVG elements: </td> <td> <button id="btnShowSvg" onclick="showSvgElementsTool();">Show</button> <button id="btnHideSvg" onclick="hideSvgElementsTool();">Hide</button> </td> </tr> <tr> <td>Paragraph: </td> <td> <button id="btnShowParagraph" onclick="showParagraphTool();">Show</button> <button id="btnHideParagraph" onclick="hideParagraphTool();">Hide</button> </td> </tr> <tr> <td>Image: </td> <td> <button id="btnShowImage" onclick="showImageTool();">Show</button> <button id="btnHideImage" onclick="hideImageTool();">Hide</button> </td> </tr> <tr> <td>Button: </td> <td> <button id="btnShowButton" onclick="showButtonTool();">Show</button> <button id="btnHideButton" onclick="hideButtonTool();">Hide</button> </td> </tr> </table> </div>
- 用于显示和隐藏
结果是: