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

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

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

  1. var products = [
  2. {
  3. ProductId : 1,
  4. ProductName : "Chai",
  5. QuantityPerUnit : "10 boxes x 20 bags",
  6. UnitPrice : 18.00,
  7. Description : "Soft drinks, coffees, teas, beers, and ales"
  8. },
  9. {
  10. ProductId : 2,
  11. ProductName : "Chang",
  12. QuantityPerUnit : "24 - 12 oz bottles",
  13. UnitPrice : 19.00,
  14. Description : "Soft drinks, coffees, teas, beers, and ales"
  15. },
  16. ……
  17. ];

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

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

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

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

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

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

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

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

  1. <style>
  2. html, body {
  3. padding: 0px;
  4. margin: 0px;
  5. }
  6. .main {
  7. margin: 0px;
  8. padding: 0px;
  9. position: absolute;
  10. top: 0px;
  11. bottom: 0px;
  12. left: 0px;
  13. right: 0px;
  14. }
  15. </style>

接下来指定view的className属性:

  1. view.className = 'main';

噢~总算出来了~

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

  1. listView.setRowHeight(50);
  2. listView.drawRowBackground = function(g, data, selected, x, y, width, height){
  3. if(this.isSelected(data)){
  4. g.fillStyle = '#87A6CB';
  5. }
  6. else if(this.getRowIndex(data) % 2 === 0){
  7. g.fillStyle = '#F1F4F7';
  8. }
  9. else{
  10. g.fillStyle = '#FAFAFA';
  11. }
  12. g.beginPath();
  13. g.rect(x, y, width, height);
  14. g.fill();
  15. };

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

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

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

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

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

  1. ht.Default.setImage('productIcon', {
  2. width: 50,
  3. height: 50,
  4. clip: function(g, width, height) {
  5. g.beginPath();
  6. g.arc(width/2, height/2, Math.min(width, height)/2-3, 0, Math.PI * 2, true);
  7. g.clip();
  8. },
  9. comps: [
  10. {
  11. type: 'image',
  12. stretch: 'uniform',
  13. rect: [0, 0, 50, 50],
  14. name: {func: function(data){return data.a('ProductId');}}
  15. }
  16. ]
  17. });

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

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

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

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

  1. var g3d = new ht.graph3d.Graph3dView();
  2.  
  3. var node = new ht.Node();
  4. node.s3(30, 30, 30);
  5. node.p3(-30, 15, 0);
  6. node.s('all.color', '#87A6CB');
  7. g3d.dm().add(node);
  8.  
  9. node = new ht.Node();
  10. node.s3(30, 30, 30);
  11. node.p3(30, 15, 0);
  12. node.s('all.color', '#87A6CB');
  13. node.setElevation(15);
  14. g3d.dm().add(node);

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

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

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

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

  1. var borderPane = new ht.widget.BorderPane();
  2.  
  3. borderPane.setLeftView(listView, 350);
  4. 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树。

  1. var dragImage = null,
  2. productId = null;
  3. listView.handleDragAndDrop = function(e, state) {
  4. if (state === 'prepare') {
  5. var data = listView.getDataAt(e);
  6. listView.sm().ss(data);
  7. if (dragImage && dragImage.parentNode) {
  8. document.body.removeChild(dragImage);
  9. }
  10. dragImage = ht.Default.toCanvas('productIcon', 30, 30, 'uniform', data);
  11. productId = data.a('ProductId');
  12. }
  13. else if (state === 'begin') {
  14. if (dragImage) {
  15. var pagePoint = ht.Default.getPagePoint(e);
  16. dragImage.style.left = pagePoint.x - dragImage.width / 2 + 'px';
  17. dragImage.style.top = pagePoint.y - dragImage.height / 2 + 'px';
  18. document.body.appendChild(dragImage);
  19. }
  20. }
  21. else if (state === 'between') {
  22. if (dragImage) {
  23. var pagePoint = ht.Default.getPagePoint(e);
  24. dragImage.style.left = pagePoint.x - dragImage.width / 2 + 'px';
  25. dragImage.style.top = pagePoint.y - dragImage.height / 2 + 'px';
  26. }
  27. }
  28. else {
  29. if (dragImage) {
  30. if (dragImage.parentNode) {
  31. document.body.removeChild(dragImage);
  32. }
  33. dragImage = null;
  34. productId = null;
  35. }
  36. }
  37. };

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

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

思路是这样子的:

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

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

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

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

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

  1. listView.handleDragAndDrop = function(e, state) {
  2. if (state === 'prepare') {
  3. var data = listView.getDataAt(e);
  4. listView.sm().ss(data);
  5. if (dragImage && dragImage.parentNode) {
  6. document.body.removeChild(dragImage);
  7. }
  8. dragImage = ht.Default.toCanvas('productIcon', 30, 30, 'uniform', data);
  9. productId = data.a('ProductId');
  10. }
  11. else if (state === 'begin') {
  12. if (dragImage) {
  13. var pagePoint = ht.Default.getPagePoint(e);
  14. dragImage.style.left = pagePoint.x - dragImage.width / 2 + 'px';
  15. dragImage.style.top = pagePoint.y - dragImage.height / 2 + 'px';
  16. document.body.appendChild(dragImage);
  17. }
  18. }
  19. else if (state === 'between') {
  20. if (dragImage) {
  21. var pagePoint = ht.Default.getPagePoint(e);
  22. dragImage.style.left = pagePoint.x - dragImage.width / 2 + 'px';
  23. dragImage.style.top = pagePoint.y - dragImage.height / 2 + 'px';
  24.  
  25. if (ht.Default.containedInView(e, g3d)) {
  26. if (lastFaceInfo) {
  27. lastFaceInfo.data.s(lastFaceInfo.face + '.image', lastFaceInfo.oldValue);
  28. lastFaceInfo = null;
  29. }
  30. var faceInfo = g3d.getHitFaceInfo(e);
  31. if (faceInfo) {
  32. faceInfo.oldValue = faceInfo.data.s(faceInfo.face + '.image');
  33. faceInfo.data.s(faceInfo.face + '.image', productId);
  34. lastFaceInfo = faceInfo;
  35. }
  36. }
  37. }
  38. }
  39. else {
  40. if (dragImage) {
  41. if (lastFaceInfo) {
  42. lastFaceInfo.data.s(lastFaceInfo.face + '.image', lastFaceInfo.oldValue);
  43. lastFaceInfo = null;
  44. }
  45. if (ht.Default.containedInView(e, g3d)) {
  46. var faceInfo = g3d.getHitFaceInfo(e);
  47. if (faceInfo) {
  48. faceInfo.data.s(faceInfo.face + '.image', productId);
  49. }
  50. }
  51. if (dragImage.parentNode) {
  52. document.body.removeChild(dragImage);
  53. }
  54. dragImage = null;
  55. productId = null;
  56. }
  57. }
  58. };

在看看最后的效果图吧

今天就到这吧,将的内容有点多,涉及到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. 字符串混淆技术在.NET程序保护中的应用及如何解密被混淆的字符串

    Visual Studio提供的Dotfuscator保护程序,可以对用户代码中包含的字符串进行加密.比如下面的例子,为了找到这个程序的注册算法,用.NET Reflector加载程序集后,发现代码中 ...

  2. ListView 加载更多列表 Load More mono forandroid 项目笔记

    今天项目经理找我说Listview加载更多的时候会出现一些问题,主要表现在会顿一下.让我我就去找Java的方法看看.自己写出了mono 的加载更多功能.和大家分享一下 先看效果 首先是模型类ListI ...

  3. UWP滑动后退

    经过近些年智能手机App的不断发展,用户已经不仅仅满足于功能上的需求.UI.设计等非功能点逐渐在App体验中占了大多数的分数.不知从何时起,滑动手势就成为了App的一个标配.他不仅仅是一个功能,更是一 ...

  4. 团队项目——站立会议DAY6

    团队项目--站立会议 DAY6        团队成员介绍(5人):张靖颜.何玥.钟灵毓秀.赵莹.王梓萱        今日(2016/5/13),站立会议已进行了一周时间,大家将这一周所遇到的问题和 ...

  5. [.net 面向对象程序设计进阶] (4) 正则表达式 (三) 表达式助手

    [.net 面向对象程序设计进阶] (2) 正则表达式(三) 表达式助手 上面两节对正则表达式的使用及.NET下使用正则表达式作了详细说明,本节主要搜集整理了常用的正则表达式提供参考. 此外为了使用方 ...

  6. 如何成为一个Xamarin专家

    近期,我们发布了 Xamarin studio 6,这个版本充满了美妙的新特性,能够更有效的帮助我们的开发工作.由于其深层次的 IDE 比较复杂,同时我们也很难去发现并记得那些对我们最有帮助的特性,所 ...

  7. Windows进程通信 -- 共享内存(1)

    共享内存的方式原理就是将一份物理内存映射到不同进程各自的虚拟地址空间上,这样每个进程都可以读取同一份数据,从而实现进程通信.因为是通过内存操作实现通信,因此是一种最高效的数据交换方法. 共享内存在 W ...

  8. Senparc.Weixin.MP SDK 微信公众平台开发教程(四):Hello World

    =============  以下写于2013-07-20 ============= 这一篇文章其实可以写在很前面,不过我还是希望开发者们尽多地了解清楚原理之后再下手. 通过上一篇Senparc.W ...

  9. 判断当前日期是否在[startDate, endDate]区间

    /** * 判断当前日期是否在[startDate, endDate]区间 * * @param startDate 开始日期 * @param endDate 结束日期 * @author jqli ...

  10. MVVM架构~knockoutjs系列之Mapping插件为对象添加ko属性

    返回目录 对于一个JS对象来说,如果希望将所有属性进行监视,在之前我们需要一个个对属性添加ko.observable方法,而有了Mapping插件后,它可以帮助我们这件事. 在Mapping出现之前 ...