您的位置:首页 > 其它

学习 kityminder 笔记(九)

2015-11-24 00:00 369 查看
继续学习 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)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: