[TOC]
# 项目概览:happy:
## [样本案例](https://state.software/#model-panel)
<img src="https://ww2.sinaimg.cn/large/006tNbRwly1fdlcna76vfj31jc0nwgp3.jpg" width = "400" height = "300" alt="图片名称" align=center />
## 绘制过程
<img src="https://ww4.sinaimg.cn/large/006tNbRwly1fdlcoiu8epg30g60cfk4q.gif" width = "400" height = "300" alt="图片名称" align=center />
## 绘制结果
<img src="https://ww1.sinaimg.cn/large/006tNbRwly1fdlcneju9lj314q0ow77a.jpg" width = "400" height = "300" alt="图片名称" align=center />
<img src="https://ww3.sinaimg.cn/large/006tNbRwly1fdlcn8ft20j318s0oq0we.jpg" width = "500" height = "300" alt="图片名称" align=center />
## 结果复用
<img src="https://ww3.sinaimg.cn/large/006tNbRwly1ffvkruy54hg30z50hj1fo.gif" width = "500" height = "300" alt="图片名称" align=center />
## Build Setup
```bash
# install dependencies
npm install
# serve with hot reload at localhost:8080
npm run dev
# build for production with minification
npm run build
```
# 要点归纳 :cool:
1. getBbox(true)/getBbox() 区别: 没有文档,就阅读源码.
2. sideBar:小数取整导致值缺失(越积累越多),极快速拖动条框,导致条框跟随(越界时无法初始化)(preventDefault解决),jQuery的draggable使用(stop状态一定要重置).
3. 路径跟踪(vue.watch的属性直接赋值才会引起改变,如果是对象,对对象属性赋值无法触发)
4. 箭头角度(Math.atan2,四个象限想不清除,后来实操解决)
5. 鼠标带动 路径180转动时,在第四/三象限需要 负偏移些, 其他两个象限需要正偏移,**否则**鼠标下面是路径元素,松开时无法捕捉到 状态图.(这里offset即偏移是path(带角度)偏移,然后计算得到相应的X,Y轴偏移量,直接定死X,Y偏移量太Low了.)
6. SVG内部的SVG图,嵌套放缩.
```
function calculateNowScale(originalScale, containsScale, returnPalette) {
let nowScale = _.clone(originalScale);
if (returnPalette) {
containsScale.forEach(function(item) {
nowScale.x *= item.x;
nowScale.y *= item.y;
})
} else {
containsScale.forEach(function(item) {
nowScale.x /= item.x;
nowScale.y /= item.y;
})
}
return nowScale;
}
```
1. SVG 中嵌套的SVG图来回移动. (先发现所有的root元素,)("mousedown"在platte中移动;"mouseup"发现其父元素,根据迭代计算的放缩值计算位移值)
```
function translateTheRoot(el, contains, returnPalette) {
const vel = V(el);
let scale;
let relativeTranslate;
let absoluteTranslate;
if (contains.length) {
scale = contains.map(function(el) {
return parseScaleString(el);
}).reduce(function(a, b) {
return { x: a.x * b.x, y: a.y * b.y };
});
relativeTranslate = vel.bbox(false, contains[0]);
absoluteTranslate = V(contains[0]).bbox();
} else {
scale = { x: 1, y: 1 };
relativeTranslate = vel.bbox();
absoluteTranslate = V(el.ownerSVGElement).bbox();
}
const nowTranslate = {};
if (returnPalette) {
nowTranslate.x = (relativeTranslate.x * scale.x) + absoluteTranslate.x;
nowTranslate.y = (relativeTranslate.y * scale.y) + absoluteTranslate.y;
} else {
nowTranslate.x = (relativeTranslate.x - absoluteTranslate.x) / scale.x;
nowTranslate.y = (relativeTranslate.y - absoluteTranslate.y) / scale.y;
}
vel.translate(nowTranslate.x, nowTranslate.y, { absolute: true });
}
```
1. 解耦(每个组件内部有自己的Method,画板platte值负责触发)(通过MapAction函数注册)(findParentByName先确定元素类型)
```
//event choose function
chooseComponent: function(e) {
this.component = utils.findParentByName(e.target, this.nameSet);
this.component ? this.method(this.component, e) : null;
},
moveComponent: function(e) {
this.component ? this.method(this.component, e) : null;
},
removeComponent: function(e) {
this.component ? this.method(this.component, e) : null;
this.component = undefined;
//send data to codeEditor, when 'mouseUp' to promise latest component position.
const item = utils.findParentByName(e.target, [this.pathName, this.rootName]);
this[SET_CODE_KEY](item ? item.id : null);
},
```
```
<svg class="sketch" @mousemove="moveComponent" @mouseup="removeComponent" @mousedown="chooseComponent" @mouseover="displayTool" @mouseout="hideTool">
```
1. 柯里化函数(不同需求只是变量不同,逻辑相同) (取代重载利器)
```
export function curryIt(fn) {
const len = fn.length;
const args = [];
const func = function(num) {
args.push(num);
if (args.length === len) {
return () => fn.apply(null, args);
} else {
return func;
}
}
return func;
}
```
1. $watch与compute
$watch相比compute更灵活,也就是说$watch位置随意,可访问的变量灵活了.
1. 路径/箭头实现
v-for循环出linkData中的元素数量,:data绑定pointLink.vue的`props: ['data'], `. computed中的pathD,arrowD即长和箭头都跟着联动了.
=> 主面板只要watch事件并更改linkData值即可.
```
<PointLink v-for="item in linkData" :data="item"></PointLink>
```
1. 编辑代码面板
mapState的store中数据变更也能带动更新computed相应的变量.(相当于引用了data)
```
computed: mapState({
datasets: state => state.card.datasets.filter(data => data.name.includes(state.card.filterKey))
})
```
利用@input="updataCode($event.target.value)"更新.
# 开发随笔 :note:
## 总结
### SideBar
在具有变动DOM大小的需求中,应该使用absolute,因为正常文档流中如果取整数,很容易多/少1px,将元素挤下去。(这里仍旧使用static,float,但采用小数(最好别这样),唉)
absolute元素若果没有非static元素的限制,起点会以body为基准,但**height:100%会以视口window为基准。除非给body加上非static的属性声明.
### Search
### List
margin,width 是同级的,也就是说margin会在width=100%上给元素叠加,超出的部分默认overflow
父元素width就会对子元素约束,并且子元素不会撑开父元素。
否则,父元素大小由子元素确定.
overflow:hidden 常配合 父元素的 固定宽高使用。
### SVG
SVG 适合于直接 px 布局,结合 scalable;
它本身不是面向width=*%的,而且也只会去第一次转化的px为其大小.
普通元素自适应百分比布局倒挺好的。
svg 默认 类似于 inline-block; 但是若想和他一行,应该使用float(如果使用inline-block, 会有高度差)

SVG的g/内部标签不支持
droppable,SVG不支持拖入SVG的事件触发,例如drop不会被触发.
### Vue class
父组件中暴露的字组件的class=sketch, 如果父组件也对sketch进行了定义,那么它的亲儿子元素sketch会叠加。
而亲儿子元素内部的sketch不会受到影响。(子组件不受它爷爷,老爷影响,但受他爸)
组件间 彼此通讯的数据 越少越精剪越好。
### modules.exports export export default
ES6 会将export export default 一起包装为{ **:**, default:**},
然后赋给modules.export, 再通过require导入.
也就是说ES6只用export,而webpack new webpack.ProvidePlugin() 是import * as "what?", 所以default是在一个“what?”对象中。
因此,要么用module.exports导,要么手动import {default} as ?. 而上面那个插件只能用module.exports格式了。
### transform
css3 transform 与 svg transform 不同。
g标签可以设置css3 transform, 但会使svg transform失效。
### z-index
SVG内部元素不识别z-index, 谁(e.g g标签)挂载在最后,�