文档章节

学习 kityminder 笔记(十)

刘军兴
 刘军兴
发布于 2015/11/25 12:04
字数 1575
阅读 75
收藏 0
点赞 0
评论 0

今天学习 layout 下的各个 js. 在此之前, 需要回顾一下 core/layout.
注意在 core 下面有 layout.js, module 下面也有 layout.js, 我是被混淆了, 不能换个名字么?

=== 布局基类 Layout 位于 core/layout.js ===

布局的基类, 各种不同的布局从此类派生.
class Layout {
  // 子类需要实现此布局算法. 算法输入是父节点, 及其子节点(数组), 
  //   要求布局这些子节点(即相对于父节点的变换)
  virtual doLayout(parent, children[]): throw 'sub-class impl'
  align(),stack(),move() 等辅助方法(子类可使用), 稍后看.
}

 

在理解布局前, 需要先了解一点变换的知识, 以及 kity 中对变换的包装(和实现).

变换这里指将一个点(x1,y1) 经函数 f 映射到另一个点 (x2,y2).

对于平移(translate)有:
     x2 = x1 + a, y2 = y1 + b
这里 a,b 分别是 x,y 轴平移量.

在 svg 中相当于为元素设置一个 transform="translate(a,b)" (或其它等价形式).

对于缩放(scale)有:
    x2 = a*x1, y2 = b*y1
在 svg 中相当于为元素设置 transform="scale(a,b)" (或等价形式)

对于旋转(rotate)一个角度 α:
   x2 = x1*cosα + y1*sinα
   y2 = y1*cosα - x1*sinα
对应 svg 中相当于 transform="rotate(α)"

斜切变换 skewX(α), skewY() 相似:
    x2 = x1 + y1*tanα, y2 = y1

上述各种变换都可是线性变化, 即 x2,y2 是 a*x1+b*y1+c 的形式, 因此可表示为线性代数的
矩阵乘法. 这样变换就可以写作:

点 x,y 平移 tx,ty 距离:
     [1 0 tx] [x]   [x+tx]
     [0 1 ty]*[y] = [y+ty]
     [0 0 1 ] [1]   [ 1  ]
点 x,y 缩放 sx,sy 倍:
     [sx 0 0] [x]   [x*sx]
     [0 sy 0]*[y] = [y*sy]
     [0  0 1] [1]   [1]
点 x,y 绕原点旋转 α 角的矩阵, 向量和乘的结果略:
     [cos -sin 0]
     [sin cos  0]
     [ 0   0   1]
斜切  skewX:         skewY:
     [1 tan(ax) 0]  [1       0 0]
     [0  1      0]  [tan(ay) 1 0]
     [0  0      1]  [0       0 1]

使用矩阵的最强大的地方在于, 多个线性变换可以乘积, 而矩阵*矩阵还是矩阵, 这即是 svg matrix 的含义了.

多个(线性)变换组合在一起, 即是多个矩阵的乘积, 矩阵乘积仍然是矩阵, 
svg 中 transform="matrix(a,b,c,d,e,f)" 即表示矩阵:
     [a c e]
     [b d f]
     [0 0 1]

这样, 你无论为一个元素施加多少次线性变换, 其最终结果都是一个简单的矩阵.

因此我合理地猜测这些变换,矩阵在 kity svg 库中都有对应的封装类/方法. 例如 kity.Matrix 类...

 

=== 下面研究 layout/mind.js, btree.js ===

以上我们看到了 Layout (虚)基类, 现在我们找一个实做的子类来查看 doLayout() 是具体怎么实现的.
位于 src/layout 目录下有 6 个 js 文件. 例如 tianpan.js(拼音天盘?), fish-bone*(鱼骨图) 等.
我简单看了下, 其中 mind.js 对应缺省布局, 其引用了 btree.js, 所以我们先研究这两个.

// 实际名字可称为 MindLayout 或 DefaultLayout
class <noname-layout> : public Layout {
  doLayout(node, children): {  // 这里算法需要仔细看
    // 1. 将 children 切分成两部分 left~right. 也可认为是 up~down.
    var left[] = 前一半 children,
        right[] = 后一半 children;

    // 2. 得到 left, right (子)布局器 (layout)
    var left_layout = Minder.left_layout_object;
    // right_layout 也一样, 所以只需研究明白 left 一半即可.
    
    // 3. 使用子布局器 布局各自一半.
    left_layout.doLayout(node, left[])  // right 一半相同

    // 4. 合在一起, 设置 node 的 vertex_out, vector_out
    box = node.content_box
    set out-vertex,out-vector // 估计和连线有关, 以后看.
  }
}

 

这里 left, right 子布局器在 btree.js 中. 该文件其实生成了 dir=left,right,top,bottom 四个布局器,
为了简化问题, 我实际代入该生成函数以 dir=left, 模拟出一个类, 以方便理解.

// 将一组子节点布局到自己的左侧, 子节点右边界是对齐的(right, align), 
//   垂直方向(即沿着 y 轴)顺序排列(stack).
class LeftLayout : public Layout {
  doLayout(node, children[]): {
    // 1.
    axis = 'x', oppsite = 'right'  // left 是 x 轴的, 相对方向为 right.
    parent.out_vertex = ..., .out_vector = ... (略)

    // 2.
    for-each (child in children[]) {
      child.layout_transform = new kity.Matrix() // 等于重置了变换矩阵?
      child.in_vertex = ..., .in_vector = ... (暂时略)
    }

    // 3. 使用基类辅助方法. 对齐子节点, 堆叠成一列.
    base::align(children[], 'right')  // right = oppsite of left
    base::stack(children[], 'y')      // y = oppsite of x-axis

    // 4. 计算偏移各子节点的一个 dx,dy 值. 
    p_box = parent.content_box  // 父节点位置.
    c_box = getBranchBox() // 工具方法:获取给点的子节点所占的布局区域
    // 这里还是对 dx 的计算有点疑惑, 可能需要调试下...
    dx = ..., dy = ...  // c_box 放 p_box 左边+margin, y 值中心对齐.
    // 平移子节点到该偏移, 实际是调用 base::move() 方法. 
    for-each (child)
      node.translate(dx, dy)
  }
}

这里重点是将一组子节点靠右对齐(即所有 child.right 值相同), 沿着 y 轴堆叠(顺序排列, 中间有间距),
然后布置在父节点的左侧. 实际使用三个 Layout 基类的方法: align(), stack(), move().

下面特化 align() 为 align_right(), 在上面的例子中调用的 align() 给出参数为 'right':
(其它 align left,top,bottom 类似, 只是多一个 switch(dir) 判断.

class Layout {
  align_right(nodes[]) {
    for-each (node in nodes[]) {
      // 经此平移, 所有 node 节点的 right 值变为 0, 所以就右对齐了.
      node.transform_matrix.translate(-node.right, 0)
    }
  }
}

下面特化 stack() 为 stack_y():

class Layout {
  stack_y(nodes) {
    distance = node.margin-bottom  // 节点间距离
    position = 0  // 节点在 y 轴上的位置.
    for-each (node) {
      // 对 node 的当前变换矩阵 再叠加一个 dy 平移, 使得其 y 轴定位到 position 位置.
      matrix = node.transform_matrix
      matrix.translate(0, position - node.top)
       // 计算下一个位置. 考虑两个节点之间的间距.
       position += node.height + distance_of_curr_node_and_next_node
    }
  }
}

一组 nodes[] 在 align_right() 之后, node.right = 0; 在 stack_y() 之后 nodes[0].top = 0;
这相当于整组节点的右上角是 (0,0) 原点了. 上面计算偏移 dx,dy 的疑惑也略微解开了一些, 因为那里已经
知道整个 children_box .top=0, .right=0 了. 

现在我们知道了 Layout 的作用是计算子节点的布局位置, 该位置是相对于父节点的. 对于其它布局形式,
如鱼骨图, 天盘?图估计作用类似, 只是计算方法有所不同, 布局的子节点的位置也就有些不同.

这里 Layout 只是算出了位置, 但并未将节点实际移动到那里, 于是问题就产生了:
   谁,什么时候,怎么移动(动画?)节点到新的位置的呢?

 

© 著作权归作者所有

共有 人打赏支持
刘军兴
粉丝 54
博文 184
码字总数 226359
作品 0
昌平
百度脑图解析:如何进行web复杂应用的渐进式开发

内容来源:2017 年 4 月 8 日,张博在“HTML5梦工场 & 微软开发者沙龙第05期—持续集成”进行《Web复杂应用的 「渐进式」开发》演讲分享。IT 大咖说(微信id:itdakashuo)作为独家视频合作方...

06/04
0
0
学习 kityminder 笔记(五)

接着学习 kityminder, 前面其实没看完 kity, 大致了解之后, 我们先看看 minder 部分, 两者结合起来学更好些. 下载 kityminder-core (按文档说只含核心部分), 从 git-hub, 建立起开发/构造环境...

刘军兴
2015/11/19
0
0
学习 kityminder 笔记(六)

接上篇, 接着学习 kityminder. == core/keyreceiver.js == extend class Minder { init-hook(): 构造时设置选项, 侦听 'paperrender' 事件, 以调用 _initKeyReceiver() _initKeyReceiver():......

刘军兴
2015/11/19
0
0
学习 kityminder 笔记(七)

接上篇继续学习. 本段都是 seajs require(module/*.js) 的, 看起来是按照字母顺序 a-z 排列的, 所以应没什么互相依赖性. 考虑到前面有很多细节都略过, 或不懂, 在学习过程中可能还要不断回顾...

刘军兴
2015/11/20
0
0
再学习 Kity 笔记(五) 初步

在过去两周左右, 一直在学习 kity, kityminder, nodejs, seajs 等一系列项目. 有些认识经过一段时间学习, 已经发生了 变化, 使得原有笔记过时. 兹为深入学习, 有必要回顾复习重新看一遍. Kit...

刘军兴
2015/12/04
68
0
学习 kityminder 笔记(九)

继续学习 kityminder. === module/style.js === // 拷贝选中节点的当前样式,包括字体、字号、粗体、斜体、背景色、字体色// 对应为 styleNames = ['font-size', 'font-family', 'font-weig...

刘军兴
2015/11/24
61
0
学习 kityminder 笔记(十一)

上次看到了 Layout 类及其实做子类 MindLayout 等, 本次研究驱动它们的部分: Minder.layout() 函数. 回顾 core/layout.js 里面相关代码(按照调用顺序): extend class Minder {// 用于在 Mind...

刘军兴
2015/11/30
78
0
学习 kityminder 笔记(八)

继续接上篇(文本多了似乎容易丢)... == module/image.js == // 为选中的节点添加图片.class ImageCommand : Command {execute(): for-each node.data += {.image=, ...} }这里小结一下 Comm...

刘军兴
2015/11/24
90
0
KityMinder 1.2.0 发布,脑图工具

脑图工具 KityMinder 出新版本啦! 功能增加,体验提升:) 自从KityMinder1.x版本正式上线以来,得到了广大同学的热情关注。同学们为KityMinder提出了各种好的建议。我们整个小组受到了很大...

战毅
2014/07/10
8.2K
12
学习 kityminder & angular (十四) event 和 scope.$apply

回顾 event 机制 先回顾一下以前看的 core/event.js, 其提供了 minder 的事件机制 (event) 支持: // 表示一个脑图中发生的事件class MinderEvent {ctor(type, parms, canstop): 构造一个脑图...

刘军兴
2015/12/14
188
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Android Studio 3.0 之后打包apk出现应用未安装问题

1、废话 出现这个问题的原因,并不是只有一个,而是有多个原因,不懂的估计会被搞得一头雾水,下面我列举的是我遇到的几种问题和网友遇到的几种问题,但不一定是全部,也有可能有些莫名其妙的...

她叫我小渝
19分钟前
0
0
前端基础

1. get请求传参长度的误区 误区:我们经常说get请求参数的大小存在限制,而post请求的参数大小是无限制的。 实际上HTTP 协议从未规定 GET/POST 的请求长度限制是多少。对get请求参数的限制是...

wenxingjun
今天
0
0
拦截SQLSERVER的SSL加密通道替换传输过程中的用户名密码实现运维审计(一)

工作准备 •一台SQLSERVER 2005/SQLSERVER 2008服务 •SQLSERVER jdbc驱动程序 •Java开发环境eclipse + jdk1.8 •java反编译工具JD-Core 反编译JDBC分析SQLSERVER客户端与服务器通信原理 SQ...

紅顏為君笑
今天
7
0
jQuery零基础入门——(六)修改DOM结构

《jQuery零基础入门》系列博文是在廖雪峰老师的博文基础上,可能补充了个人的理解和日常遇到的点,用我的理解表述出来,主干出处来自廖雪峰老师的技术分享。 在《零基础入门JavaScript》的时...

JandenMa
今天
0
0
linux mint 1.9 qq 安装

转: https://www.jianshu.com/p/cdc3d03c144d 1. 下载 qq 轻聊版,可在百度搜索后下载 QQ7.9Light.exe 2. 去wine的官网(https://wiki.winehq.org/Ubuntu) 安装 wine . 提醒网页可以切换成中...

Canaan_
今天
0
0
PHP后台运行命令并管理运行程序

php后台运行命令并管理后台运行程序 class ProcessModel{ private $pid; private $command; private $resultToFile = ''; public function __construct($cl=false){......

colin_86
今天
1
0
数据结构与算法4

在此程序中,HighArray类中的find()方法用数据项的值作为参数传递,它的返回值决定是否找到此数据项。 insert()方法向数组下一个空位置放置一个新的数据项。一个名为nElems的字段跟踪记录着...

沉迷于编程的小菜菜
今天
1
1
fiddler安装和基本使用以及代理设置

项目需求 由于开发过程中客户端和服务器数据交互非常频繁,有时候服务端需要知道客户端调用接口传了哪些参数过来,这个时候就需要一个工具可以监听这些接口请求参数,已经接口的响应的数据,这种...

银装素裹
今天
0
0
Python分析《我不是药神》豆瓣评论

读取 Mongo 中的短评数据,进行中文分词 对分词结果取 Top50 生成词云 生成词云效果 看来网上关于 我不是药神 vs 达拉斯 的争论很热啊。关于词频统计就这些,代码中也会完成一些其它的分析任...

猫咪编程
今天
0
0
虚拟机怎么安装vmware tools

https://blog.csdn.net/tjcwt2011/article/details/72638977

AndyZhouX
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部