很多可视化编辑器都或多或少有一些拖拽功能,比如从一个List列表中拖拽一个节点到拓扑组件上进行建模,并且在拖拽的过程中鼠标位置下会附带一个被拖拽节点的缩略图,那么今天我们就来实现这样的拖拽效果。

首先我们需要创建一个List列表,在列表中加入图片信息,让List列表不那么单调,先来看看效果图。

接下来我们一步一步来是想这个List列表,先来解决下数据,在这里我就列举一两个:

var products = [
{
ProductId : 1,
ProductName : "Chai",
QuantityPerUnit : "10 boxes x 20 bags",
UnitPrice : 18.00,
Description : "Soft drinks, coffees, teas, beers, and ales"
},
{
ProductId : 2,
ProductName : "Chang",
QuantityPerUnit : "24 - 12 oz bottles",
UnitPrice : 19.00,
Description : "Soft drinks, coffees, teas, beers, and ales"
},
……
];

有了数据,我们就可以来创建List组件了:

var listView = new ht.widget.ListView(),
view = listView.getView(); document.body.appendChild(view);

这时我们创建的是一个空的List组件,在浏览器上看不到任何东西,那么接下来我们就该把我们定义的数据添加到List组件上了:

products.forEach(function(product){
var data = new ht.Data();
data.a(product);
listView.dm().add(data);
});

数据的添加是不是很简单,但是List组件上显示的内容默认是Data的name属性或displayName属性,在创建Data时,并没有对Data设置displayName或者name属性,所以这个时候在页面上看到的还是一个空的List组件,别急,我们可以在不设置displayName或name属性的情况下让组件显示效果图上的文本内容,请看:

listView.getLabel = function(data){
return data.a('ProductName') + ' - $' + data.a('UnitPrice').toFixed(2);
};

嘿嘿,ListView组件提供了getLabel方法供用户重载来实现自定义显示文本内容,这下应该就可以显示文本内容了吧~

oh no~还是什么都没有,是不是还少了点什么呢~对了,忘记给ListView组件添加铺满浏览器的样式了,将厦门的样式添加到head标签中:

<style>
html, body {
padding: 0px;
margin: 0px;
}
.main {
margin: 0px;
padding: 0px;
position: absolute;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
}
</style>

接下来指定view的className属性:

view.className = 'main';

噢~总算出来了~

行高太小了,背景也太单调了,向效果图看齐:

listView.setRowHeight(50);
listView.drawRowBackground = function(g, data, selected, x, y, width, height){
if(this.isSelected(data)){
g.fillStyle = '#87A6CB';
}
else if(this.getRowIndex(data) % 2 === 0){
g.fillStyle = '#F1F4F7';
}
else{
g.fillStyle = '#FAFAFA';
}
g.beginPath();
g.rect(x, y, width, height);
g.fill();
};

通过setRowHeight()方法设置行高,通过重载drawRowBackground()方法绘制交叉背景。

嘿,有点样子了,和效果图越来越近了~那么就差图标了呢。

ht.Default.setImage('1', 40, 40, 'data:image/jpeg;base64,...');
ht.Default.setImage('2', 40, 40, ‘data:image/jpeg;base64,...');
…… listView.setIndent(60);
listView.getIcon = function(data){
return data.a('ProductId');
};

通过ht.Default.setImage()方法定义ProductId对应的图片资源,以ProductId作为图片的别名,然后接下来定义icon位置大小为60,重载ListView的getIcon方法返回数据中定义的ProductId属性,如此就可以看到图标了。

还没完,效果图上显示的图片是圆形的,这该如何是好呢?别急,我们有万能的矢量,上么样的图形都难不倒我们:

ht.Default.setImage('productIcon', {
width: 50,
height: 50,
clip: function(g, width, height) {
g.beginPath();
g.arc(width/2, height/2, Math.min(width, height)/2-3, 0, Math.PI * 2, true);
g.clip();
},
comps: [
{
type: 'image',
stretch: 'uniform',
rect: [0, 0, 50, 50],
name: {func: function(data){return data.a('ProductId');}}
}
]
});

在代码中我们定义了一个名称为productIcon的矢量,在矢量中通过clip属性定义裁切区域,效果就是超出该裁切区域外的内容将被隐藏。现在矢量定义好了,我们只需要在ListView的getIcon()方法中返回我们定义的矢量名称就可以实现圆形图标了:

listView.getIcon = function(data){
return 'productIcon';
};

到这里,和效果图的效果就一模一样了~那么接下来我们就该创建3D拓扑组件了,来看看效果图:

很简单,就在3D拓扑中放两个正方体:

var g3d = new ht.graph3d.Graph3dView();

var node = new ht.Node();
node.s3(30, 30, 30);
node.p3(-30, 15, 0);
node.s('all.color', '#87A6CB');
g3d.dm().add(node); node = new ht.Node();
node.s3(30, 30, 30);
node.p3(30, 15, 0);
node.s('all.color', '#87A6CB');
node.setElevation(15);
g3d.dm().add(node);

这是你会发现并没有像效果图中显示的那么会有网格效果,并且视角也不对,没事,待我添加几个属性:

g3d.setEye(-100, 100, 80);
g3d.setGridVisible(true);
g3d.setGridColor(‘#F1F4F7');

如此就和效果图一模一样了~

ListView和3D拓扑是两个独立的组件,我们该如何将这两个组件组合在一起呢?这时候,我想到了BorderPane组件,将List组件放在左边,将3D拓扑组件放在右边:

var borderPane = new ht.widget.BorderPane();

borderPane.setLeftView(listView, 350);
borderPane.setCenterView(g3d);

看,成功将两个组件合并在一起了,离成功不远了。接下来就是今天的重头戏了,该如何实现拖拽List上的节点到3D拓扑上,并实现节点的图标吸附到3D拓扑的图元上呢,我给大家细细道来。

首先先来了解下ListView的handleDragAndDrop()方法,draganddrop一共有4个状态:prepare、begin、between和end,可更具这4个不同状态来做不同的业务处理。

第一步,我们来实现鼠标附带图标的效果,在拖拽ListView的节点时,在鼠标下方增加一个该节点的缩略图:

思路是这样的:

1. 在prepare状态时获取当前拖拽节点的ProductId属性,并通过调用ht.Default.toCanvas()方法将当前拖拽节点结合矢量productIcon获得一个canvas对象;

2. 在begin状态时根据鼠标当前位置设置canvas对象的left和top属性,并将其添加到DOM树中;

3. 在between状态时,根据鼠标位置信息,重新设置canvas对象的left和top属性,令canvas对象一直跟着鼠标在移动;

4. 在end状态时,将canvas对象移除DOM树。

var dragImage = null,
productId = null;
listView.handleDragAndDrop = function(e, state) {
if (state === 'prepare') {
var data = listView.getDataAt(e);
listView.sm().ss(data);
if (dragImage && dragImage.parentNode) {
document.body.removeChild(dragImage);
}
dragImage = ht.Default.toCanvas('productIcon', 30, 30, 'uniform', data);
productId = data.a('ProductId');
}
else if (state === 'begin') {
if (dragImage) {
var pagePoint = ht.Default.getPagePoint(e);
dragImage.style.left = pagePoint.x - dragImage.width / 2 + 'px';
dragImage.style.top = pagePoint.y - dragImage.height / 2 + 'px';
document.body.appendChild(dragImage);
}
}
else if (state === 'between') {
if (dragImage) {
var pagePoint = ht.Default.getPagePoint(e);
dragImage.style.left = pagePoint.x - dragImage.width / 2 + 'px';
dragImage.style.top = pagePoint.y - dragImage.height / 2 + 'px';
}
}
else {
if (dragImage) {
if (dragImage.parentNode) {
document.body.removeChild(dragImage);
}
dragImage = null;
productId = null;
}
}
};

如此在拖拽ListView节点时就能够看到有一个小图标一直跟着鼠标在移动。

OK,接下来该解决图元吸附功能,当鼠标拖拽ListView节点到3D拓扑上的图元是,将该节点的图标设置为图元当前面的贴图。

思路是这样子的:

1. 在between状态时,通过ht.Default.containedInView()方法判断殿前鼠标是否在3D拓扑组件上;

2. 若鼠标在3D拓扑上,则通过g3d.getHitFaceInfo()方法,根据鼠标当前信息获取当前鼠标下的图元表面信息;

3. 若当前鼠标在图元的某个表面上,则先保存该图元表面信息的贴图,然后设置当前图元表面的贴图为拖拽节点对应的图片,最后将当前图元表面信息缓存下来,当鼠标离开该表面时,还原图元的贴图;

4. 在end状态时,如果当前鼠标位置在某个图元表面时,就将当前拖拽节点的对应的图片做为当前图元表面的贴图。

那么接下来就需要对ListView组件的handleDragAndDrop()方法做些微的修改了。

listView.handleDragAndDrop = function(e, state) {
if (state === 'prepare') {
var data = listView.getDataAt(e);
listView.sm().ss(data);
if (dragImage && dragImage.parentNode) {
document.body.removeChild(dragImage);
}
dragImage = ht.Default.toCanvas('productIcon', 30, 30, 'uniform', data);
productId = data.a('ProductId');
}
else if (state === 'begin') {
if (dragImage) {
var pagePoint = ht.Default.getPagePoint(e);
dragImage.style.left = pagePoint.x - dragImage.width / 2 + 'px';
dragImage.style.top = pagePoint.y - dragImage.height / 2 + 'px';
document.body.appendChild(dragImage);
}
}
else if (state === 'between') {
if (dragImage) {
var pagePoint = ht.Default.getPagePoint(e);
dragImage.style.left = pagePoint.x - dragImage.width / 2 + 'px';
dragImage.style.top = pagePoint.y - dragImage.height / 2 + 'px'; if (ht.Default.containedInView(e, g3d)) {
if (lastFaceInfo) {
lastFaceInfo.data.s(lastFaceInfo.face + '.image', lastFaceInfo.oldValue);
lastFaceInfo = null;
}
var faceInfo = g3d.getHitFaceInfo(e);
if (faceInfo) {
faceInfo.oldValue = faceInfo.data.s(faceInfo.face + '.image');
faceInfo.data.s(faceInfo.face + '.image', productId);
lastFaceInfo = faceInfo;
}
}
}
}
else {
if (dragImage) {
if (lastFaceInfo) {
lastFaceInfo.data.s(lastFaceInfo.face + '.image', lastFaceInfo.oldValue);
lastFaceInfo = null;
}
if (ht.Default.containedInView(e, g3d)) {
var faceInfo = g3d.getHitFaceInfo(e);
if (faceInfo) {
faceInfo.data.s(faceInfo.face + '.image', productId);
}
}
if (dragImage.parentNode) {
document.body.removeChild(dragImage);
}
dragImage = null;
productId = null;
}
}
};

在看看最后的效果图吧

今天就到这吧,将的内容有点多,涉及到HT for Web的知识点也比较多,下面附上本次Demo的源代码,感兴趣的朋友可以载下来看看,同时也欢迎大家留言质询。

下载源码

HT for Web列表和3D拓扑组件的拖拽应用的更多相关文章

  1. 基于HT for Web 快速搭建3D机房设备面板

    以真实设备为模型,搭建出设备面板,并实时获取设备运行参数,显示在设备面板上,这相比于纯数值的设备监控系统显得更加生动直观.今天我们就在HT for Web的3D技术上完成设备面板的搭建. 我们今天模拟 ...

  2. React组件:拖拽布局Dragact v0.1.6 发布

    仓库地址:Dragact爽滑的拖拽组件 大家好,新年已经过去,大家又投入了繁忙的工作当中,由于我在国外,因此压根儿没有休息... 少说废话,上周一周的时间里,我陆陆续续的为Dragact组件进行了一系 ...

  3. 基于HT for Web矢量实现3D叶轮旋转

    在上一篇<基于HT for Web矢量实现2D叶轮旋转>中讲述了叶轮旋转在2D上的应用,今天我们就来讲讲叶轮旋转在3D上的应用. 在3D拓扑上可以创建各种各样的图元,在HT for Web ...

  4. 由于抽签HT For Web ComboBox下拉框组件

    传统HTML5的下拉框select仅仅能实现简单的文字下拉列表,而HT for Web通用组件中ComboBox不仅可以实现传统HTML5下拉框效果,并且可以在文本框和下拉列表中加入自己定义的小图标, ...

  5. 自绘制HT For Web ComboBox下拉框组件

    传统的HTML5的下拉框select只能实现简单的文字下拉列表,而HTforWeb通用组件中ComboBox不仅能够实现传统HTML5下拉框效果,而且可以在文本框和下拉列表中添加自定义的小图标,让整个 ...

  6. 解决Delphi图形化界面的TEdit、TLable等组件手动拖拽固定大小,但是编译之后显示有差别的情况

    经常遇到这样的情况,在我们使用Delphi的可视化工具进行UI设计的时候,我们拖拽TEdit或者Label组件,并且在可视化界面上设置它们的长.宽 但是当我们编译和运行程序的时候,却发现真正显示出来的 ...

  7. element-UI ,Table组件实现拖拽效果

    拖拽效果,先放效果图,步骤放在后面~~ 一.引入三方插件 1.引入sortable.js的包: npm install sortable.js --save 2.或者npm i -S vuedragg ...

  8. 基于HT for Web的3D拓扑树的实现

    在HT for Web中2D和3D应用都支持树状结构数据的展示,展现效果各异,2D上的树状结构在展现层级关系明显,但是如果数据量大的话,看起来就没那么直观,找到指定的节点比较困难,而3D上的树状结构在 ...

  9. 基于HT for Web的3D树的实现

    在HT for Web中2D和3D应用都支持树状结构数据的展示,展现效果各异,2D上的树状结构在展现层级关系明显,但是如果数据量大的话,看起来就没那么直观,找到指定的节点比较困难,而3D上的树状结构在 ...

随机推荐

  1. Java构建工具Ant小记(一)

    Ant简介 Ant是基于java的构建工具.理论上来说它类似与make工具,但是却克服了make的一些固有的缺陷. 传统的Make是基于操作系统shell的构建工具,虽然也可以基于工作的os对make ...

  2. Nim语言的模块化编程

    前言 Nim支持把一大段程序分成若干个模块 一个模块就是一个源代码文件 每个模块都拥有它自己的名称空间 模块化可以起到封装(信息隐藏)和分步编译的作用 一个模块可以通过import语句获得另一个模块的 ...

  3. 【情人节来一发】网站添加QQ客服功能

    今年的元宵节遇到情人节,挺不自量力的,呵呵,开篇给各位讲个段子,早上一美女同学在空间发说说道:“开工大吉 起床啦,卖元宵,卖玫瑰,卖避孕套啦-有木有一起去发财的小伙伴?Let’s go…”,对于此种长 ...

  4. 架构设计:前后端分离之Web前端架构设计

    在前面的文章里我谈到了前后端分离的一些看法,这个看法是从宏观的角度来思考的,没有具体的落地实现,今天我将延续上篇文章的主题,从纯前端的架构设计角度谈谈前后端分离的一种具体实现方案,该方案和我原来设想有 ...

  5. java提高篇(二一)-----ArrayList

    一.ArrayList概述       ArrayList是实现List接口的动态数组,所谓动态就是它的大小是可变的.实现了所有可选列表操作,并允许包括 null 在内的所有元素.除了实现 List ...

  6. java提高篇(八)----详解内部类

    可以将一个类的定义放在另一个类的定义内部,这就是内部类. 内部类是一个非常有用的特性但又比较难理解使用的特性(鄙人到现在都没有怎么使用过内部类,对内部类也只是略知一二). 第一次见面 内部类我们从外面 ...

  7. Ubuntu环境搭建系列—WPS/LAMP/Python篇

    由于篇幅不宜太长,所以就将此文分成了两部分,在第一部分中我们讲解了google-chrome(谷歌浏览器)的安装,jdk的环境配置,android开发的环境搭建.那么在第二部分中,位们将讲解的是金山W ...

  8. ASP.NET MVC从视图传递多个模型到Controller

    从后台组织好数据然后传递到页面倒是水到渠成很方便,因为MVC自身就将这样的需求内建到了这个系统中.我只需要在后台组织好一个List 或IEnumerable类型的变量,将需要传递的数据模型扔进去便可. ...

  9. 实战使用Axure设计App,使用WebStorm开发(1) – 用Axure描述需求

    系列文章 实战使用Axure设计App,使用WebStorm开发(1) – 用Axure描述需求  实战使用Axure设计App,使用WebStorm开发(2) – 创建 Ionic 项目   实战使 ...

  10. linux下进程间通信

    信号 信号是进程间相互传递消息的一种方法,只是用来通知某进程发生了什么事件,并不给进程传递任何数据. #include <sys/types.h> #include <unistd. ...