简单实现svg的拖拽和缩放

简单实现svg的拖拽和缩放,第1张

此方法限制太多,可能

svg使用d3绘制,并且抽象出svg中所有元素的一个参照点和缩放比例

svg元素不会太多,否则会造成卡顿。

最近有个项目需要我帮一下前端,主要是使用d3绘制svg放在页面,其中有一个功能就是对绘制的svg进行拖动和缩放,有点像地图。

这里我已经写好了一个方法来绘制svg

其中svg是要绘制的元素,data是要绘制的数据,x,y是svg的中心坐标,svgA是父元素的边长,来控制svg(正方形)刚好在父元素内,radio是缩放比例

实现方式是<font color='red'>重绘</font>,所以元素太多会造成卡顿。

一、拖拽

我们来分析拖拽的过程,鼠标按下---->鼠标移动------>松开鼠标。对应的事件分别是mousedown、mousemove、mouseup,先定义两个全局变量

鼠标按下事件

鼠标移动事件

最后放开鼠标

一个问题,毋庸置疑这三个事件都注册在svg元素(或者与svg等大的父元素)上,但是当鼠标拖到svg外面时,在svg外面放开了鼠标,鼠标回到svg中,图形会随着鼠标移动,这样是不应该的,所以应该把最后一个事件mouseup注册到最外面的元素上,那么鼠标在svg外放开也可以触发。

二、缩放

缩放的实现和拖拽类似,相同的就不赘述了。

缩放是根据鼠标滚轮的事件触发,但是鼠标滚轮有他的默认事件,那就是页面滚动,这里要阻止它。

对于缩放,我是想做对于鼠标位置放大和缩小,这里要获取到鼠标相对于父元素的坐标(具体做法可以参考上篇文章),保证鼠标放在的那一点相对于父元素的坐标(后都称绝对坐标)不变,再计算中心坐标的偏移量,一开始我是使用矩阵的坐标变换做的,计算量很大,结果显示并不如预期,并且当时矩阵坐标变换也学的不好,我怀疑是算错了,然后突然想到向量,发现用向量的话计算量大大降低,结果显示还是一样。最后还是做的关于中心坐标(包括拖拽后的)的缩放。

对于没能将图形在鼠标位置放大缩小的原因,我认为是做法有问题,项目中的svg图形是以中心点开始向外发散绘制的,所以不应该是鼠标那一点绝对坐标不变,而应该是鼠标所在的元素组的参考点绝对坐标不变。但是实现起来太麻烦,另外如果鼠标没有在任何一个元素组也不好处理,所以干脆以中心坐标不变吧。

另外,此方法简单粗暴,但用处并不太大,只做对拖拽和缩放的理解使用。

最尴尬的是在写这篇博客的时候我看到了一篇文章,让我知道了有 transform ,汗呐!!!

>

Dim x1 As Integer, y1 As Integer Dim x2 As Integer, y2 As Integer Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single) If Button = 1 Then x1 = X: y1 = Y End Sub Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single) If Button = 1 Then MeCls MeLine (x1, y1)-(X, Y), , B '显示方框图形 End If End Sub Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single) x2 = X: y2 = Y If x1 <> x2 And y1 <> y2 Then ' 如果鼠标移动了 MeCurrentX = 0 MeCurrentY = 0 '打印位置到0,0 Print "起点坐标x=" & x1 & " y=" & y1 Print "终点坐标x=" & x2 & " y=" & y2 End If End Sub

uBuilder功能

z坐标)

z坐标)

(y坐标)

转换指定对象的相对坐标为绝对坐标

Vector3类型的绝对坐标点

Shift:按住可在3D场景下旋转物体角度,点要旋转物体时方向的小球有3个点,代表3个坐标轴的方向,可以固定每次15度角旋转。

常见问题

答:不支持作为底图使用。由于百度地图坐标系的坐标原点的特殊性,我们目前不支持百度地图作为地理底图。如果坐标数据来自于百度地图,数据上传时选择“百度坐标系”,可以与其他的地理底图进行匹配。

答:出现位置偏移,一般是数据与底图采用的坐标系不一致。CityBuilder中,除OSM底图全世界都是WGS84坐标系外,其他底图在国内采用的GCJ02坐标系。

如果数据与OSM匹配,则说明数据现在是WGS84坐标系,在上传数据时您选错了数据源的坐标系,应该选择WGS84

坐标系;

如果都不能匹配且偏移量小,那可能您的数据源是百度坐标系,而在上传时选错了坐标系,应该选择百度坐标系;

如果都不能匹配且偏移量很大,可能是数据源本身的问题,或者坐标经纬度写反了(csv或Excel格式常发生这种情况)。

常见问题

坐标系

坐标系概念

以场景原点为中心的直角坐标系称为世界坐标。

在 ThingJS 中所有的物体的 position 值均为世界坐标,排列为 [x,y,z] 。

世界坐标系

当在场景中创建了园区,在园区下我们放置一个模型,模型是园区的子物体,我们想在园区的坐标系下,设置模型的位置,这时使用的园区的坐标系,就是模型的父物体坐标系。

父物体坐标系

自身坐标系

某对象向前移动 2 米,就是在自身坐标系下设置坐标 [0

控件

position: 相对屏幕坐标的定位位置;

场景工具

拾取坐标

点击“拾取坐标”,d出“拾取坐标”面板,可在此开启“拾取坐标”功能;

开启“拾取坐标”功能后,在3D容器内点击要获取的位置,“坐标信息”面板将提供该位置的坐标;

鼠标移至需要使用的坐标数组处,单击复制。

全景球数据

// 世界坐标系下的物体坐标

'localPosition':[]// 父物体坐标系下的物体坐标

摄影机

我们可以通过相对于目标物体的坐标系下 x 轴旋转角度、 y 轴旋转角度以及距目标物体“中心”的距离来确定一个位置,作为“看点”的 position 位置。

rotateAround 让摄像机环绕某坐标点(世界坐标系下)或某物体旋转飞行

//环绕的坐标点

通过 target 设置环绕的坐标点;

屏幕坐标与3D世界坐标转换

可通过 worldToScreen() , screenToWorld() 进行 3D 世界坐标和 2D 屏幕坐标的相互转换。

2D 屏幕坐标系以左上角为原点,向右为 X 正向,向下为 Y 正向

//世界坐标系下3D坐标转换成2D屏幕坐标

//分别代表屏幕X坐标、Y坐标、Z深度

//屏幕坐标转3D世界坐标

//传入屏幕坐标

//返回三维坐标

//该坐标为经过摄像机position,target两点的直线 与 世界坐标系下过target点的垂直平面的交点

屏幕坐标转 3D 世界坐标返回的为经过摄像机 position , target 两点的直线与三维世界坐标系下平面的交点,见下图:

园区与层级

在 ThingJS 在线开发中,将“办公楼TMP”下的楼层“挂接”到“办公楼”时,设置楼层的相对坐标。

// 设置相对坐标,楼层相对于建筑的位置保持一致

地图数据

常用坐标系

坐标系

WGS84地理坐标系

目前广泛使用的GPS使用的坐标系

GCJ02 火星坐标系

由中国国家测绘局制订的地理信息系统的坐标系统。是WGS84坐标系经加密后的坐标系。

BD09 百度坐标系

在GCJ02坐标系基础上再次加密。其中bd09ll表示百度经纬度坐标,bd09mc表示百度墨卡托米制坐标

由于百度地图坐标系的坐标原点的特殊性,CityBuilder目前不支持百度地图的瓦片服务。

如果坐标数据来自于百度地图,数据上传时选择“百度坐标系”,可以与其他的地理底图进行匹配。

坐标系-中国区

综合应用

// 设置相对坐标,楼层相对于建筑的位置保持一致

// 设置相对坐标,楼层相对于建筑的位置保持一致

// 设置相对坐标,楼层相对于建筑的位置保持一致

// 设置相对坐标,楼层相对于建筑的位置保持一致

相对关系与坐标转换

坐标转换

之前的教程中已经讲解过了坐标转换,本章不在做多余赘述。

为了让大家更容易理解与使用相对关系与坐标转化,我们新增了一个 示例。

对于一些有摆放规律或者有位置信息的管理对象(比如书柜里的书、楼层里的烟雾感应器、消防喷淋器),我们可以动态的请求数据来进行批量创建。在这种应用场景下创建管理对象时,建议设置对象的父物体、使用相对坐标,以更方便的进行对象的管理和控制。

界面介绍

工具:主要包括场景信息、场景效果、拾取坐标、自定义模型和设置。详细介绍请参照 在线开发 - 菜单导航 - 场景工具。

拾取和选择

//启动框选 传入 鼠标按下时开始框选的屏幕坐标

图层

// 根据经纬度坐标创建一条纯色渲染的线

// 根据两点经纬度坐标创建一条从北京 到 天津 的连线

// 起点 终点 坐标

// 根据经纬度坐标创建一个多边形

地理对象

coordinates: 点的经纬度坐标,坐标格式为[经度

对于GeoPoint类型的物体,通过 moveGeoPath方法可使它沿着经纬度坐标构成的路径移动。

path:为一个由经纬度坐标串构成的路径数组

coordinates: 线的经纬度坐标,由一串点的经纬度坐标组成

coordinates: 线的经纬度坐标,由一串点的经纬度坐标组成

事件

{Array} ClickpickedPosition 获取拾取点坐标

{Array} DBLClickpickedPosition 获取拾取点坐标

{Array} SingleClickpickedPosition 获取拾取点坐标

{Array} MouseUppickedPosition 获取拾取点坐标

{Array} MouseDownpickedPosition 获取拾取点坐标

{Array} MouseDownpickedPosition 获取拾取点坐标

{Array} MouseMovepickedPosition 获取拾取点坐标

{Array} DragStartpickedPosition 获取拾取点坐标

{Array} DragpickedPosition 获取拾取点坐标

{Array} DragEndpickedPosition 获取拾取点坐标

{Array} CameraChangeStarttarget 摄像机观察点世界坐标信息

{Array} CameraChangeStartposition 摄像机世界坐标信息

{Array} CameraChangeEndtarget 摄像机观察点世界坐标信息

{Array} CameraChangeEndposition 摄像机世界坐标信息

{Array} CameraChangetarget 摄像机观察点世界坐标信息

{Array} CameraChangeposition 摄像机世界坐标信息

创建对象

angles:设置世界坐标系下三轴旋转角度,例如:angles:[90

90] ,代表在世界坐标系下物体沿X轴旋转90度

scale:设置相对自身坐标系下的缩放比例

position:世界坐标系下位置

localPosition:父物体坐标下的位置

angles:世界坐标系下三轴旋转角度

localAngles:世界父物体坐标系下三轴旋转角度

scale:自身坐标系下三轴缩放量

控制对象

要想控制一个对象物体的空间位置,首先需要理解空间坐标系。

我们使用右手坐标系,但不同于我们平时熟悉的坐标系,平时通常是 z 轴向上,我们使用的坐标系是 y 轴向上,如图:

描述或控制一个物体的位置,我们在不同情况下会分别使用 3 套坐标系统:

世界坐标系

父物体坐标系

自身坐标系

z]位置坐标的单位均为米。

世界坐标系

世界坐标系是系统的绝对坐标系,当场景(注意不是指园区)创建后,在整个场景空间中标绘一个位置,此时场景空间的坐标系就是世界坐标系。

一个物体在世界坐标系下控制物体位置直接使用 position 属性,如:

获取世界坐标系下的物体位置,也直接使用 position 属性,如:

父物体坐标系:

当在场景中创建了园区,在园区下我们放置一个飞机,飞机是园区的子物体,我们想在园区的坐标系下,设置飞机的位置,这时使用的园区的坐标系,就是飞机的父物体坐标系。

再举个例子,我们想给一个人物添加一顶帽子,因为人在场景里位置和方向是不确定的,在世界坐标系下设置帽子的位置,要经过非常复杂的计算。但不管人在哪,面向哪,帽子和人的相对位置是一定的,所以我们在以人为坐标系的情况下就很容易把帽子放到正确的位置。前提是帽子是人的子物体,人的坐标系就是帽子的父物体坐标系

一个物体要在父物体坐标系下设置或获取位置我们使用 localPosition 属性。

自身坐标系:

聪明的你,一定能想到,有时候我们也希望在以自身作为坐标系统下控制,比如,叉车向前走2米,就是在自身坐标系下设置坐标[0

一个物体在自身坐标系下控制位置使用如下接口:

在世界坐标系下,使用 angles 属性来设置或访问旋转信息。

0] //设置世界坐标系Y轴向旋转45角度

在父物体坐标系下,使用 localAngles 属性来设置或访问旋转信息。

0] //设置父物体坐标系Y轴向旋转45角度

在自身坐标系下,使用如下接口方法:

//使用rotate,可输入角度和轴向。设置沿给定轴向转一定角度,传入的旋转轴是自身坐标系下的轴方向

0],该坐标是在世界坐标下

对于缩放,是个 3D 里面比较复杂的概念,我们这里只提供自身坐标系下的缩放控制。

物体自身坐标系的原点,就是这个物体的轴心点(pivot)。

一个物体在世界坐标系和父坐标系下的位置,其实就是物体轴心点在世界坐标系下和父坐标系下的位置,物体在自身坐标系下的旋转和放缩,也是基于轴心点。

物体在世界坐标系下的旋转的正确理解

一个物体在世界坐标系下的坐标位置是 [10

45]。我们该如何理解沿世界坐标系 Z 轴旋转的 45 度呢?

等于先把物体放到世界坐标原点下

将物体沿世界坐标的 Z 轴旋转 45 度

将物体放置到世界坐标系下的 [10

等于先把物体放到世界坐标原点下

将物体放置到世界坐标系下的 [10

将物体沿世界坐标的 Z 轴旋转 45 度

position :在世界坐标系下设置目标位置,关于获取坐标点可使用坐标拾取工具

offsetPosition :在自身坐标系下设置目标位置,和 position 任选其一设置

scale :在自身坐标系下三个轴向目标缩放值

// 路径坐标点数组

// 路径坐标点数组

path :由世界坐标系下的坐标点组成的路径,关于获取坐标点可使用坐标拾取工具

坐标转换

对一个物体我们已经了解针对它的3种坐标系统,可以在不同情况下使用对应方式,很方便地控制或获取物体位置。

但在有些时候,我们需要三套坐标体系坐标的转换,我们使用如下接口:

// 将输入的物体自身坐标系下坐标转换成世界坐标

// 将输入的世界坐标标转换成物体自身坐标系下坐标

// 世界坐标下的位置

0] // 相对于父物体的坐标

此时,“连接” 的一刻,子物体将以设置的相对坐标作为与父物体的相对位置关系,并保持此相对位置关系。

// 世界坐标下的位置

0] // 相对于父物体的坐标

2D/3D界面

offset : 设置自身坐标系下偏移量为[0

offset : 设置自身坐标系下偏移量为[0

using System;

using SystemCollectionsGeneric;

using SystemComponentModel;

using SystemData;

using SystemDrawing;

using SystemText;

using SystemWindowsForms;

using SystemDrawingImaging;

namespace qiequtupian

{

public partial class mainform : Form

{

bool isDrag = false;

Rectangle theRectangle = new Rectangle(new Point(0, 0), new Size(0, 0));

Point startPoint, oldPoint;

private Graphics ig;

public Form1()

{

InitializeComponent();

}

private void button1_Click(object sender, EventArgs e)

{

openFileDialog1Filter = "jpg,jpeg,bmp,gif,ico,png,tif,wmf|jpg;jpeg;bmp;gif;ico;png;tif;wmf";

openFileDialog1ShowDialog();

Image myImage = SystemDrawingImageFromFile(openFileDialog1FileName);

pictureBox1Image = myImage;

}

private void pictureBox1_MouseDown(object sender, MouseEventArgs e)

{

if (eButton == MouseButtonsLeft)

{

//如果开始绘制,则开始记录鼠标位置

if ((isDrag = !isDrag) == true)

{

startPoint = new Point(eX, eY);

oldPoint = new Point(eX, eY);

}

}

}

private void pictureBox1_MouseUp(object sender, MouseEventArgs e)

{

isDrag = false;

ig = pictureBox1CreateGraphics();

igDrawRectangle(new Pen(ColorBlack, 1), startPointX, startPointY, eX - startPointX, eY - startPointY);

theRectangle = new Rectangle(startPointX, startPointY, eX - startPointX, eY - startPointY);

}

private void pictureBox1_MouseMove(object sender, MouseEventArgs e)

{

Graphics g = thisCreateGraphics();

if (isDrag)

{

gDrawRectangle(new Pen(ColorBlack, 1), startPointX, startPointY, eX - startPointX, eY - startPointY);

}

}

private void Form1_MouseClick(object sender, MouseEventArgs e)

{

try

{

Graphics graphics = thisCreateGraphics();

Bitmap bitmap = new Bitmap(pictureBox1Image);

Bitmap cloneBitmap = bitmapClone(theRectangle, PixelFormatDontCare);

graphicsDrawImage(cloneBitmap, eX, eY);

Graphics g = pictureBox1CreateGraphics();

SolidBrush myBrush = new SolidBrush(ColorWhite);

gFillRectangle(myBrush, theRectangle);

}

catch

{ }

}

}

}

Javascript的特点是dom的处理与网页效果,大多数情况我们只用到了这个语言的最简单的功能,比如制作轮播/网页的tab等等,这篇文章将向你展示如何在自己的网页上制作拖拽.

有很多理由让你的网站加入拖拽功能,最简单的一个是数据重组.例如:你有一个序列的内容让用户排序,用户需要给每个条目进行输入或者用select 选择,替代前面这个方法的就是拖拽.或许你的网站也需要一个用户可以拖动的导航窗口!那么这些效果都是很简单:因为你可以很容易的实现!

网页上实现拖拽其实也不是很复杂.第一你需要知道鼠标坐标,第二你需要知道用户鼠标点击一个网页元素并实现拖拽,最后我们要实现移动这个元素.

获取鼠标移动信息

第一我们需要获取鼠标的坐标.我们加一个用户函数到documentonmousemove就可以了:

Java代码 收藏代码

documentonmousemove = mouseMove;

function mouseMove(ev){

ev = ev || windowevent;

var mousePos = mouseCoords(ev);

}

function mouseCoords(ev){

if(evpageX || evpageY){

return {x:evpageX, y:evpageY};

}

return {

x:evclientX + documentbodyscrollLeft - documentbodyclientLeft,

y:evclientY + documentbodyscrollTop - documentbodyclientTop

};

}

你首先要声明一个evnet对象.不论何时你移动鼠标/点击/按键等等,会对应一个event的事件.在Internet Explorer里event是全局变量,会被存储在windowevent里. 在firefox中,或者其他浏览器,event事件会被相应的自定义函数获取.当我们将mouseMove函数赋值于documentonmousemove,mouseMove会获取鼠标移动事件.

(ev = ev || windowevent) 这样让ev在所有浏览器下获取了event事件,在Firefox下"||windowevent"将不起作用,因为ev已经有了赋值.在MSIE下ev是空的,所以ev将设置为windowevent

因为我们在这篇文章中需要多次获取鼠标坐标,所以我们设计了mouseCoords这个函数,它只包含了一个参数,就是the event

我们需要运行在MSIE与Firefox为首的其他浏览器下.Firefox以eventpageX和eventpageY来代表鼠标相应于文档左上角的位置.如果你有一个500500的窗口,而且你的鼠标在正中间,那么paegX和pageY将是250,当你将页面往下滚动500px,那么 pageY将是750此时pageX不变,还是250

MSIE和这个相反,MSIE将eventclientX与eventclientY来代表鼠标与ie窗口的位置,并不是文档.当我们有一个 500500的窗口,鼠标在正中间,那么clientX与clientY也是250,如果你垂直滚动窗口到任何位置,clientY仍然是250,因为相对ie窗口并没有变化.想得到正确的结果,我们必须加入scrollLeft与scrollTop这两个相对于文档鼠标位置的属性.最后,由于MSIE 并没有0,0的文档起始位置,因为通常会设置2px的边框在周围,边框的宽度包含在documentbodyclientLeft与 clientTop这两个属性中,我们再加入这些到鼠标的位置中.

很幸运,这样mouseCoords函数就完成了,我们不再为坐标的事 *** 心了.

捕捉鼠标点击

下次我们将知道鼠标何时点击与何时放开.如果我们跳过这一步,我们在做拖拽时将永远不知道鼠标移动上面时的动作,这将是恼人的与违反直觉的.

这里有两个函数帮助我们:onmousedown与onmouseup我们预先设置函数来接收documentonmousemove,这样看起来很象我们会获取documentonmousedown与documentonmouseup.但是当我们获取 documentonmousedown时,我们同时获取了任何对象的点击属性如:text,images,tables等等我们只想获取那些需要拖拽的属性,所以我们设置函数来获取我们需要移动的对象.

移动一个元素

我们知道了怎么捕捉鼠标移动与点击.剩下的就是移动元素了.首先,要确定一个明确的页面位置,css样式表要用'absolute'设置元素绝对位置意味着我们可以用样式表的top和left来定位,可以用相对位置来定位了.我们将鼠标的移动全部相对页面top-left,基于这点,我们可以进行下一步了.

当我们定义itemstyleposition='absolute',所有的 *** 作都是改变left坐标与top坐标,然后它移动了.

Java代码 收藏代码

documentonmousemove = mouseMove;

documentonmouseup = mouseUp;

var dragObject = null;

var mouseOffset = null;

function getMouseOffset(target, ev){

ev = ev || windowevent;

var docPos = getPosition(target);

var mousePos = mouseCoords(ev);

return {x:mousePosx - docPosx, y:mousePosy - docPosy};

}

function getPosition(e){

var left = 0;

var top = 0;

while (eoffsetParent){

left += eoffsetLeft;

top += eoffsetTop;

e = eoffsetParent;

}

left += eoffsetLeft;

top += eoffsetTop;

return {x:left, y:top};

}

function mouseMove(ev){

ev = ev || windowevent;

var mousePos = mouseCoords(ev);

if(dragObject){

dragObjectstyleposition = 'absolute';

dragObjectstyletop = mousePosy - mouseOffsety;

dragObjectstyleleft = mousePosx - mouseOffsetx;

return false;

}

}

function mouseUp(){

dragObject = null;

}

function makeDraggable(item){

if(!item) return;

itemonmousedown = function(ev){

dragObject = this;

mouseOffset = getMouseOffset(this, ev);

return false;

}

}

你会注意到这个代码几乎是前面的全集,将前面的合在一起就实现了拖拽效果了.

当我们点击一个item时,我们就获取了很多变量,如鼠标位置,鼠标位置自然就包含了那个item的坐标信息了.如果我们点击了一个2020px图像的正中间,那么鼠标的相对坐标为{x:10,y:10}.当我们点击这个图像的左上角那么鼠标的相对坐标为 {x:0,y:0}当我们点击时,我们用这个方法取得一些鼠标与校对的信息.如果我们不能加载页面item,那么信息将是document信息,会忽略了点击的item信息.

mouseOffset函数使用了另一个函数getPositiongetPosition的作用是返回 item相对页面左上角的坐标,如果我们尝试获取itemoffsetLeft或者itemstyleleft,那么我们将取得item相对与父级的位置,不是整个document.所有的脚本我们都是相对整个document,这样会更好一些.

为了完成getPosition任务,必须循环取得item的父级,我们将加载内容到item的左/上的位置.我们需要管理想要的top与left列表.

自从定义了mousemove这个函数,mouseMove就会一直运行.第一我们确定item的 styleposition为absolute,第二我们移动item到前面定义好的位置.当mouse点击被释放,dragObject被设置为 null,mouseMove将不在做任何事.

Dropping an Item

前面的例子目的很简单,就是拖拽item到我们希望到的地方.我们经常还有其他目的如删除item,比如我们可以将item拖到垃圾桶里,或者其他页面定义的位置.

很不幸,我们有一个很大的难题,当我们拖拽,item会在鼠标之下,比如mouseove,mousedown,mouseup或者其他mouse action.如果我们拖拽一个item到垃圾桶上,鼠标信息还在item上,不在垃圾桶上.

怎么解决这个问题呢?有几个方法可以来解决.第一,这是以前比较推荐的,我们在移动鼠标时item会跟随鼠标,并占用了mouseover/mousemove等鼠标事件,我们不这样做,只是让item跟随着鼠标,并不占用mouseover等鼠标事件,这样会解决问题,但是这样并不好看,我们还是希望item能直接跟在mouse下.

另一个选择是不做item的拖拽.你可以改变鼠标指针来显示需要拖拽的item,然后放在鼠标释放的位置.这个解决方案,也是因为美学原因不予接受.

最后的解决方案是,我们并不去除拖拽效果.这种方法比前两种繁杂许多,我们需要定义我们需要释放目标的列表,当鼠标释放时,手工去检查释放的位置是否是在目标列表位置上,如果在,说明是释放在目标位置上了.

Java代码 收藏代码

/

All code from the previous example is needed with the exception

of the mouseUp function which is replaced below

/

var dropTargets = [];

function addDropTarget(dropTarget){

dropTargetspush(dropTarget);

}

function mouseUp(ev){

ev = ev || windowevent;

var mousePos = mouseCoords(ev);

for(var i=0; i<dropTargetslength; i++){

var curTarget = dropTargets[i];

var targPos = getPosition(curTarget);

var targWidth = parseInt(curTargetoffsetWidth);

var targHeight = parseInt(curTargetoffsetHeight);

if(

(mousePosx > targPosx) &&

(mousePosx < (targPosx + targWidth)) &&

(mousePosy > targPosy) &&

(mousePosy < (targPosy + targHeight))){

// dragObject was dropped onto curTarget!

}

}

dragObject = null;

}

鼠标释放时会去取是否有drop属性,如果存在,同时鼠标指针还在drop的范围内,执行drop *** 作.我们检查鼠标指针位置是否在目标范围是用(mousePosx>targetPosx),而且还要符合条件(mousePosx<(targPosx + targWidth)).如果所有的条件符合,说明指针确实在范围内,可以执行drop指令了.

Pulling It All Together

最后我们拥有了所有的drag/drop的脚本片断!下一个事情是我们将创建一个DOM处理.

下面的代码将创建container(容器),而且使任何一个需要drag/drop的item变成一个容器的item代码在这个文章第二个demo的后面,它可以用户记录一个list(列表),定为一个导航窗口在左边或者右边,或者更多的函数你可以想到的.

下一步我们将通过"假代码"让reader看到真代码,下面为推荐:

1、当document第一次载入时,创建dragHelper DIVdragHelper将给移动的item加阴影.真实的item没有被dragged,只是用了insertBefor和appendChild来移动了,我们隐藏了dragHelper

2、有了mouseDown与mouseUp函数.所有的 *** 作会对应到当到iMouseDown的状态中,只有当mouse左键为按下时iMouseDown才为真,否则为假.

3、我们创建了全局变量DragDrops与全局函数CreateDragContainerDragDrops包含了一系列相对彼此的容器.任何参数(containers)将通过CreatedcragContainer进行重组与序列化,这样可以自由的移动.CreateDragContainer函数也将item进行绑定与设置属性.

4、现在我们的代码知道每个item的加入,当我们移动处mouseMove,mouseMove函数首先会设置变量target,鼠标移动在上面的item,如果这个item在容器中(checked with getAttribute):

运行一小段代码来改变目标的样式.创造rollover效果

检查鼠标是否没有放开,如果没有

o 设置curTarget代表当前item

o 记录item的当前位置,如果需要的话,我们可以将它返回

o 克隆当前的item到dragHelper中,我们可以移动带阴影效果的item

o item拷贝到dragHelper后,原有的item还在鼠标指针下,我们必须删除掉dragObj,这样脚本起作用,dragObj被包含在一个容器中.

o 抓取容器中所有的item当前坐标,高度/宽度,这样只需要记录一次,当item被drag时,每随mouse移动,每移钟就会记录成千上万次.

如果没有,不需要做任何事,因为这不是一个需要移动的item

5、检查curTarget,它应该包含一个被移动的item,如果存在,进行下面 *** 作:

开始移动带有阴影的item,这个item就是前文所创建的

检查每个当前容器中的container,是否鼠标已经移动到这些范围内了

o 我们检查看一下正在拖动的item是属于哪个container

o 放置item在一个container的某一个item之前,或者整个container之后

o 确认item是可见的

如果鼠标不在container中,确认item是不可见了.

你的代码第一次能用是因为event是有效的,不知道你如何调用的,但是看名字应该是响应的一个onclick消息,第二次你在setinterval中调用的click_it,这个时候event是无效的,因为setinterval并不会创建消息

IE内核的浏览器中event只在onclick或者onmouseover等事件响应函数中才有效,你用setInterval调用的时候event并不会被赋值,也就没有clientX这个成员变量,所以就会报错,原因就是这样,如果你需要解决方案,继续补充问题

换成按钮点击的方法这种说法我不是很理解,手动创建事件是很复杂的,你不妨告诉我你要实现什么效果,我好告诉你最直接的解决方案

哦,原来是drag啊,你需要注册三个事件,mousedown,mousemove,mouseup,在mousedown中取得鼠标的位置,算出相对div的偏移,然后在move的过程中根据偏移和鼠标位置不断的改变div的坐标,在mouseup里中止拖动(设置一个标志位就可以了,isDragging,默认false,mousedown就设置成true,move里面判断是不是true,如果是就让div跟着走,不是就不管,up里面重新设置为false)

以上就是关于简单实现svg的拖拽和缩放全部的内容,包括:简单实现svg的拖拽和缩放、delphi TreeView 鼠标右击选择节点、vb怎么获得矩形的坐标等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/9732614.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-01
下一篇2023-05-01

发表评论

登录后才能评论

评论列表(0条)

    保存