Commit 9f91613b authored by 张晨辰's avatar 张晨辰

feat: merge

parents 726aa7d2 95e07b86
No preview for this file type
......@@ -2,7 +2,7 @@
* Created by rockyl on 2019-09-23.
*/
const data = {
const data1 = {
"views": [
{
"name": "view1",
......@@ -71,7 +71,23 @@ const data = {
}
]
};
const data = {
"views": [
],
"assets": [
{
"name": "bg.jpg",
uuid:"a1",
"url": "http://0.0.0.0:4002/assets/bg.jpg"
},
{
"name": "btn-join.png",
uuid:"a2",
"url": "http://0.0.0.0:4002/assets/btn-join.png"
}
]
};
const resp = {
"success": true,
"data": {
......
......@@ -2,12 +2,14 @@
* Created by rockyl on 2019-09-19.
*/
export const API_HOST = 'http://10.10.95.74:7777';
//export const API_HOST = 'http://localhost:3002';
//export const API_HOST = 'http://10.10.93.73:7777';
export const API_HOST = 'http://localhost:3002';
export const UPLOAD_FILE_URL = API_HOST + '/api/uploadFile';
export const PARSE_BUNDLE_URL = API_HOST + '/api/parsePSD';
export const DOCK_POINT_OFFSET = 4;
//文件类型图标 t表示展示缩略图
export const fileTypeIcon = {
'': 'file-empty',
......
......@@ -16,10 +16,12 @@ export default new Router({
{
path: '/editor/:projectID',
name: 'editor',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "editor" */ './views/Editor.vue')
}
component: () => import('./views/Editor.vue')
},
{
path: '/behavior',
name: 'behavior',
component: () => import('./views/BehaviorEditorWrapper.vue')
},
]
})
......@@ -65,8 +65,8 @@ export const projectStore = {
},
/**
* 修改当前组件的属性
* @param {*} state
* @param {*} data
* @param {*} state
* @param {*} data
*/
modifyProperties(state, data) {
if (!data || !data.label) {
......@@ -80,8 +80,8 @@ export const projectStore = {
},
/**
* 修改当前组件
* @param {*} state
* @param {*} data
* @param {*} state
* @param {*} data
*/
modifyComponent(state, data) {
if (!data || !data.label) {
......
@import "var";
$dock-point-width: 9px;
.behavior {
width: 100%;
height: 100%;
.svg-board {
width: 100%;
height: 100%;
.line {
stroke: #979797;
&.hover, &:hover {
stroke: $--color-primary;
stroke-dasharray: 5, 1;
}
}
.node {
display: flex;
flex-direction: column;
min-width: 100px;
background-color: $--background-color-base;
border: 1px solid $block-border-blur-background-color;
position: relative;
border-radius: 5px;
outline: none;
user-select: none;
margin: 0 $dock-point-width;
&:hover {
border-color: $block-border-hover-background-color;
& > .header {
background-color: $block-border-hover-background-color;
}
}
&:focus {
border-color: $block-border-focus-background-color;
& > .header {
background-color: $block-border-focus-background-color;
}
}
.header {
min-height: 12px;
background-color: $block-border-blur-background-color;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
padding: 3px;
font-size: 12px;
color: white;
}
.body {
display: flex;
flex-direction: column;
padding: 3px;
font-size: 12px;
color: $--color-text-primary;
.field-item {
display: flex;
.key {
flex: 1;
width: 0;
overflow: hidden;
}
.value {
flex: 1;
text-align: right;
}
}
}
.dock {
position: absolute;
top: 50%;
transform: translateY(-50%);
display: flex;
flex-direction: column;
.point {
border: 1px solid $block-border-blur-background-color;
padding: 1px;
margin-bottom: 5px;
background-color: white;
div {
width: 3px;
height: 3px;
border: 1px solid $block-border-blur-background-color;
border-radius: 3px;
}
&:hover {
border-color: $--color-primary;
& > div {
border-color: $--color-primary;
}
}
&:last-child {
margin-bottom: 0;
}
}
}
.input {
@extend .dock;
left: -$dock-point-width;
}
.output {
@extend .dock;
right: -$dock-point-width;
}
}
}
.properties {
width: 100%;
height: 100%;
background-color: #5396da;
}
}
......@@ -26,17 +26,8 @@ $--font-path: '~element-ui/lib/theme-chalk/fonts';
$--pane-background-color: mix($--background-color-base, $--color-black, 95%);
$--pane-border-color: mix($--background-color-base, $--color-black, 90%);
$main-border-color: mix($--background-color-base, $--color-white, 80%);
$block-blur-border-color: $main-border-color;
$block-hover-border-color: mix($main-border-color, $--color-white, 80%);
$block-focus-border-color: mix($main-border-color, $--color-white, 50%);
$block-header-blur-background-color: mix($--color-black, $--color-white, 50%);
$block-header-hover-background-color: mix($--color-primary, $block-header-blur-background-color, 40%);
$block-header-focus-background-color: $--color-primary;
$dock-item-color: $block-blur-border-color;
$dock-item-hover-color: deepskyblue;
$block-border-blur-background-color: mix($--background-color-base, $--color-black, 60%);
$block-border-hover-background-color: mix($--color-primary, $block-border-blur-background-color, 40%);
$block-border-focus-background-color: $--color-primary;
$--design-border-color: $--color-primary;
\ No newline at end of file
<template>
<behavior-editor></behavior-editor>
<behavior-editor style="width: 100%;height: 100%;display: flex;"></behavior-editor>
</template>
<script>
......
<template>
<div class="behavior">
<split-panes class="pane-container">
<board :builtins="builtins" :mainProcess="mainProcess" splitpanes-min="20" :splitpanes-size="80"/>
<div class="properties" splitpanes-min="20" :splitpanes-size="20">
</div>
</split-panes>
</div>
</template>
<script>
import Board from "./Board";
import SplitPanes from 'splitpanes'
const builtins = {
entry: {
id: 'entry',
name: 'Entry',
options: {},
script: "resolve({type: 'success'});",
output: ['success'],
},
wait: {
id: 'wait',
name: 'Wait',
options: {
duration: {type: 'number', default: 1000},
},
script: "setTimeout(function(){resolve({type: 'complete'})}, options.duration || 0);",
output: ['complete'],
},
};
const mainProcess = {
uuid: '1',
alias: '主过程',
meta: {
id: 'main',
name: 'Main',
options: {},
metas: {
compare: {
id: 'compare',
name: 'Compare',
options: {
left: {type: 'any', default: ''},
right: {type: 'any', default: ''},
operator: {type: 'string', default: '=='},
},
script: `
let leftValue = typeof options.left === 'object' ? args[options.left.path] : options.left;
let rightValue = typeof options.right === 'object' ? args[options.right.path] : options.right;
let func = new Function('return '+leftValue+args.operator+rightValue);
let result = func();
resolve({type: result ? 'equal' : 'unequal'});
`,
output: ['complete'],
},
nestProc: {
id: 'nestProc',
name: 'NestProc',
metas: {
print: {
id: 'print',
name: 'Print',
options: {
text: {type: 'string', default: ''},
},
script: "console.log(options.text);resolve({type: 'success'});",
output: ['success'],
}
},
options: {},
subEntry: '1',
sub: {
1: {
uuid: '1',
meta: 'wait',
alias: '等待',
options: {
duration: 500,
},
output: ['2'],
},
2: {
uuid: '2',
alias: '打印',
meta: 'print',
options: {
text: 'hello',
},
output: [],
},
},
},
test: {
options: {
text: {type: 'string', default: ''},
},
script: "console.log(args, options);resolve({type: 'success'});",
output: ['success', 'failed'],
},
},
subEntry: '1',
sub: {
1: {
uuid: '1',
alias: '入口',
meta: 'entry',
output: {
success: ['2'],
},
design: {
x: 10,
y: 10,
},
},
2: {
uuid: '2',
alias: 'test',
meta: 'test',
options: {
text: 'hello',
},
output: {
success: ['3'],
failed: [],
},
design: {
x: 20,
y: 100,
},
},
3: {
uuid: '3',
alias: '等待',
meta: 'wait',
options: {
duration: 500,
},
output: {
complete: ['4']
},
design: {
x: 200,
y: 50,
},
},
4: {
uuid: '4',
alias: 'nestProc',
meta: 'nestProc',
options: {
text: 'hello',
},
output: [],
design: {
x: 150,
y: 200,
},
},
}
}
};
export default {
name: "BehaviorEditor",
components: {Board,SplitPanes,},
data() {
return {
builtins,
mainProcess,
}
},
mounted() {
},
methods: {
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<div class="behavior">
<svg class="svg-board" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="layer" stroke-width="2" fill="none" fill-rule="evenodd">
<link-line v-for="(line, key, index) in lines" :data="line" :key="index" @dblclick="onDeleteLine"></link-line>
<path v-show="lineDrawing.visible" class="line hover" :d="lineDrawing.path"></path>
</g>
<g id="nodes">
<process-node v-for="(process, key, index) of processMap" :process="process" :key="index"
@hover-point="onPointHover"
@leave-point="onPointLeave"
@down-point="onPointDown"
/>
</g>
</svg>
<tool-tip ref="toolTip"/>
</div>
</template>
<script>
import ProcessNode from "./Board/ProcessNode";
import Process from "./Board/Process";
import LinkLine from "./Board/LinkLine";
import ToolTip from "./Board/ToolTip";
import {DOCK_POINT_OFFSET} from "../../../config";
import {state} from "./Board/state";
export default {
name: "Board",
components: {ToolTip, LinkLine, ProcessNode,},
props: ['builtins', 'mainProcess'],
data() {
let processMap = {};
let currentProcess = new Process(null, this.mainProcess, this.builtins);
for (let id in currentProcess.meta.sub) {
const subData = currentProcess.meta.sub[id];
processMap[id] = new Process(currentProcess, subData, this.builtins)
}
return {
processMap,
lines: {},
lineDrawing: {
visible: false,
path: ''
}
}
},
mounted() {
this.updateLines();
},
methods: {
updateLines() {
this.lines = {};
for (let id in this.processMap) {
const process = this.processMap[id];
const {output} = process.data;
for (let outputType in output) {
const outputGroup = output[outputType];
for (let i = 0, li = outputGroup.length; i < li; i++) {
const outputID = outputGroup[i];
this.addLine(process.data, outputID, outputType, i);
}
}
}
console.log(this.lines);
},
addLine(process, outputID, outputType, outputIndex) {
const nextProcess = this.processMap[outputID];
if (nextProcess) {
this.$set(this.lines, state.lineID, {
id: state.lineID,
prev: process,
next: nextProcess.data,
outputType,
outputIndex,
});
state.lineID++;
}
},
onPointHover(x, y, point) {
this.$refs.toolTip.show(x + 10, y - 8, point);
},
onPointLeave(x, y, point) {
this.$refs.toolTip.hide();
},
onPointDown(e, process, point) {
document.addEventListener("mousemove", this.onMouseMove);
document.addEventListener("mouseup", this.onMouseUp);
this.processDrawing = process;
this.pointDrawing = point;
const {x, y} = process.design;
const startPos = process.design.output[point][0];
this.drawingLineStart = `M${startPos.x + x - DOCK_POINT_OFFSET},${startPos.y + y + DOCK_POINT_OFFSET} C${startPos.x + x + 100},${startPos.y + y} `;
this.lineDrawing.visible = true;
state.drawing = true;
this.onMouseMove(e);
},
onMouseMove(e) {
const {x, y} = e;
this.lineDrawing.path = this.drawingLineStart + `${x},${y} ${x},${y}`;
},
onMouseUp(e) {
document.removeEventListener("mousemove", this.onMouseMove);
document.removeEventListener("mouseup", this.onMouseUp);
this.lineDrawing.visible = false;
state.drawing = false;
if(state.targetUUID){
this.processDrawing.output[this.pointDrawing] = [state.targetUUID];
this.addLine(this.processDrawing, state.targetUUID, this.pointDrawing, 0);
state.targetUUID = null;
}
},
onDeleteLine(line) {
const {prev, outputType, outputIndex, id} = line;
prev.output[outputType].splice(outputIndex, 1);
this.$delete(this.lines, id);
}
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<div class="point"
@mousedown.stop="onMouseDown"
@mouseenter.stop="onMouseEnter"
@mouseleave.stop="onMouseLeave"
>
<div></div>
</div>
</template>
<script>
export default {
name: "DockPoint",
props: ['data'],
methods: {
onMouseDown(e) {
this.$emit('mousedown', e, this.data);
},
onMouseEnter(e) {
this.$emit('mouseenter', e, this.data);
},
onMouseLeave(e) {
this.$emit('mouseleave', e, this.data);
},
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<path class="line" :d="transPath" @dblclick="onDblClick"></path>
</template>
<script>
import {DOCK_POINT_OFFSET} from "../../../../config";
export default {
name: "LinkLine",
props: ['data'],
mounted() {
console.log();
},
watch: {
'data': function (v) {
}
},
computed: {
transPath() {
const {prev, next, outputType, outputIndex} = this.data;
const from = prev.design.output[outputType][outputIndex];
const to = next.design.input['default'][0];
const fromPos = {
x: from.x + prev.design.x,
y: from.y + prev.design.y,
};
const toPos = {
x: to.x + next.design.x,
y: to.y + next.design.y,
};
//const absXOff = Math.abs(from.x - to.x);
let x1 = fromPos.x + 100;
/*if(absXOff < 200){
x1 = from.x + absXOff / 2;
}*/
let x2 = toPos.x - 100;
/*if(absXOff < 200){
x2 = to.x - absXOff / 2;
}*/
return `M${fromPos.x - DOCK_POINT_OFFSET},${fromPos.y + DOCK_POINT_OFFSET} C${x1},${fromPos.y + DOCK_POINT_OFFSET} ${x2},${toPos.y + DOCK_POINT_OFFSET} ${toPos.x + DOCK_POINT_OFFSET},${toPos.y + DOCK_POINT_OFFSET}`
},
},
methods: {
onDblClick(e) {
this.$emit('dblclick', this.data);
}
}
}
</script>
<style scoped>
</style>
/**
* Created by rockyl on 2019-09-29.
*/
export default class Process {
constructor(parent, data, builtins) {
this._builtins = builtins;
this._parent = parent;
this._data = data;
this._meta = typeof data.meta === 'string' ? this.resolveMeta(data.meta) : data.meta;
}
get data(){
return this._data;
}
get meta(){
return this._meta;
}
resolveMeta(name) {
let meta = this._meta ? this._meta.metas[name] : null;
if (!meta && this._parent) {
meta = this._parent.resolveMeta(name);
}
if(!meta){
meta = this._builtins[name];
}
return meta;
}
}
<template>
<foreignObject :x="data.design.x" :y="data.design.y" :width="width" :height="height">
<div ref="node" class="node" tabindex="0" @mousedown="onMouseDown" @mouseenter="onMouseEnter">
<div class="header">
<span>{{data.alias || meta.name}}</span>
</div>
<div class="body">
<div class="field-item" v-for="(param, key, index) in meta.options" :key="index">
<span class="key">{{key}}</span>:
<span class="value">{{data.options[key]}}</span>
</div>
</div>
<div ref="inputDock" class="dock input">
<dock-point v-if="meta.name !== 'Entry'" v-for="(point, key, index) in inputMeta" :key="index"></dock-point>
</div>
<div ref="outputDock" class="dock output">
<dock-point v-for="(point, key, index) in meta.output" :key="index" :data="point"
@mouseenter="onPointHover"
@mouseleave="onPointLeave"
@mousedown="onPointDown"
></dock-point>
</div>
</div>
</foreignObject>
</template>
<script>
import DockPoint from "./DockPoint";
import {state} from "./state";
export default {
name: "ProcessNode",
components: {DockPoint},
props: ['process'],
data() {
this.prepare();
const inputMeta = this.process.meta.name === 'Entry' ? [] : ['default'];
return {
width: 130,
height: 100,
inputMeta,
}
},
created() {
},
mounted() {
this.updateDockPointPos();
let bounds = this.$refs.node.getBoundingClientRect();
this.width = bounds.width + 9;
this.height = bounds.height;
},
computed: {
meta() {
return this.process.meta;
},
data() {
return this.process.data;
},
},
watch: {
process(v) {
}
},
methods: {
prepare() {
let {design, options} = this.process.data;
if (!design) {
this.$set(this.process.data, 'design', {});
design = this.process.data.design;
}
if (!options) {
this.$set(this.process.data, 'options', {});
options = this.process.data.options;
}
if (!design.x) {
this.$set(design, 'x', 0);
}
if (!design.y) {
this.$set(design, 'y', 0);
}
},
onMouseEnter(e) {
if(state.drawing){
state.targetUUID = this.data.uuid;
}
},
onMouseDown(e) {
const {x, y} = this.data.design;
this.mouseDownPos = {x: e.screenX, y: e.screenY, dx: x, dy: y};
document.addEventListener("mousemove", this.onMouseMove);
document.addEventListener("mouseup", this.onMouseUp);
},
onMouseMove(e) {
const {x, y, dx, dy} = this.mouseDownPos;
const offset = this.offset = {x: e.screenX - x, y: e.screenY - y};
const tx = offset.x + dx;
const ty = offset.y + dy;
this.data.design.x = tx;
this.data.design.y = ty;
this.$emit('changing-position', this, {x: tx, y: ty});
},
onMouseUp(e) {
document.removeEventListener("mousemove", this.onMouseMove);
document.removeEventListener("mouseup", this.onMouseUp);
if (this.offset) {
this.offset = null;
this.$emit('change-position', this, this);
}
},
updateDockPointPos() {
const {x: dx, y: dy} = this.process.data.design;
for (let side of ['input', 'output']) {
let container = this.$refs[side + 'Dock'];
let sideMeta = side === 'input' ? this.inputMeta : this.meta[side];
let dockPointPos = {};
if (sideMeta) {
for (let i = 0, li = sideMeta.length; i < li; i++) {
const key = sideMeta[i];
let posArr = [];
dockPointPos[key] = posArr;
let dockPoint = container.children[i];
const {x, y} = dockPoint.getBoundingClientRect();
posArr.push({
x: x - dx,
y: y - dy,
});
}
}
this.$set(this.process.data.design, side, dockPointPos);
}
},
onPointHover(e, point) {
const {x, y} = e.target.getBoundingClientRect();
this.$emit('hover-point', x, y, point);
},
onPointLeave(e, point) {
const {x, y} = e.target.getBoundingClientRect();
this.$emit('leave-point', x, y, point);
},
onPointDown(e, point) {
let output = this.data.output[point];
if (!output || output.length === 0) {
this.$emit('down-point', e, this.data, point);
}
},
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<div ref="dotTip" class="dotTip" :style="style" v-show="visible">
<span>{{content}}</span>
</div>
</template>
<script>
export default {
name: "ToolTip",
data() {
return {
visible: false,
content: '',
style: {
left: '0px',
top: '0px',
},
}
},
methods: {
show(x, y, text, delay = 0) {
if (delay > 0) {
setTimeout(() => {
this._show(x, y, text);
}, delay)
} else {
this._show(x, y, text);
}
},
_show(x, y, text) {
this.style.left = x + 'px';
this.style.top = y + 'px';
this.content = text;
this.visible = true;
},
hide() {
this.visible = false;
}
}
}
</script>
<style scoped>
.dotTip {
position: absolute;
top: 200px;
left: 200px;
color: white;
font-size: 12px;
background-color: #303133;
padding: 5px;
border-radius: 5px;
pointer-events: none;
}
</style>
\ No newline at end of file
/**
* Created by rockyl on 2019-10-08.
*/
export const state = {
drawing: false,
targetUUID: '',
lineID: 0,
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment