# 基于 MVVM 和 canvas 的图形框架的使用文档

## 更新日志
### `2.4.32`
- 支持deep watch
### `2.4.30`
- 支持mixin template
### `2.4.27`
- fix: bug
- 新增 Vue.getComponentDefinition 和 this.$getComponentDefinition 方法

### `2.4.23`
- fix: zIndex

### `2.4.23`
- fix: 去掉分区，限制clip范围

### `2.4.22`
- fix: 使用Set替换Link

### `2.4.20`
- fix: 修复响应式的bug

### `2.4.13`
- 优化show的性能

### `2.4.12`
- 优化依赖收集性能问题

### `2.4.11`
- fix: 不使用 object-rest-spread

### `2.4.10`
- fix: bug 

### `2.4.9`
- 新增 ``show`` 配置项，值为``false``时将不显示改组件以及子组件 

### `2.4.8`
- 修复卡死问题

### `2.4.7`
- 修复显示bug，修复offscreen配置的bug
- 分区域获取某一点上的组件，提高性能

### `2.4.6`
- 修复canvas裁剪残影的bug

### `2.4.5`
- 修复 bug

### `2.4.4`

- 修复 bug

### `2.4.3`

- 引入 `config 键值对对象`取代 `config 钩子函数`，后续会在某个版本完全移除 `config钩子函数`的支持
- `config 键值对的对象`是一个，属性可以是基础属性，也可以是函数，函数的第一个参数是当前 Uae 实例对象
- 使用箭头函数时，`this`不是当前 Uae 实例对象，但当前 Uae 实例对象作为第一个参数传进来
- 示例：

  ```javascript
  Uae.component('name', {
    data() {
      return {
        x: 100,
        y: 100
      }
    }
    config: {
      x: um => um.x,
      y() { return this.y },
      width: 100,
      height: 40
    }
  })
  ```

- 优化报错提示

### `2.4.2`

- 修复`offscreen`的 bug

### `2.4.0`

- 新增`局部更新`特性，升级到`2.4.0`后，如果想要提高流畅性，请配置好组件的`宽高`，最好与理想宽高贴合
- 如果组件的宽高任意一个不设置，都会影响父组件的局部更新

### `2.3.18`

- 优化了内存占用问题
- 移除了 solid 配置项，离屏 canvas 由默认使用改为默认不使用，升级`2.3.18`或更高的版本之后，若发现图形变卡，请尝试在组件添加配置`offscreen: true`

## 引入

```
npm install uaeengine
```

```
<script src="https://unpkg.com/uaeengine/dist/uae.js"></script>
```

## 全局配置

```javascript
Uae.config.guide = true; // 打开辅助线，开发阶段可打开
Uae.config.focusEvent = 'mouseup'; // 设置聚焦事件，默认mouseup
```

## 工具方法

在`2.3.18`版本之后可用

```javascript
import { isPointInCircle, isPointInRoundRect, isPointInPath } from 'uaeengine/src/utils';
```

- isPointInCircle 判断坐标是否在圆内
- isPointInRoundRect 判断坐标是否在圆角矩形内
- isPointInPath 判断坐标是否在路径上

## 实例化

```javascript
import Uae from 'uaeengine';
let app = new Uae({
  canvas: this.canvas, // canvas dom对象
  template: `<component v-for="item in elements" :is="item.type" :data="item"/>`, // 元素定义
  data() {
    return {
      elements: [
        {
          id: 'element1',
          type: 'startEvent',
          name: '空启动事件'
        }
      ]
    };
  },
  computed: {
    // 计算属性
  },
  config() {
    // 配置
  },
  methods: {
    // 方法声明
  },
  watch: {
    // 数据监听
  },
  beforeCreate() {
    // 访问不了data, computed, method等
  },
  created() {
    // data 可访问
  },
  beforeMount() {
    // computed, method, config 可访问
  },
  mounted() {
    // watch 绑定
  },
  beforeDestroy() {
    // 销毁前
  },
  destroyed() {
    // 销毁
  }
});
```

## 组件定义

```javascript
Uae.component('名称', {
  props: ['data'], // 入参，字符串数组
  template: '<comp1/>', // 子元素定义, 不支持插槽
  draw() {
    // 自定义图形，使用 this.$ctx 绘画
  },
  isHere(cx, cy) {
    // 不一定要有，cx, cy 是鼠标在组件的坐标
    // 如果该钩子函数存在，会以该函数为准
    // 缺省时会根据组件内部方法 $isPointInHere(cx, cy) 判断是否在组件上
  },
  config: {
    // config 属性可以是基础属性，也可以是函数，函数的第一个参数是 当前示例
    x() {
      return 0;
    }, // 相对父组件的定位，默认0,
    y: um => um.y, // 相对父组件的定位，默认0
    width, // 组件大小，默认是父组件的宽度，不建议不设置，会影响性能
    height, // 组件大小，默认是父组件的高度，不建议不设置，会影响性能
    zIndex, // 兄弟组件的显示层级，默认0
    offscreen, // 离屏canvas, 默认为undefined，如果Uae设置为false，则所有组件为false。true使用，false不使用，undefined会生成一个面积最大为10000平方像素的离屏canvas。
    offsetX, // 偏移量，子组件和draw画的图形相对本身偏移，默认0
    offsetY, // 偏移量，子组件和draw画的图形相对本身偏移，默认0
    scale, // 组件缩放，默认1
    overflow, // 默认hidden，可选 visible（子组件可超出该组件范围）
    show, // 默认true，值为false时将不显示改组件
  }
  // 其它钩子函数
});
```

## offscreen 配置使用说明

- 缺省值 `undefined` ,会生成一个小的`离屏canvas`，用于辅助函数 `$isPointInHere` 判断坐标是否在组件上，所以 `$isPointInHere` 不能保证返回正确
- 如果组件`尺寸过大`，则不建议设为 true，因为离屏 canvas 过大后，绘制离屏 canvas 的速度反而不如直接使用钩子函数 draw 直接绘制的快
- 建议所有 `offscreen` 值为 `undefined` 的组件，提供 `isHere` 函数并且把 `offscreen` 改为 `false`

## 组件内置变量

- $parent 父组件
- $children 子组件
- $root 画板对象
- $ctx 上下文对象，提供 $ctx.roundRect(x, y, width, height, radius) 得到圆角矩形路径
- $ctx 仅在 draw 钩子函数中有效，如需要借助 $ctx 计算宽度，请使用 this.$root.$ctx 来计算
- $tag 组件标签名

## 组件内置方法

- $on 绑定事件
- $off 取消绑定
- $offAll 取消绑定所有事件
- $emit 对外抛出事件
- $nextTick 下个事件周期执行
- $toCanvasX 坐标转换
- $toCanvasY 坐标转换
- $toOriginalX 坐标转换
- $toOriginalY 坐标转换
- $isPointInHere 判断点是否在组件内，仅当离屏 canvas 存在时有用
- $isPointInBox 判断点是否在组件的盒子模型内
- $findCompByPoint 获取组件实例

## 内置组件

### component

- 入参 Props
  - is -string，组件名称
- 用法
  ```html
  <component is="selRect" :data="data" />
  ```

## 混入

- 全局混入

```javascript
Uae.mixin({
  props: [],
  template: '',
  draw() {
    // 会被覆盖
  },
  isHere() {
    // 会被覆盖
  },
  data() {
    return {
      // 同名被覆盖
    };
  },
  computed: {
    // 同名被覆盖
  },
  methods: {
    // 同名被覆盖
  },
  watch: {
    // 同名被覆盖
  },
  beforeCreate() {
    // 不会被覆盖
  },
  mounted() {
    // 不会被覆盖
  },
  beforeDestroy() {
    // 不会被覆盖
  }
});
```

- 组件混入

```
Uae.component('selRect', {
    mixins: []
})
```

## 内置指令

- : 绑定数据
- @ 绑定事件
- v-for="item in arr" v-for="(item, index) in arr"
- v-if 绑定数据 v-if="visible"
- v-if 优先级高于 v-for
- 待扩展：自定义指令

## 事件

### 组件事件

```javascript
Uae.component('selRect', {
  template: '<button @click="handleClick"/>', // @click="handleClick"
  methods: {
    handleClick() {
      console.log('click');
    }
  }
});
```

- 内置事件有
  - click
  - dblclick
  - contextmenu
  - mousemove
  - mouseenter
  - mouseleave
  - mousedown
  - dragstart
  - drag
  - dragend
  - dragenter
  - dragover
  - dragleave
  - drop
- 在组件内使用 this.$emit('name') 自定义事件

### 对外事件

```javascript
let app = new Uae();
// 事件绑定
app.$on('click', e => {});
app.$on('contextmenu', e => {});
app.$on('mousemove', e => {});
app.$on('mousedown', e => {});
app.$on('dblclick', e => {});
app.$on('dragstart', e => {});
app.$on('drag', e => {});
app.$on('dragend', e => {});
app.$on('mouseenter', e => {});
// 取消绑定
app.$off('mouseenter', func);
app.$offAll('mouseenter');
```
