学习 kityminder 笔记(九)
学习 kityminder 笔记(九)
刘军兴 发表于2年前
学习 kityminder 笔记(九)
  • 发表于 2年前
  • 阅读 64
  • 收藏 0
  • 点赞 0
  • 评论 0

新睿云服务器60天免费使用,快来体验!>>>   

继续学习 kityminder.

=== module/style.js === 

 

// 拷贝选中节点的当前样式,包括字体、字号、粗体、斜体、背景色、字体色
// 对应为 styleNames = ['font-size', 'font-family', 'font-weight', 'font-style', 'background', 'color']
class CopyStyleCommand : public Command {
   execute(): 将被选中 node 的 data 与 style 有关的部分复制内部 clipboard
}

// 粘贴已拷贝的样式到选中的节点上
class PasteStyleCommand : public Command {
   execute(): 将 clipboard 中 style 复制到被选中 node 上. 然后布局.
}

// 移除选中节点的样式
class ClearStyleCommand : public Command {
   execute(): 清除被选 node data 中 style, 重新渲染和布局.
}

register module StyleModule {
   commands: copystyle->CopyStyleCommand etc.
}

 

=== module/text.js ===

FONT_ADJUST 用于针对不同系统,浏览器,字体 做居中兼容性处理......

class TextRenderer : public Renderer {
   create(): 为 text 创建 kity.Group 对象, 应是 <g> 元素.
   update(): 得到/计算文本, 样式, 浏览器兼容性调整等数据.
      创建/修改 kity.Text() 对象/元素在 <g> 中. 这里代码较多, 需稍后细看.
   setTextStyle(): 遍历 _styleHooks[] 钩子进行回调.
}

class TextCommand : public Command {
   execute(): 为选中节点设置文本.
}

extend class TextRenderer {
   static _styleHooks: []  // 一种可以扩展 style 的机制...
   static registerStyleHook(): 添加钩子到 _styleHooks[] 中.
}

extend class MinderNode {
   getTextGroup(): ?
}

register module text {
   commands: text->TextCommand,
   renderers: center->TextRenderer
}
这里的问题是, 对于一个 node 的一组 renderers[], 是如何使用的? 前面已经看到很多种不同 renderer 了.


前面看 font.js 时跳过以等待看 text.js, 则现在补看.

=== module/font.js ===

register StyleHook in TextRenderer {
   看起来是得到 node 的字体(font)样式然后渲染到 svg 元素上.
}

// 设置选中节点的字体颜色. 对于 queryValue(), 如果只有一个节点被选中
//   则返回节点颜色; 如果有多个则返回 'mixed', 如果计算是否公共的更好吗?
class fontcolorCommand : public Command {
   execute(): node.data.color = val; 然后 render().
}

// 设置选中节点的背景颜色
class backgroundCommand : public Command {
   execute(): node.data.background = color
}

// 下面 fontfamilyCommand, fontsizeCommand 类似, 略去.
// 很多命令都要求有节点被选中才能使用, 为什么不 mixin 这个函数或属性进去呢?

register module fontmodule {
   commands: forecolor->fontcolorCommand, etc.
}

 

=== 回顾 basestyle.js  ===

// 加粗选中的节点
class boldCommand : public Command {
   execute(): node.data.font-weight = 'bold' or ''
}

class italicCommand : public Command {
   execute(): node.data.font-style = 'italic' or ''
}

register StyleHook[] of TextRenderer {
   根据节点的 font-weight, font-style 属性设置 svg 元素的字体属性.
   这里 hook 弄得有点过复杂, 还有 style-hash 的构成和计算也很麻烦...
}

register module basestylemodule {
   commands: bold->boldCommand, italic->italicCommand.
   shortcutKeys: ctrl+b->bold, ctrl+i->italic
}


=== module/view.js ===

// 当前主要是不知道这个类对应界面什么东西?
class ViewDragger {
   timeline(): ?
   move(),moveTo(): ? 见下面 CameraCommand.
}

// 切换抓手状态,抓手状态下,鼠标拖动将拖动视野,而不是创建选区
// 这个应是对应界面上 '允许拖拽' 按钮(左下部分)
class ToggleHandCommand : Command {
   execute(): status='hand'
}

// 设置当前视野的中心位置到某个节点上. 看起来对应 '定位根节点' 按钮功能?
class CameraCommand : Command {
   execute(): 使用 ViewDragger.move() 来实现.
}

// 指定方向移动当前视野, 在四个方向上可移动一半视野...
class MoveCommand : Command {
   execute(): 使用 ViewDragger.move() 实现, 给出移动距离和时间.
}

register module View {
   commands: hand->ToggleHandCommand etc.
   events: 几个事件的注册及处理, 暂时略.
}

 

=== module/zoom.js ===

// 缩放当前的视野到一定的比例(百分比)
class Zoom : Command {
  execute(): 使用动画(相关词有 animator, timeline, 暂时不熟悉)放大 view.
     发布 viewchange, zoom 事件.
}

class ZoomInCommand/ZoomOutCommand : Command {
   execute(): 缩小/放大, 实现类似于 Zoom.
}

register module Zoom {
   init: 设置缩放比例的数组 [10,20,50,100,200] 可以自定义.
   commands: zoom,zoomin,zoomout
   events: 似乎可以用 mousewheel 来缩放. 未实验成功.
   shortcutKeys: ctrl+=, ctrl+- 对应缩放.
}

 

=== 以上完成了第一遍对 module/*.js 的遍览, 现在可以回顾一下比较重要的 render 部分.

已知在 render.js 中扩展了方法 Minder.renderNode(node), 伪代码及解释如下:

function Minder::renderNode(node) {
  // 1. 如果此节点还未创建 renderers[] 则现在创建.
  if (!node._renderers)
     createRenderersForNode(node);
  
  // 2. 发布 before-render 事件
  fire_event(before-render, ...)
  
  // 3. 遍历所有 render in node._renderers[]. 
  //  此处按照的顺序, 是创建 ._renderers[] 的顺序, 按照程序是
  //     center,left,right,top,bottom,outline,outside.
  node._contentBox = new Box();  // 初始化计算盒子(矩形).
  for-each (renderer) {
    // 3.1 判断(根据上下文) 是否应该渲染.
    if (renderer.should_render?) {
      // 3.1.1 此时需要渲染, 如果渲染图形(元素 <g>)未创建, 则现在创建.
      if (!renderer.<g>)
        renderer.<g> = renderer.create() --> append-to(<g>)
      // 3.1.2 显示该元素
      .<g>.visible = true
      // 3.1.3 更新(update) 渲染图形, 这里我们知道 create() 只调用一次,
      //    update() 每次渲染(改变)时都会被调用. 可能结果存于 box 中.
       last_box = renderer.update(..., .box)
      // 3.1.4 合并渲染区域(符号 += 解释为 merge 方法).
      renderer.content_box += last_box 
    }
    // 3.2 如果不需渲染, 但是已经创建了 svg 图形元素, 则把它们隐藏起来. 
    else if (renderer.<g>) {
      .<g>.visible = false;
    } 
    // 3.3 否则什么都不需要做.
  }

  // 4. 发布 node-render 事件.
  fire-event(node-render, ...)
}


回顾一下最基本的 TextRenderer:

// text 是 'center' 型 renderer, 渲染过程中一般第一个被调用.
class TextRenderer : public Renderer {
  create(): {
    new kity.Group() // 产生一个 <g> 元素, id 为 node_textN, N 为数字.
  }
  update(): {
    // 略去一些 browser 相关兼容代码.
    box = new kity.Box()
    // 遍历 style_hooks[] 让各个模块设置 text-style (简略一些)
    for-each (style_hooks) --> hook(...)
    // 为每行文本创建一个 svg <text> 元素.
    for-each (line) --> new kity.Text(...) add-to(<g>)
    // 再次遍历 style_hooks[] ... 这里不知道为什么遍历第二次? 也许应该先创建 <text> 再设置 style 才对.
    for-each (style_hooks) --> hook(...)
    // 计算一个 textHash, 可能用于比较与上次是否发生了变化.
    text_hash = ....join('/')
    // 返回一个函数, 函数在调用 update() 的 render 中判断和调用.
    // 可能某些地方会延迟调用?
    return function() {
      // 计算 box 并返回的代码.
    }
  }
}

// 回顾一个 style_hook:
FontModule.style_hook = function(node, <g>) {
  color = node.color | node.style.color | ...
  font-family = node.font-family | ...
  font-size = node.font-size | ...
  // 将这些字体相关属性设置到 svg 元素上.
  <g>.fill = color  // color 属性设置到 <g>
  <g>.for-each(<text>)
    <text>.font-family=..., .font-size=...
}

// 另一个 style_hook
BaseStyleModule.style_hook = function(node, <g>) {
  <g>.for-each (<text>)
    <text>.weight = node.font-weight
    <text>.style = node.font-style
}


这样大致理解了 render 过程. 表述为将一个 node(可认为是一个 json object, 含一组属性)对应到画布元素(一个或
多个)的过程. 通过扩展机制1(注册到 _rendererClass[]) 的方法为每个节点产生 renderers[], 再通过扩展机制2
(注册到 style_hooks[]) 来支持节点的 TextRenderer 的各种 style 扩展. 其它类型的 Renderer 没有扩展机制2.

(END)

 

 

 

 

 

  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 54
博文 141
码字总数 223378
×
刘军兴
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: