Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Z
zeroing-editor
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
劳工
zeroing-editor
Commits
480c0363
Commit
480c0363
authored
Dec 12, 2019
by
张晨辰
Browse files
Options
Browse Files
Download
Plain Diff
feat: merge
parents
6bdad43a
f8719341
Changes
27
Show whitespace changes
Inline
Side-by-side
Showing
27 changed files
with
1145 additions
and
122 deletions
+1145
-122
common.js
src/api/common.js
+2
-1
project.js
src/api/project.js
+10
-7
config.js
src/config.js
+3
-0
en.json
src/locales/en.json
+5
-1
zh-CN.json
src/locales/zh-CN.json
+5
-1
router.js
src/router.js
+5
-0
behavior.js
src/store/modules/behavior.js
+12
-1
env.js
src/store/modules/env.js
+2
-1
project.js
src/store/modules/project.js
+90
-27
projects.js
src/store/modules/projects.js
+5
-2
template.js
src/template.js
+2
-4
assets.scss
src/themes/light/assets.scss
+9
-5
behavior.scss
src/themes/light/behavior.scss
+18
-4
home.scss
src/themes/light/home.scss
+7
-0
playground.scss
src/themes/light/playground.scss
+4
-3
MaxRectsBinPack.js
src/utils/MaxRectsBinPack.js
+531
-0
index.js
src/utils/index.js
+20
-20
sheet-pack.js
src/utils/sheet-pack.js
+141
-0
Editor.vue
src/views/Editor.vue
+31
-6
Assets.vue
src/views/Editor/Assets.vue
+2
-4
FileItem.vue
src/views/Editor/Assets/FileItem.vue
+22
-11
BehaviorEditor.vue
src/views/Editor/behavior-editor/BehaviorEditor.vue
+10
-2
Board.vue
src/views/Editor/behavior-editor/Board.vue
+36
-9
MetaSearchDialog.vue
src/views/Editor/behavior-editor/MetaSearchDialog.vue
+45
-0
PropertiesEditor.vue
src/views/Editor/behavior-editor/PropertiesEditor.vue
+1
-1
Home.vue
src/views/Home.vue
+59
-12
Preview.vue
src/views/Preview.vue
+68
-0
No files found.
src/api/common.js
View file @
480c0363
...
@@ -59,7 +59,8 @@ export async function fetchApi(uri, {params, method = 'get', contentType = 'json
...
@@ -59,7 +59,8 @@ export async function fetchApi(uri, {params, method = 'get', contentType = 'json
break
;
break
;
}
}
}
else
{
}
else
{
url
+=
(
url
.
indexOf
(
'?'
)
<
0
?
'?'
:
''
)
+
(
url
.
endsWith
(
'&'
)
?
''
:
'&'
)
+
stringify
(
params
);
url
+=
(
url
.
indexOf
(
'?'
)
<
0
?
'?'
:
''
);
url
+=
(
url
.
endsWith
(
'?'
)
?
''
:
'&'
)
+
stringify
(
params
);
}
}
}
}
...
...
src/api/project.js
View file @
480c0363
...
@@ -6,8 +6,9 @@
...
@@ -6,8 +6,9 @@
import
{
fetchApi
}
from
"./common"
;
import
{
fetchApi
}
from
"./common"
;
export
async
function
fetchAll
()
{
export
async
function
fetchAll
(
currentPage
,
pageSize
)
{
return
await
fetchApi
(
'/api/project/query'
,
{
return
await
fetchApi
(
'/api/project/query'
,
{
params
:
{
currentPage
,
pageSize
,},
errMessage
:
'Failed to fetch projects'
,
errMessage
:
'Failed to fetch projects'
,
})
})
}
}
...
@@ -52,9 +53,9 @@ export async function saveOne(project) {
...
@@ -52,9 +53,9 @@ export async function saveOne(project) {
})
})
}
}
export
async
function
pack
(
id
,
debug
)
{
export
async
function
pack
(
id
,
debug
,
packedAssets
)
{
return
await
fetchApi
(
'/api/project/pack'
,
{
return
await
fetchApi
(
'/api/project/pack'
,
{
params
:
{
id
,
debug
},
params
:
{
id
,
debug
,
packedAssets
},
method
:
'post'
,
method
:
'post'
,
errMessage
:
'Failed to pack project'
,
errMessage
:
'Failed to pack project'
,
})
})
...
@@ -73,11 +74,13 @@ export async function importView(file) {
...
@@ -73,11 +74,13 @@ export async function importView(file) {
return
response
;
return
response
;
}
}
export
async
function
uploadFile
(
file
)
{
export
async
function
uploadFile
(
file
,
compress
=
false
)
{
let
params
=
{
file
};
if
(
compress
)
{
params
.
compress
=
true
;
}
const
response
=
await
fetchApi
(
'/api/uploadFile'
,
{
const
response
=
await
fetchApi
(
'/api/uploadFile'
,
{
params
:
{
params
,
file
,
},
method
:
'post'
,
method
:
'post'
,
contentType
:
'form-data'
,
contentType
:
'form-data'
,
errMessage
:
'Failed to upload file'
,
errMessage
:
'Failed to upload file'
,
...
...
src/config.js
View file @
480c0363
...
@@ -6,6 +6,7 @@ export let API_HOST;
...
@@ -6,6 +6,7 @@ export let API_HOST;
if
(
process
.
env
.
NODE_ENV
===
'development'
)
{
if
(
process
.
env
.
NODE_ENV
===
'development'
)
{
//API_HOST = 'http://10.10.95.74:7777';
//API_HOST = 'http://10.10.95.74:7777';
//API_HOST = 'http://192.168.1.16:7777';
//API_HOST = 'http://192.168.1.16:7777';
//API_HOST = 'http://192.168.0.104:7777';
//API_HOST = 'http://10.10.92.33:7777';
//API_HOST = 'http://10.10.92.33:7777';
//API_HOST = 'http://localhost:3002';
//API_HOST = 'http://localhost:3002';
API_HOST
=
window
.
__data
.
apiHost
;
API_HOST
=
window
.
__data
.
apiHost
;
...
@@ -22,6 +23,8 @@ export const SSO_VERIFY_PAGE_URL = '/sso/logout';
...
@@ -22,6 +23,8 @@ export const SSO_VERIFY_PAGE_URL = '/sso/logout';
export
const
DOCK_POINT_OFFSET
=
4
;
export
const
DOCK_POINT_OFFSET
=
4
;
export
const
PAGE_SIZE
=
20
;
//文件类型图标 t表示展示缩略图
//文件类型图标 t表示展示缩略图
export
const
fileTypeIcon
=
{
export
const
fileTypeIcon
=
{
''
:
'file-empty'
,
''
:
'file-empty'
,
...
...
src/locales/en.json
View file @
480c0363
...
@@ -17,6 +17,8 @@
...
@@ -17,6 +17,8 @@
"Delete all"
:
"Delete all"
,
"Delete all"
:
"Delete all"
,
"Import"
:
"Import"
,
"Import"
:
"Import"
,
"Export"
:
"Export"
,
"Export"
:
"Export"
,
"Importing project"
:
"Importing project"
,
"Exporting project"
:
"Exporting project"
,
"Upload"
:
"Upload"
,
"Upload"
:
"Upload"
,
"Uploading"
:
"Uploading"
,
"Uploading"
:
"Uploading"
,
"Edit"
:
"Edit"
,
"Edit"
:
"Edit"
,
...
@@ -55,6 +57,7 @@
...
@@ -55,6 +57,7 @@
"Packing"
:
"Packing"
,
"Packing"
:
"Packing"
,
"Type"
:
"Type"
,
"Type"
:
"Type"
,
"Group"
:
"Group"
,
"Group"
:
"Group"
,
"Meta Search"
:
"Meta Search"
,
"Access denied"
:
"Access denied"
,
"Access denied"
:
"Access denied"
,
"Invalid router"
:
"Invalid router"
,
"Invalid router"
:
"Invalid router"
,
"Jump after"
:
"Jump after {cd}s"
,
"Jump after"
:
"Jump after {cd}s"
,
...
@@ -133,7 +136,8 @@
...
@@ -133,7 +136,8 @@
"save"
:
"Save"
,
"save"
:
"Save"
,
"details"
:
"Details"
,
"details"
:
"Details"
,
"preview"
:
"Preview"
,
"preview"
:
"Preview"
,
"pack"
:
"Pack"
,
"preview2"
:
"Fast-Preview"
,
"publish"
:
"Publish"
,
"exit"
:
"Exit"
,
"exit"
:
"Exit"
,
"undo"
:
"Undo"
,
"undo"
:
"Undo"
,
"redo"
:
"Redo"
"redo"
:
"Redo"
...
...
src/locales/zh-CN.json
View file @
480c0363
...
@@ -17,6 +17,8 @@
...
@@ -17,6 +17,8 @@
"Delete all"
:
"删除全部"
,
"Delete all"
:
"删除全部"
,
"Import"
:
"导入"
,
"Import"
:
"导入"
,
"Export"
:
"导出"
,
"Export"
:
"导出"
,
"Importing project"
:
"项目导入中"
,
"Exporting project"
:
"项目导出中"
,
"Upload"
:
"上传"
,
"Upload"
:
"上传"
,
"Uploading"
:
"上传中"
,
"Uploading"
:
"上传中"
,
"Edit"
:
"编辑"
,
"Edit"
:
"编辑"
,
...
@@ -55,6 +57,7 @@
...
@@ -55,6 +57,7 @@
"Packing"
:
"打包"
,
"Packing"
:
"打包"
,
"Type"
:
"类型"
,
"Type"
:
"类型"
,
"Group"
:
"分组"
,
"Group"
:
"分组"
,
"Meta Search"
:
"过程元查找"
,
"Access denied"
:
"无权限"
,
"Access denied"
:
"无权限"
,
"Invalid router"
:
"无效的页面"
,
"Invalid router"
:
"无效的页面"
,
"Jump after"
:
"{cd}秒后跳转"
,
"Jump after"
:
"{cd}秒后跳转"
,
...
@@ -133,7 +136,8 @@
...
@@ -133,7 +136,8 @@
"save"
:
"保存"
,
"save"
:
"保存"
,
"details"
:
"详情"
,
"details"
:
"详情"
,
"preview"
:
"预览"
,
"preview"
:
"预览"
,
"pack"
:
"发布"
,
"preview2"
:
"快速预览"
,
"publish"
:
"发布"
,
"exit"
:
"退出"
,
"exit"
:
"退出"
,
"undo"
:
"撤销"
,
"undo"
:
"撤销"
,
"redo"
:
"重做"
"redo"
:
"重做"
...
...
src/router.js
View file @
480c0363
...
@@ -18,5 +18,10 @@ export default new Router({
...
@@ -18,5 +18,10 @@ export default new Router({
name
:
'editor'
,
name
:
'editor'
,
component
:
()
=>
import
(
'./views/Editor.vue'
)
component
:
()
=>
import
(
'./views/Editor.vue'
)
},
},
{
path
:
'/preview/:projectID'
,
name
:
'preview'
,
component
:
()
=>
import
(
'./views/Preview.vue'
)
},
]
]
})
})
src/store/modules/behavior.js
View file @
480c0363
...
@@ -186,7 +186,10 @@ export const behaviorStore = {
...
@@ -186,7 +186,10 @@ export const behaviorStore = {
addProcessMeta
(
commit
,
isInline
,
masterProcess
,
meta
);
addProcessMeta
(
commit
,
isInline
,
masterProcess
,
meta
);
return
meta
;
return
meta
;
}
},
searchMeta
({
state
},
{
keyword
})
{
searchMeta
(
state
.
data
.
processes
,
keyword
);
},
}
}
};
};
...
@@ -204,3 +207,11 @@ function addProcessMeta(commit, isInline, masterProcess, meta) {
...
@@ -204,3 +207,11 @@ function addProcessMeta(commit, isInline, masterProcess, meta) {
commit
(
'addProcessMeta'
,
meta
);
commit
(
'addProcessMeta'
,
meta
);
}
}
}
}
function
searchMeta
(
processes
,
keyword
,
path
)
{
for
(
let
process
of
processes
){
/*if(process.id === keyword || process.name === keyword){
}*/
}
}
src/store/modules/env.js
View file @
480c0363
...
@@ -11,7 +11,7 @@ export const envStore = {
...
@@ -11,7 +11,7 @@ export const envStore = {
state
:
{
state
:
{
initialized
:
false
,
initialized
:
false
,
name
:
'Zeroing Editor'
,
name
:
'Zeroing Editor'
,
version
:
'1.0.
1
'
,
version
:
'1.0.
2
'
,
templates
:
{
templates
:
{
builtin
:
[
'blank'
],
builtin
:
[
'blank'
],
custom
:
[],
custom
:
[],
...
@@ -19,6 +19,7 @@ export const envStore = {
...
@@ -19,6 +19,7 @@ export const envStore = {
processes
:
[],
processes
:
[],
scripts
:
[],
scripts
:
[],
customs
:
[],
customs
:
[],
projectCount
:
0
,
},
},
mutations
:
{
mutations
:
{
updateEnv
(
state
,
env
)
{
updateEnv
(
state
,
env
)
{
...
...
src/store/modules/project.js
View file @
480c0363
...
@@ -11,6 +11,7 @@ import { clonePureObj, saveAs } from "../../utils";
...
@@ -11,6 +11,7 @@ import { clonePureObj, saveAs } from "../../utils";
import
{
template
}
from
"../../template"
;
import
{
template
}
from
"../../template"
;
import
{
importView
,
uploadFile
}
from
"../../api/project"
;
import
{
importView
,
uploadFile
}
from
"../../api/project"
;
import
events
from
"@/global-events"
;
import
events
from
"@/global-events"
;
import
{
packImages
}
from
"../../utils/sheet-pack"
;
const
defaultOptions
=
{
const
defaultOptions
=
{
pageTitle
:
'no title'
,
pageTitle
:
'no title'
,
...
@@ -313,6 +314,13 @@ export const projectStore = {
...
@@ -313,6 +314,13 @@ export const projectStore = {
uuid
:
generateUUID
(),
uuid
:
generateUUID
(),
})
})
},
},
replaceAsset
(
state
,
{
uuid
,
url
})
{
for
(
let
asset
of
state
.
data
.
assets
){
if
(
asset
.
uuid
===
uuid
){
asset
.
url
=
url
;
}
}
},
deleteAsset
(
state
,
uuid
)
{
deleteAsset
(
state
,
uuid
)
{
const
{
assets
}
=
state
.
data
;
const
{
assets
}
=
state
.
data
;
for
(
let
i
=
0
,
li
=
assets
.
length
;
i
<
li
;
i
++
)
{
for
(
let
i
=
0
,
li
=
assets
.
length
;
i
<
li
;
i
++
)
{
...
@@ -429,7 +437,7 @@ export const projectStore = {
...
@@ -429,7 +437,7 @@ export const projectStore = {
/**
/**
* 返回Array格式的views
* 返回Array格式的views
*/
*/
views
:
state
=>
{
views
(
state
)
{
// 如果有选中的节点,则展示对应的视图组
// 如果有选中的节点,则展示对应的视图组
// 否则展示第一个视图组
// 否则展示第一个视图组
let
_view
=
[];
let
_view
=
[];
...
@@ -440,6 +448,9 @@ export const projectStore = {
...
@@ -440,6 +448,9 @@ export const projectStore = {
}
}
return
_view
;
return
_view
;
},
assets
(
state
)
{
return
state
.
data
.
assets
;
}
}
},
},
actions
:
{
actions
:
{
...
@@ -558,11 +569,10 @@ export const projectStore = {
...
@@ -558,11 +569,10 @@ export const projectStore = {
modifyActiveView
({
commit
},
view
)
{
modifyActiveView
({
commit
},
view
)
{
commit
(
'modifyActiveView'
,
view
)
commit
(
'modifyActiveView'
,
view
)
},
},
/**
/**
* 新增节点脚本
* 新增节点脚本
* @param {*} param0
* @param {*} param0
* @param {*}
data
* @param {*}
script
*/
*/
addNodeScript
({
commit
,
state
},
script
)
{
addNodeScript
({
commit
,
state
},
script
)
{
let
_scripts
=
_
.
cloneDeep
(
state
.
activeComponent
.
scripts
||
[]);
let
_scripts
=
_
.
cloneDeep
(
state
.
activeComponent
.
scripts
||
[]);
...
@@ -596,38 +606,91 @@ export const projectStore = {
...
@@ -596,38 +606,91 @@ export const projectStore = {
saveAs
(
content
,
`view-
${
view
.
name
}
.zrv`
);
saveAs
(
content
,
`view-
${
view
.
name
}
.zrv`
);
});
});
},
},
async
uploadFiles
({
commit
},
files
)
{
async
uploadFiles
({
commit
},
files
)
{
const
{
failedList
,
result
}
=
await
uploadFiles
(
files
);
for
(
let
item
of
result
)
{
const
{
url
,
__originFile
}
=
item
;
commit
(
'addAsset'
,
{
url
,
file
:
__originFile
});
}
return
failedList
;
},
async
replaceAsset
({
commit
},
{
uuid
,
file
})
{
const
{
failedList
,
result
}
=
await
uploadFiles
([
file
]);
commit
(
'replaceAsset'
,
{
uuid
,
url
:
result
[
0
].
url
,});
return
failedList
;
},
async
packProject
({
state
},
debug
)
{
let
packedAssets
;
if
(
!
debug
){
packedAssets
=
await
packAssets
(
state
.
data
.
assets
);
}
const
result
=
await
projectApi
.
pack
(
state
.
id
,
debug
,
packedAssets
);
console
.
log
(
result
);
return
result
;
},
savePreview
({
state
,
rootState
,
getters
})
{
const
{
project
}
=
getters
;
const
{
processes
,
scripts
,
customs
}
=
rootState
.
env
;
const
data
=
{
processes
,
scripts
,
customs
,
data
:
state
.
data
,
};
localStorage
.
setItem
(
'preview-project-'
+
project
.
id
,
JSON
.
stringify
(
data
));
localStorage
.
setItem
(
'preview-ts'
,
Date
.
now
().
toString
());
}
},
};
async
function
uploadFiles
(
files
)
{
const
failedList
=
[];
const
failedList
=
[];
let
ps
=
[];
let
ps
=
[];
for
(
let
file
of
files
)
{
for
(
let
file
of
files
)
{
events
.
$emit
(
'upload-indicator'
,
true
);
events
.
$emit
(
'upload-indicator'
,
true
);
ps
.
push
(
ps
.
push
(
uploadFile
(
file
).
catch
(
e
=>
{
uploadFile
(
file
).
catch
(
e
=>
{
failedList
.
push
(
file
);
}).
finally
(()
=>
{
}).
finally
(()
=>
{
events
.
$emit
(
'upload-indicator'
,
false
);
events
.
$emit
(
'upload-indicator'
,
false
);
})
})
);
);
}
}
const
result
=
await
Promise
.
all
(
ps
);
const
result
=
await
Promise
.
all
(
ps
);
for
(
let
item
of
result
)
{
const
{
url
,
__originFile
}
=
item
;
return
{
commit
(
'addAsset'
,
{
url
,
file
:
__originFile
});
failedList
,
}
result
,
/*for (let file of files) {
};
try {
}
const {url} = await uploadFile(file);
commit('addAsset', {url, file});
async
function
packAssets
(
assets
)
{
}catch (e) {
let
failedList
=
[];
failedList.push(file);
let
newAssets
=
assets
.
concat
();
await
packImages
(
newAssets
);
for
(
let
asset
of
newAssets
)
{
if
(
asset
.
file
)
{
const
{
url
}
=
await
uploadFile
(
asset
.
file
,
true
).
catch
(
e
=>
{
failedList
.
push
(
asset
);
});
let
sheetConfig
=
{
file
:
url
,
type
:
'sheet'
,
frames
:
asset
.
frames
,
};
let
sheetConfigFile
=
new
File
([
JSON
.
stringify
(
sheetConfig
)],
'sheet.json'
,
{
type
:
'plain/text'
});
const
{
url
:
sheetConfigUrl
}
=
await
uploadFile
(
sheetConfigFile
).
catch
(
e
=>
{
failedList
.
push
(
asset
);
});
asset
.
url
=
sheetConfigUrl
;
asset
.
uuid
=
generateUUID
();
delete
asset
.
file
;
delete
asset
.
frames
;
}
}
events.$emit('upload-indicator', false);
}*/
return
failedList
;
},
async
packProject
({
state
},
debug
)
{
const
result
=
await
projectApi
.
pack
(
state
.
id
,
debug
);
console
.
log
(
result
);
return
result
;
}
}
},
console
.
log
(
newAssets
);
};
return
newAssets
;
}
src/store/modules/projects.js
View file @
480c0363
...
@@ -25,10 +25,13 @@ export const projectsStore = {
...
@@ -25,10 +25,13 @@ export const projectsStore = {
},
},
},
},
actions
:
{
actions
:
{
async
updateProjects
({
commit
})
{
async
fetchProjects
({
commit
},
{
currentPage
,
pageSize
})
{
const
projects
=
await
projectApi
.
fetchAll
();
const
projects
=
await
projectApi
.
fetchAll
(
currentPage
,
pageSize
);
commit
(
'updateProjects'
,
projects
);
commit
(
'updateProjects'
,
projects
);
},
},
async
fetchProject
({
commit
},
projectId
)
{
return
await
projectApi
.
fetchOne
(
projectId
);
},
async
createProject
({
commit
},
data
)
{
async
createProject
({
commit
},
data
)
{
const
project
=
await
projectApi
.
createOne
(
data
);
const
project
=
await
projectApi
.
createOne
(
data
);
commit
(
'addProject'
,
project
);
commit
(
'addProject'
,
project
);
...
...
src/template.js
View file @
480c0363
...
@@ -34,10 +34,8 @@ content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, u
...
@@ -34,10 +34,8 @@ content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, u
<body>
<body>
<div id="$CONTAINER_ID$" style="line-height:0;font-size:0"></div>
<div id="$CONTAINER_ID$" style="line-height:0;font-size:0"></div>
<script src="
${
process
.
env
.
NODE_ENV
===
'development'
?
'http://10.10.94.134:4002/dist/index.js'
:
'http://yun.duiba.com.cn/editor/zeroing/libs/engine.a913456caee2ee40c20108a1c4571f61479e54a1.js'
}
"></script>
<script src="
${
process
.
env
.
NODE_ENV
===
'development'
?
'http://10.10.94.134:4002/dist/index.js'
:
'http://yun.duiba.com.cn/editor/zeroing/libs/engine.d20665eae76962ad21c153fe7a719130b08e292c.js.js'
}
"></script>
<script src="$PROCESSES_URL$"></script>
$SCRIPTS$
<script src="$SCRIPTS_URL$"></script>
<script src="$CUSTOMS_URL$"></script>
<script>
<script>
engine.launch('//yun.duiba.com.cn/aurora/$VERSION$-data.json');
engine.launch('//yun.duiba.com.cn/aurora/$VERSION$-data.json');
</script>
</script>
...
...
src/themes/light/assets.scss
View file @
480c0363
...
@@ -67,11 +67,11 @@
...
@@ -67,11 +67,11 @@
&
:hover
{
&
:hover
{
&
>
.icon
>
.operate-bar
{
&
>
.icon
>
.operate-bar
{
display
:
block
;
visibility
:
visible
;
}
}
&
>
.name
>
.full-name
{
&
>
.name
>
.full-name
{
display
:
block
;
visibility
:
visible
;
}
}
}
}
...
@@ -93,14 +93,18 @@
...
@@ -93,14 +93,18 @@
}
}
.operate-bar
{
.operate-bar
{
display
:
none
;
visibility
:
hidden
;
position
:
absolute
;
position
:
absolute
;
right
:
1px
;
right
:
1px
;
bottom
:
1px
;
bottom
:
1px
;
display
:
flex
;
.el-button
+
.el-button
{
margin-left
:
2px
;
}
.el-button
{
.el-button
{
padding
:
2px
;
padding
:
2px
;
margin-left
:
2px
;
}
}
}
}
}
}
...
@@ -121,7 +125,7 @@
...
@@ -121,7 +125,7 @@
}
}
.full-name
{
.full-name
{
display
:
none
;
visibility
:
hidden
;
position
:
absolute
;
position
:
absolute
;
top
:
0
;
top
:
0
;
left
:
0
;
left
:
0
;
...
...
src/themes/light/behavior.scss
View file @
480c0363
...
@@ -64,12 +64,26 @@ $dock-pin-width: 9px;
...
@@ -64,12 +64,26 @@ $dock-pin-width: 9px;
display
:
flex
;
display
:
flex
;
flex-direction
:
column
;
flex-direction
:
column
;
.el-button
{
padding
:
3px
;
margin-top
:
2px
;
margin-right
:
2px
;
}
.top-bar
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
flex-start
;
.edit-path
{
.edit-path
{
flex
:
1
;
padding
:
5px
;
padding
:
5px
;
height
:
14px
;
height
:
14px
;
border-bottom
:
1px
solid
$--border-color-light
;
border-bottom
:
1px
solid
$--border-color-light
;
}
}
}
.operate-bar
{
.operate-bar
{
padding
:
3px
;
padding
:
3px
;
...
...
src/themes/light/home.scss
View file @
480c0363
...
@@ -15,6 +15,7 @@
...
@@ -15,6 +15,7 @@
.editor-name
{
.editor-name
{
font-size
:
50px
;
font-size
:
50px
;
color
:
$--color-primary
;
color
:
$--color-primary
;
margin
:
10px
0
;
}
}
.editor-version
{
.editor-version
{
...
@@ -25,6 +26,7 @@
...
@@ -25,6 +26,7 @@
.project-list
{
.project-list
{
flex
:
1
;
flex
:
1
;
margin-bottom
:
10px
;
margin-bottom
:
10px
;
height
:
0
;
}
}
.project-info
{
.project-info
{
...
@@ -43,4 +45,9 @@
...
@@ -43,4 +45,9 @@
.project-detail
{
.project-detail
{
}
}
.bottom-bar
{
display
:
flex
;
justify-content
:
space-between
;
}
}
}
\ No newline at end of file
src/themes/light/playground.scss
View file @
480c0363
...
@@ -17,6 +17,10 @@
...
@@ -17,6 +17,10 @@
&
:
:-
webkit-scrollbar
{
&
:
:-
webkit-scrollbar
{
display
:
none
;
display
:
none
;
}
}
.active
{
border
:
2px
dashed
rgb
(
20
,
100
,
206
);
}
}
}
// .zero-playground-draw-panel{
// .zero-playground-draw-panel{
// min-height: 1200px;
// min-height: 1200px;
...
@@ -60,6 +64,3 @@
...
@@ -60,6 +64,3 @@
cursor
:
default
;
cursor
:
default
;
user-select
:
none
;
user-select
:
none
;
}
}
.active
{
border
:
2px
dashed
rgb
(
20
,
100
,
206
);
}
src/utils/MaxRectsBinPack.js
0 → 100755
View file @
480c0363
/**
* Based on the Public Domain MaxRectanglesBinPack.cpp source by Jukka Jylänki
* https://github.com/juj/RectangleBinPack/
*
* Based on C# port by Sven Magnus
* http://unifycommunity.com/wiki/index.php?title=MaxRectanglesBinPack
*
* Based on ActionScript3 by DUZENGQIANG
* http://www.duzengqiang.com/blog/post/971.html
*
* Ported to javascript by 06wj
* https://github.com/06wj/MaxRectsBinPack
*/
/**
* Rect
* @param {Number} x 矩形坐标x
* @param {Number} y 矩形坐标y
* @param {Number} width 矩形宽
* @param {Number} height 矩形高
*/
function
Rect
(
x
,
y
,
width
,
height
)
{
this
.
x
=
x
||
0
;
this
.
y
=
y
||
0
;
this
.
width
=
width
||
0
;
this
.
height
=
height
||
0
;
}
Rect
.
prototype
=
{
constructor
:
Rect
,
/**
* clone 复制
* @return {Rect}
*/
clone
:
function
()
{
return
new
Rect
(
this
.
x
,
this
.
y
,
this
.
width
,
this
.
height
);
}
};
Rect
.
isContainedIn
=
function
(
a
,
b
)
{
return
a
.
x
>=
b
.
x
&&
a
.
y
>=
b
.
y
&&
a
.
x
+
a
.
width
<=
b
.
x
+
b
.
width
&&
a
.
y
+
a
.
height
<=
b
.
y
+
b
.
height
;
};
var
BestShortSideFit
=
0
;
///< -BSSF: Positions the Rectangle against the short side of a free Rectangle into which it fits the best.
var
BestLongSideFit
=
1
;
///< -BLSF: Positions the Rectangle against the long side of a free Rectangle into which it fits the best.
var
BestAreaFit
=
2
;
///< -BAF: Positions the Rectangle into the smallest free Rectangle into which it fits.
var
BottomLeftRule
=
3
;
///< -BL: Does the Tetris placement.
var
ContactPointRule
=
4
;
///< -CP: Choosest the placement where the Rectangle touches other Rectangles as much as possible.
/**
* MaxRectanglesBinPack
* @param {Number} width 容器宽度
* @param {Number} height 容器高度
* @param {Boolean} allowRotate 是否允许旋转
*/
export
default
function
MaxRectsBinPack
(
width
,
height
,
allowRotate
)
{
this
.
binWidth
=
0
;
this
.
binHeight
=
0
;
this
.
allowRotate
=
false
;
this
.
usedRectangles
=
[];
this
.
freeRectangles
=
[];
this
.
init
(
width
,
height
,
allowRotate
);
}
MaxRectsBinPack
.
prototype
=
{
constructor
:
MaxRectsBinPack
,
/**
* 初始化
* @param {Number} width 容器宽度
* @param {Number} height 容器高度
* @param {Boolean} allowRotate 是否允许旋转
*/
init
:
function
(
width
,
height
,
allowRotate
)
{
this
.
binWidth
=
width
;
this
.
binHeight
=
height
;
this
.
allowRotate
=
allowRotate
||
false
;
this
.
usedRectangles
.
length
=
0
;
this
.
freeRectangles
.
length
=
0
;
this
.
freeRectangles
.
push
(
new
Rect
(
0
,
0
,
width
,
height
));
},
/**
* insert a new rect
* @param {Number} width 矩形宽
* @param {Number} height 矩形高
* @param {Number} method 分配方法 0~4
* @return {Rect}
*/
insert
:
function
(
width
,
height
,
method
)
{
var
newNode
=
new
Rect
();
var
score1
=
{
value
:
0
};
var
score2
=
{
value
:
0
};
method
=
method
||
0
;
switch
(
method
)
{
case
BestShortSideFit
:
newNode
=
this
.
_findPositionForNewNodeBestShortSideFit
(
width
,
height
,
score1
,
score2
);
break
;
case
BottomLeftRule
:
newNode
=
this
.
_findPositionForNewNodeBottomLeft
(
width
,
height
,
score1
,
score2
);
break
;
case
ContactPointRule
:
newNode
=
this
.
_findPositionForNewNodeContactPoint
(
width
,
height
,
score1
);
break
;
case
BestLongSideFit
:
newNode
=
this
.
_findPositionForNewNodeBestLongSideFit
(
width
,
height
,
score2
,
score1
);
break
;
case
BestAreaFit
:
newNode
=
this
.
_findPositionForNewNodeBestAreaFit
(
width
,
height
,
score1
,
score2
);
break
;
}
if
(
newNode
.
height
===
0
)
{
return
newNode
;
}
this
.
_placeRectangle
(
newNode
);
return
newNode
;
},
/**
* 插入一组矩形
* @param {Array} rectangles 矩形数组
* @param {Number} method 分配方法 0~4
* @return {Array} 成功插入的数组
*/
insertRects
:
function
(
rectangles
,
method
)
{
var
res
=
[];
while
(
rectangles
.
length
>
0
)
{
var
bestScore1
=
Infinity
;
var
bestScore2
=
Infinity
;
var
bestRectangleIndex
=
-
1
;
var
bestNode
=
new
Rect
();
for
(
var
i
=
0
;
i
<
rectangles
.
length
;
i
++
)
{
var
score1
=
{
value
:
0
};
var
score2
=
{
value
:
0
};
var
newNode
=
this
.
_scoreRectangle
(
rectangles
[
i
].
width
,
rectangles
[
i
].
height
,
method
,
score1
,
score2
);
if
(
score1
.
value
<
bestScore1
||
(
score1
.
value
==
bestScore1
&&
score2
.
value
<
bestScore2
))
{
bestScore1
=
score1
.
value
;
bestScore2
=
score2
.
value
;
bestNode
=
newNode
;
bestRectangleIndex
=
i
;
}
}
if
(
bestRectangleIndex
==
-
1
)
{
return
res
;
}
this
.
_placeRectangle
(
bestNode
);
var
rect
=
rectangles
.
splice
(
bestRectangleIndex
,
1
)[
0
];
rect
.
x
=
bestNode
.
x
;
rect
.
y
=
bestNode
.
y
;
res
.
push
(
rect
);
}
return
res
;
},
_placeRectangle
:
function
(
node
)
{
var
numRectanglesToProcess
=
this
.
freeRectangles
.
length
;
for
(
var
i
=
0
;
i
<
numRectanglesToProcess
;
i
++
)
{
if
(
this
.
_splitFreeNode
(
this
.
freeRectangles
[
i
],
node
))
{
this
.
freeRectangles
.
splice
(
i
,
1
);
i
--
;
numRectanglesToProcess
--
;
}
}
this
.
_pruneFreeList
();
this
.
usedRectangles
.
push
(
node
);
},
_scoreRectangle
:
function
(
width
,
height
,
method
,
score1
,
score2
)
{
var
newNode
=
new
Rect
();
score1
.
value
=
Infinity
;
score2
.
value
=
Infinity
;
switch
(
method
)
{
case
BestShortSideFit
:
newNode
=
this
.
_findPositionForNewNodeBestShortSideFit
(
width
,
height
,
score1
,
score2
);
break
;
case
BottomLeftRule
:
newNode
=
this
.
_findPositionForNewNodeBottomLeft
(
width
,
height
,
score1
,
score2
);
break
;
case
ContactPointRule
:
newNode
=
this
.
_findPositionForNewNodeContactPoint
(
width
,
height
,
score1
);
// todo: reverse
score1
=
-
score1
;
// Reverse since we are minimizing, but for contact point score bigger is better.
break
;
case
BestLongSideFit
:
newNode
=
this
.
_findPositionForNewNodeBestLongSideFit
(
width
,
height
,
score2
,
score1
);
break
;
case
BestAreaFit
:
newNode
=
this
.
_findPositionForNewNodeBestAreaFit
(
width
,
height
,
score1
,
score2
);
break
;
}
// Cannot fit the current Rectangle.
if
(
newNode
.
height
===
0
)
{
score1
.
value
=
Infinity
;
score2
.
value
=
Infinity
;
}
return
newNode
;
},
_occupancy
:
function
()
{
var
usedRectangles
=
this
.
usedRectangles
;
var
usedSurfaceArea
=
0
;
for
(
var
i
=
0
;
i
<
usedRectangles
.
length
;
i
++
)
{
usedSurfaceArea
+=
usedRectangles
[
i
].
width
*
usedRectangles
[
i
].
height
;
}
return
usedSurfaceArea
/
(
this
.
binWidth
*
this
.
binHeight
);
},
_findPositionForNewNodeBottomLeft
:
function
(
width
,
height
,
bestY
,
bestX
)
{
var
freeRectangles
=
this
.
freeRectangles
;
var
bestNode
=
new
Rect
();
//memset(bestNode, 0, sizeof(Rectangle));
bestY
.
value
=
Infinity
;
var
rect
;
var
topSideY
;
for
(
var
i
=
0
;
i
<
freeRectangles
.
length
;
i
++
)
{
rect
=
freeRectangles
[
i
];
// Try to place the Rectangle in upright (non-flipped) orientation.
if
(
rect
.
width
>=
width
&&
rect
.
height
>=
height
)
{
topSideY
=
rect
.
y
+
height
;
if
(
topSideY
<
bestY
.
value
||
(
topSideY
==
bestY
.
value
&&
rect
.
x
<
bestX
.
value
))
{
bestNode
.
x
=
rect
.
x
;
bestNode
.
y
=
rect
.
y
;
bestNode
.
width
=
width
;
bestNode
.
height
=
height
;
bestY
.
value
=
topSideY
;
bestX
.
value
=
rect
.
x
;
}
}
if
(
this
.
allowRotate
&&
rect
.
width
>=
height
&&
rect
.
height
>=
width
)
{
topSideY
=
rect
.
y
+
width
;
if
(
topSideY
<
bestY
.
value
||
(
topSideY
==
bestY
.
value
&&
rect
.
x
<
bestX
.
value
))
{
bestNode
.
x
=
rect
.
x
;
bestNode
.
y
=
rect
.
y
;
bestNode
.
width
=
height
;
bestNode
.
height
=
width
;
bestY
.
value
=
topSideY
;
bestX
.
value
=
rect
.
x
;
}
}
}
return
bestNode
;
},
_findPositionForNewNodeBestShortSideFit
:
function
(
width
,
height
,
bestShortSideFit
,
bestLongSideFit
)
{
var
freeRectangles
=
this
.
freeRectangles
;
var
bestNode
=
new
Rect
();
//memset(&bestNode, 0, sizeof(Rectangle));
bestShortSideFit
.
value
=
Infinity
;
var
rect
;
var
leftoverHoriz
;
var
leftoverVert
;
var
shortSideFit
;
var
longSideFit
;
for
(
var
i
=
0
;
i
<
freeRectangles
.
length
;
i
++
)
{
rect
=
freeRectangles
[
i
];
// Try to place the Rectangle in upright (non-flipped) orientation.
if
(
rect
.
width
>=
width
&&
rect
.
height
>=
height
)
{
leftoverHoriz
=
Math
.
abs
(
rect
.
width
-
width
);
leftoverVert
=
Math
.
abs
(
rect
.
height
-
height
);
shortSideFit
=
Math
.
min
(
leftoverHoriz
,
leftoverVert
);
longSideFit
=
Math
.
max
(
leftoverHoriz
,
leftoverVert
);
if
(
shortSideFit
<
bestShortSideFit
.
value
||
(
shortSideFit
==
bestShortSideFit
.
value
&&
longSideFit
<
bestLongSideFit
.
value
))
{
bestNode
.
x
=
rect
.
x
;
bestNode
.
y
=
rect
.
y
;
bestNode
.
width
=
width
;
bestNode
.
height
=
height
;
bestShortSideFit
.
value
=
shortSideFit
;
bestLongSideFit
.
value
=
longSideFit
;
}
}
var
flippedLeftoverHoriz
;
var
flippedLeftoverVert
;
var
flippedShortSideFit
;
var
flippedLongSideFit
;
if
(
this
.
allowRotate
&&
rect
.
width
>=
height
&&
rect
.
height
>=
width
)
{
flippedLeftoverHoriz
=
Math
.
abs
(
rect
.
width
-
height
);
flippedLeftoverVert
=
Math
.
abs
(
rect
.
height
-
width
);
flippedShortSideFit
=
Math
.
min
(
flippedLeftoverHoriz
,
flippedLeftoverVert
);
flippedLongSideFit
=
Math
.
max
(
flippedLeftoverHoriz
,
flippedLeftoverVert
);
if
(
flippedShortSideFit
<
bestShortSideFit
.
value
||
(
flippedShortSideFit
==
bestShortSideFit
.
value
&&
flippedLongSideFit
<
bestLongSideFit
.
value
))
{
bestNode
.
x
=
rect
.
x
;
bestNode
.
y
=
rect
.
y
;
bestNode
.
width
=
height
;
bestNode
.
height
=
width
;
bestShortSideFit
.
value
=
flippedShortSideFit
;
bestLongSideFit
.
value
=
flippedLongSideFit
;
}
}
}
return
bestNode
;
},
_findPositionForNewNodeBestLongSideFit
:
function
(
width
,
height
,
bestShortSideFit
,
bestLongSideFit
)
{
var
freeRectangles
=
this
.
freeRectangles
;
var
bestNode
=
new
Rect
();
//memset(&bestNode, 0, sizeof(Rectangle));
bestLongSideFit
.
value
=
Infinity
;
var
rect
;
var
leftoverHoriz
;
var
leftoverVert
;
var
shortSideFit
;
var
longSideFit
;
for
(
var
i
=
0
;
i
<
freeRectangles
.
length
;
i
++
)
{
rect
=
freeRectangles
[
i
];
// Try to place the Rectangle in upright (non-flipped) orientation.
if
(
rect
.
width
>=
width
&&
rect
.
height
>=
height
)
{
leftoverHoriz
=
Math
.
abs
(
rect
.
width
-
width
);
leftoverVert
=
Math
.
abs
(
rect
.
height
-
height
);
shortSideFit
=
Math
.
min
(
leftoverHoriz
,
leftoverVert
);
longSideFit
=
Math
.
max
(
leftoverHoriz
,
leftoverVert
);
if
(
longSideFit
<
bestLongSideFit
.
value
||
(
longSideFit
==
bestLongSideFit
.
value
&&
shortSideFit
<
bestShortSideFit
.
value
))
{
bestNode
.
x
=
rect
.
x
;
bestNode
.
y
=
rect
.
y
;
bestNode
.
width
=
width
;
bestNode
.
height
=
height
;
bestShortSideFit
.
value
=
shortSideFit
;
bestLongSideFit
.
value
=
longSideFit
;
}
}
if
(
this
.
allowRotate
&&
rect
.
width
>=
height
&&
rect
.
height
>=
width
)
{
leftoverHoriz
=
Math
.
abs
(
rect
.
width
-
height
);
leftoverVert
=
Math
.
abs
(
rect
.
height
-
width
);
shortSideFit
=
Math
.
min
(
leftoverHoriz
,
leftoverVert
);
longSideFit
=
Math
.
max
(
leftoverHoriz
,
leftoverVert
);
if
(
longSideFit
<
bestLongSideFit
.
value
||
(
longSideFit
==
bestLongSideFit
.
value
&&
shortSideFit
<
bestShortSideFit
.
value
))
{
bestNode
.
x
=
rect
.
x
;
bestNode
.
y
=
rect
.
y
;
bestNode
.
width
=
height
;
bestNode
.
height
=
width
;
bestShortSideFit
.
value
=
shortSideFit
;
bestLongSideFit
.
value
=
longSideFit
;
}
}
}
return
bestNode
;
},
_findPositionForNewNodeBestAreaFit
:
function
(
width
,
height
,
bestAreaFit
,
bestShortSideFit
)
{
var
freeRectangles
=
this
.
freeRectangles
;
var
bestNode
=
new
Rect
();
//memset(&bestNode, 0, sizeof(Rectangle));
bestAreaFit
.
value
=
Infinity
;
var
rect
;
var
leftoverHoriz
;
var
leftoverVert
;
var
shortSideFit
;
var
areaFit
;
for
(
var
i
=
0
;
i
<
freeRectangles
.
length
;
i
++
)
{
rect
=
freeRectangles
[
i
];
areaFit
=
rect
.
width
*
rect
.
height
-
width
*
height
;
// Try to place the Rectangle in upright (non-flipped) orientation.
if
(
rect
.
width
>=
width
&&
rect
.
height
>=
height
)
{
leftoverHoriz
=
Math
.
abs
(
rect
.
width
-
width
);
leftoverVert
=
Math
.
abs
(
rect
.
height
-
height
);
shortSideFit
=
Math
.
min
(
leftoverHoriz
,
leftoverVert
);
if
(
areaFit
<
bestAreaFit
.
value
||
(
areaFit
==
bestAreaFit
.
value
&&
shortSideFit
<
bestShortSideFit
.
value
))
{
bestNode
.
x
=
rect
.
x
;
bestNode
.
y
=
rect
.
y
;
bestNode
.
width
=
width
;
bestNode
.
height
=
height
;
bestShortSideFit
.
value
=
shortSideFit
;
bestAreaFit
=
areaFit
;
}
}
if
(
this
.
allowRotate
&&
rect
.
width
>=
height
&&
rect
.
height
>=
width
)
{
leftoverHoriz
=
Math
.
abs
(
rect
.
width
-
height
);
leftoverVert
=
Math
.
abs
(
rect
.
height
-
width
);
shortSideFit
=
Math
.
min
(
leftoverHoriz
,
leftoverVert
);
if
(
areaFit
<
bestAreaFit
.
value
||
(
areaFit
==
bestAreaFit
.
value
&&
shortSideFit
<
bestShortSideFit
.
value
))
{
bestNode
.
x
=
rect
.
x
;
bestNode
.
y
=
rect
.
y
;
bestNode
.
width
=
height
;
bestNode
.
height
=
width
;
bestShortSideFit
.
value
=
shortSideFit
;
bestAreaFit
.
value
=
areaFit
;
}
}
}
return
bestNode
;
},
/// Returns 0 if the two intervals i1 and i2 are disjoint, or the length of their overlap otherwise.
_commonIntervalLength
:
function
(
i1start
,
i1end
,
i2start
,
i2end
)
{
if
(
i1end
<
i2start
||
i2end
<
i1start
)
{
return
0
;
}
return
Math
.
min
(
i1end
,
i2end
)
-
Math
.
max
(
i1start
,
i2start
);
},
_contactPointScoreNode
:
function
(
x
,
y
,
width
,
height
)
{
var
usedRectangles
=
this
.
usedRectangles
;
var
score
=
0
;
if
(
x
==
0
||
x
+
width
===
this
.
binWidth
)
score
+=
height
;
if
(
y
==
0
||
y
+
height
===
this
.
binHeight
)
score
+=
width
;
var
rect
;
for
(
var
i
=
0
;
i
<
usedRectangles
.
length
;
i
++
)
{
rect
=
usedRectangles
[
i
];
if
(
rect
.
x
==
x
+
width
||
rect
.
x
+
rect
.
width
==
x
)
score
+=
this
.
_commonIntervalLength
(
rect
.
y
,
rect
.
y
+
rect
.
height
,
y
,
y
+
height
);
if
(
rect
.
y
==
y
+
height
||
rect
.
y
+
rect
.
height
==
y
)
score
+=
this
.
_commonIntervalLength
(
rect
.
x
,
rect
.
x
+
rect
.
width
,
x
,
x
+
width
);
}
return
score
;
},
_findPositionForNewNodeContactPoint
:
function
(
width
,
height
,
bestContactScore
)
{
var
freeRectangles
=
this
.
freeRectangles
;
var
bestNode
=
new
Rect
();
//memset(&bestNode, 0, sizeof(Rectangle));
bestContactScore
.
value
=
-
1
;
var
rect
;
var
score
;
for
(
var
i
=
0
;
i
<
freeRectangles
.
length
;
i
++
)
{
rect
=
freeRectangles
[
i
];
// Try to place the Rectangle in upright (non-flipped) orientation.
if
(
rect
.
width
>=
width
&&
rect
.
height
>=
height
)
{
score
=
this
.
_contactPointScoreNode
(
rect
.
x
,
rect
.
y
,
width
,
height
);
if
(
score
>
bestContactScore
.
value
)
{
bestNode
.
x
=
rect
.
x
;
bestNode
.
y
=
rect
.
y
;
bestNode
.
width
=
width
;
bestNode
.
height
=
height
;
bestContactScore
=
score
;
}
}
if
(
this
.
allowRotate
&&
rect
.
width
>=
height
&&
rect
.
height
>=
width
)
{
score
=
this
.
_contactPointScoreNode
(
rect
.
x
,
rect
.
y
,
height
,
width
);
if
(
score
>
bestContactScore
.
value
)
{
bestNode
.
x
=
rect
.
x
;
bestNode
.
y
=
rect
.
y
;
bestNode
.
width
=
height
;
bestNode
.
height
=
width
;
bestContactScore
.
value
=
score
;
}
}
}
return
bestNode
;
},
_splitFreeNode
:
function
(
freeNode
,
usedNode
)
{
var
freeRectangles
=
this
.
freeRectangles
;
// Test with SAT if the Rectangles even intersect.
if
(
usedNode
.
x
>=
freeNode
.
x
+
freeNode
.
width
||
usedNode
.
x
+
usedNode
.
width
<=
freeNode
.
x
||
usedNode
.
y
>=
freeNode
.
y
+
freeNode
.
height
||
usedNode
.
y
+
usedNode
.
height
<=
freeNode
.
y
)
return
false
;
var
newNode
;
if
(
usedNode
.
x
<
freeNode
.
x
+
freeNode
.
width
&&
usedNode
.
x
+
usedNode
.
width
>
freeNode
.
x
)
{
// New node at the top side of the used node.
if
(
usedNode
.
y
>
freeNode
.
y
&&
usedNode
.
y
<
freeNode
.
y
+
freeNode
.
height
)
{
newNode
=
freeNode
.
clone
();
newNode
.
height
=
usedNode
.
y
-
newNode
.
y
;
freeRectangles
.
push
(
newNode
);
}
// New node at the bottom side of the used node.
if
(
usedNode
.
y
+
usedNode
.
height
<
freeNode
.
y
+
freeNode
.
height
)
{
newNode
=
freeNode
.
clone
();
newNode
.
y
=
usedNode
.
y
+
usedNode
.
height
;
newNode
.
height
=
freeNode
.
y
+
freeNode
.
height
-
(
usedNode
.
y
+
usedNode
.
height
);
freeRectangles
.
push
(
newNode
);
}
}
if
(
usedNode
.
y
<
freeNode
.
y
+
freeNode
.
height
&&
usedNode
.
y
+
usedNode
.
height
>
freeNode
.
y
)
{
// New node at the left side of the used node.
if
(
usedNode
.
x
>
freeNode
.
x
&&
usedNode
.
x
<
freeNode
.
x
+
freeNode
.
width
)
{
newNode
=
freeNode
.
clone
();
newNode
.
width
=
usedNode
.
x
-
newNode
.
x
;
freeRectangles
.
push
(
newNode
);
}
// New node at the right side of the used node.
if
(
usedNode
.
x
+
usedNode
.
width
<
freeNode
.
x
+
freeNode
.
width
)
{
newNode
=
freeNode
.
clone
();
newNode
.
x
=
usedNode
.
x
+
usedNode
.
width
;
newNode
.
width
=
freeNode
.
x
+
freeNode
.
width
-
(
usedNode
.
x
+
usedNode
.
width
);
freeRectangles
.
push
(
newNode
);
}
}
return
true
;
},
_pruneFreeList
:
function
()
{
var
freeRectangles
=
this
.
freeRectangles
;
for
(
var
i
=
0
;
i
<
freeRectangles
.
length
;
i
++
)
for
(
var
j
=
i
+
1
;
j
<
freeRectangles
.
length
;
j
++
)
{
if
(
Rect
.
isContainedIn
(
freeRectangles
[
i
],
freeRectangles
[
j
]))
{
freeRectangles
.
splice
(
i
,
1
);
break
;
}
if
(
Rect
.
isContainedIn
(
freeRectangles
[
j
],
freeRectangles
[
i
]))
{
freeRectangles
.
splice
(
j
,
1
);
}
}
}
};
src/utils/index.js
View file @
480c0363
...
@@ -47,26 +47,6 @@ export function strEllipsis(str, maxLength = 0, rightOffset = 0) {
...
@@ -47,26 +47,6 @@ export function strEllipsis(str, maxLength = 0, rightOffset = 0) {
return
result
;
return
result
;
}
}
export
function
saveAs
(
blob
,
fileName
)
{
if
(
'msSaveOrOpenBlob'
in
navigator
)
{
navigator
.
msSaveOrOpenBlob
(
blob
,
fileName
);
}
else
{
const
url
=
URL
.
createObjectURL
(
blob
);
const
link
=
document
.
createElement
(
'a'
);
link
.
style
.
display
=
'none'
;
link
.
href
=
url
;
link
.
setAttribute
(
'download'
,
fileName
);
document
.
body
.
appendChild
(
link
);
link
.
click
();
document
.
body
.
removeChild
(
link
);
setTimeout
(()
=>
{
URL
.
revokeObjectURL
(
url
);
},
500
);
}
}
export
function
getInputDefaultValue
(
property
)
{
export
function
getInputDefaultValue
(
property
)
{
return
property
?
property
.
hasOwnProperty
(
'default'
)
?
property
.
default
+
''
:
'unset'
:
'unset'
;
return
property
?
property
.
hasOwnProperty
(
'default'
)
?
property
.
default
+
''
:
'unset'
:
'unset'
;
}
}
...
@@ -101,6 +81,26 @@ export function clonePureObj(obj) {
...
@@ -101,6 +81,26 @@ export function clonePureObj(obj) {
return
JSON
.
parse
(
JSON
.
stringify
(
obj
));
return
JSON
.
parse
(
JSON
.
stringify
(
obj
));
}
}
export
function
saveAs
(
blob
,
fileName
)
{
if
(
'msSaveOrOpenBlob'
in
navigator
)
{
navigator
.
msSaveOrOpenBlob
(
blob
,
fileName
);
}
else
{
const
url
=
URL
.
createObjectURL
(
blob
);
const
link
=
document
.
createElement
(
'a'
);
link
.
style
.
display
=
'none'
;
link
.
href
=
url
;
link
.
setAttribute
(
'download'
,
fileName
);
document
.
body
.
appendChild
(
link
);
link
.
click
();
document
.
body
.
removeChild
(
link
);
setTimeout
(()
=>
{
URL
.
revokeObjectURL
(
url
);
},
500
);
}
}
export
function
readTextFile
(
file
)
{
export
function
readTextFile
(
file
)
{
return
new
Promise
((
resolve
,
reject
)
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
const
fileReader
=
new
FileReader
();
const
fileReader
=
new
FileReader
();
...
...
src/utils/sheet-pack.js
0 → 100644
View file @
480c0363
/**
* Created by rockyl on 2019-12-08.
*/
import
MaxRectsBinPack
from
"./MaxRectsBinPack"
;
const
packExts
=
[
'.png'
];
//, '.jpg', '.jpeg', '.bmp'
let
canvas
=
document
.
createElement
(
'canvas'
);
export
async
function
packImages
(
asssts
,
options
=
{})
{
const
padding
=
options
.
padding
||
1
;
const
maxSize
=
options
.
maxSize
||
2048
;
const
mode
=
options
.
mode
||
0
;
const
images
=
await
preProcessing
(
asssts
);
let
rects
=
[],
singles
=
[];
for
(
let
item
of
images
)
{
const
{
image
,
assets
,
image
:
{
width
,
height
}}
=
item
;
if
(
width
<
maxSize
&&
height
<
maxSize
)
{
const
rectWidth
=
width
+
padding
*
2
;
const
rectHeight
=
height
+
padding
*
2
;
rects
.
push
({
image
,
assets
,
width
:
rectWidth
,
height
:
rectHeight
,
area
:
rectWidth
*
rectHeight
,
sourceW
:
width
,
sourceH
:
height
,
offX
:
0
,
offY
:
0
,
})
}
else
{
asssts
.
push
({
name
:
assets
[
0
].
name
,
ext
:
assets
[
0
].
ext
,
url
:
assets
[
0
].
url
,
uuids
:
assets
.
map
(
asset
=>
asset
.
uuid
),
})
}
}
rects
.
sort
((
a
,
b
)
=>
{
return
b
.
area
-
a
.
area
;
});
let
remainRects
=
rects
.
concat
();
let
index
=
0
;
while
(
remainRects
.
length
>
0
)
{
let
name
=
'sheet'
+
index
;
let
pack
=
new
MaxRectsBinPack
(
maxSize
,
maxSize
,
false
);
let
packedRects
=
pack
.
insertRects
(
remainRects
,
mode
);
//document.body.append(canvas);
canvas
.
width
=
canvas
.
height
=
maxSize
;
let
context
=
canvas
.
getContext
(
'2d'
);
//context.fillStyle = `rgba(${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, 1)`;
//context.strokeRect(0, 0, maxSize, maxSize);
for
(
let
rect
of
packedRects
)
{
context
.
drawImage
(
rect
.
image
,
rect
.
x
+
padding
,
rect
.
y
+
padding
);
}
let
blob
=
await
new
Promise
(
resolve
=>
{
canvas
.
toBlob
(
function
(
blob
)
{
resolve
(
blob
);
},
'image/png'
);
});
let
frames
=
{};
let
i
=
0
;
for
(
let
rect
of
packedRects
)
{
let
sprite
=
{
x
:
rect
.
x
+
padding
,
y
:
rect
.
y
+
padding
,
w
:
rect
.
width
-
padding
*
2
,
h
:
rect
.
height
-
padding
*
2
,
ox
:
rect
.
offX
,
oy
:
rect
.
offY
,
sw
:
rect
.
sourceW
,
sh
:
rect
.
sourceH
,
};
for
(
let
asset
of
rect
.
assets
)
{
frames
[
asset
.
uuid
]
=
sprite
;
i
++
;
}
}
asssts
.
push
({
ext
:
'.sht'
,
file
:
new
File
([
blob
],
name
+
'.png'
),
frames
,
});
index
++
;
}
}
function
loadImage
(
url
,
assets
)
{
return
new
Promise
((
resolve
,
reject
)
=>
{
const
img
=
new
Image
();
img
.
crossOrigin
=
'anonymous'
;
img
.
onload
=
function
()
{
resolve
({
image
:
img
,
assets
,
})
};
img
.
onerror
=
reject
;
img
.
src
=
url
;
})
}
async
function
preProcessing
(
assets
)
{
let
targetAssets
=
[];
for
(
let
i
=
0
,
li
=
assets
.
length
;
i
<
li
;
i
++
)
{
const
asset
=
assets
[
i
];
if
(
packExts
.
includes
(
asset
.
ext
))
{
targetAssets
.
push
(
assets
.
splice
(
i
,
1
)[
0
]);
i
--
;
li
--
;
}
}
let
groups
=
{};
for
(
let
asset
of
targetAssets
)
{
let
group
=
groups
[
asset
.
url
];
if
(
!
group
)
{
group
=
groups
[
asset
.
url
]
=
[];
}
group
.
push
(
asset
);
}
let
ps
=
[];
for
(
let
url
in
groups
)
{
ps
.
push
(
loadImage
(
url
,
groups
[
url
]))
}
return
await
Promise
.
all
(
ps
);
}
src/views/Editor.vue
View file @
480c0363
...
@@ -72,8 +72,8 @@
...
@@ -72,8 +72,8 @@
destroyed
()
{
destroyed
()
{
document
.
removeEventListener
(
'keydown'
,
this
.
onKeyPress
)
document
.
removeEventListener
(
'keydown'
,
this
.
onKeyPress
)
},
},
created
(){
created
()
{
events
.
$on
(
'saveAndPreview'
,()
=>
{
events
.
$on
(
'saveAndPreview'
,
()
=>
{
this
.
clickMenu
(
"preview"
);
this
.
clickMenu
(
"preview"
);
});
});
},
},
...
@@ -87,7 +87,9 @@
...
@@ -87,7 +87,9 @@
onKeyPress
(
e
)
{
onKeyPress
(
e
)
{
if
(
e
.
key
===
's'
&&
(
e
.
ctrlKey
||
e
.
metaKey
))
{
if
(
e
.
key
===
's'
&&
(
e
.
ctrlKey
||
e
.
metaKey
))
{
e
.
preventDefault
();
e
.
preventDefault
();
this
.
clickMenu
(
"preview"
);
this
.
saveProject
();
return
false
;
return
false
;
}
}
},
},
...
@@ -166,8 +168,11 @@
...
@@ -166,8 +168,11 @@
case
'preview'
:
case
'preview'
:
await
this
.
pack
(
true
);
await
this
.
pack
(
true
);
break
;
break
;
case
'pack'
:
case
'preview2'
:
await
this
.
pack
();
this
.
preview
();
break
;
case
'publish'
:
await
this
.
publish
();
break
;
break
;
case
'undo'
:
case
'undo'
:
this
.
$store
.
commit
(
'undoRedo'
,
1
);
this
.
$store
.
commit
(
'undoRedo'
,
1
);
...
@@ -197,13 +202,18 @@
...
@@ -197,13 +202,18 @@
break
;
break
;
}
}
},
},
async
publish
(){
this
.
pack
();
},
async
pack
(
debug
=
false
)
{
async
pack
(
debug
=
false
)
{
const
loading
=
this
.
$loading
({
const
loading
=
this
.
$loading
({
lock
:
true
,
lock
:
true
,
text
:
this
.
$t
(
'Packing'
),
text
:
this
.
$t
(
'Packing'
),
});
});
try
{
try
{
if
(
!
debug
){
await
this
.
saveProject
(
false
);
await
this
.
saveProject
(
false
);
}
const
packResult
=
await
this
.
packProject
(
debug
);
const
packResult
=
await
this
.
packProject
(
debug
);
this
.
$message
({
this
.
$message
({
message
:
this
.
$t
(
'Pack project successfully'
),
message
:
this
.
$t
(
'Pack project successfully'
),
...
@@ -227,6 +237,7 @@
...
@@ -227,6 +237,7 @@
});*/
});*/
}
catch
(
e
)
{
}
catch
(
e
)
{
console
.
log
(
e
);
this
.
$message
({
this
.
$message
({
message
:
this
.
$t
(
'Pack project failed'
),
message
:
this
.
$t
(
'Pack project failed'
),
type
:
'error'
,
type
:
'error'
,
...
@@ -238,6 +249,18 @@
...
@@ -238,6 +249,18 @@
backToHome
()
{
backToHome
()
{
this
.
$router
.
replace
({
name
:
'home'
});
this
.
$router
.
replace
({
name
:
'home'
});
},
},
preview
()
{
this
.
savePreview
();
const
{
projectID
}
=
this
.
$route
.
params
;
let
previewUrl
=
new
URL
(
location
.
href
);
previewUrl
.
hash
=
'#/preview/'
+
projectID
;
setTimeout
(()
=>
{
window
.
open
(
previewUrl
.
href
,
'blank'
);
},
300
);
},
...
mapActions
([
...
mapActions
([
'localVersionExist'
,
'localVersionExist'
,
'loadFromLocal'
,
'loadFromLocal'
,
...
@@ -246,6 +269,8 @@
...
@@ -246,6 +269,8 @@
"saveToRemote"
,
"saveToRemote"
,
'updateEnv'
,
'updateEnv'
,
'packProject'
,
'packProject'
,
'savePreview'
,
'packImages'
,
])
])
}
}
}
}
...
...
src/views/Editor/Assets.vue
View file @
480c0363
...
@@ -37,7 +37,7 @@
...
@@ -37,7 +37,7 @@
</template>
</template>
<
script
>
<
script
>
import
{
map
State
,
mapMutations
,
mapActions
}
from
'vuex'
import
{
map
Getters
,
mapMutations
,
mapActions
}
from
'vuex'
import
Pane
from
"../../components/Pane"
;
import
Pane
from
"../../components/Pane"
;
import
FileItem
from
"./Assets/FileItem"
;
import
FileItem
from
"./Assets/FileItem"
;
import
AssetsShow
from
"./Assets/AssetsShow"
;
import
AssetsShow
from
"./Assets/AssetsShow"
;
...
@@ -57,9 +57,7 @@
...
@@ -57,9 +57,7 @@
}
}
},
},
computed
:
{
computed
:
{
...
mapState
({
...
mapGetters
([
'assets'
]),
assets
:
state
=>
state
.
project
.
data
.
assets
}),
},
},
mounted
()
{
mounted
()
{
this
.
currentItem
=
null
;
this
.
currentItem
=
null
;
...
...
src/views/Editor/Assets/FileItem.vue
View file @
480c0363
...
@@ -2,8 +2,11 @@
...
@@ -2,8 +2,11 @@
<div
class=
"file-item"
@
click=
"$emit('click', $event)"
>
<div
class=
"file-item"
@
click=
"$emit('click', $event)"
>
<div
class=
"icon"
>
<div
class=
"icon"
>
<i
v-if=
"!showThumbnail"
draggable=
"true"
class=
"file-icon"
:class=
"fileIcon"
></i>
<i
v-if=
"!showThumbnail"
draggable=
"true"
class=
"file-icon"
:class=
"fileIcon"
></i>
<img
@
dragstart=
"assetDragStart(data)"
v-if=
"showThumbnail"
draggable=
"true"
class=
"thumbnail"
:src=
"thumbnailUrl"
alt=
"thumb"
@
dblclick=
"onDbclick()"
>
<img
@
dragstart=
"assetDragStart(data)"
v-if=
"showThumbnail"
draggable=
"true"
class=
"thumbnail"
:src=
"thumbnailUrl"
alt=
"thumb"
@
dblclick=
"onDbclick()"
>
<div
class=
"operate-bar"
>
<div
class=
"operate-bar"
>
<el-button
circle
size=
"mini"
type=
"success"
icon=
"el-icon-upload2"
@
dblclick
.
native
.
stop
@
click=
"onClickReplace"
/>
<el-button
circle
size=
"mini"
type=
"success"
icon=
"el-icon-edit"
@
dblclick
.
native
.
stop
@
click=
"onClickEdit"
/>
<el-button
circle
size=
"mini"
type=
"success"
icon=
"el-icon-edit"
@
dblclick
.
native
.
stop
@
click=
"onClickEdit"
/>
<el-button
circle
size=
"mini"
type=
"danger"
icon=
"el-icon-delete"
@
dblclick
.
native
.
stop
<el-button
circle
size=
"mini"
type=
"danger"
icon=
"el-icon-delete"
@
dblclick
.
native
.
stop
@
click=
"onClickDelete"
/>
@
click=
"onClickDelete"
/>
...
@@ -17,21 +20,17 @@
...
@@ -17,21 +20,17 @@
</
template
>
</
template
>
<
script
>
<
script
>
import
{
mapMutations
}
from
"vuex"
;
import
{
mapMutations
,
mapActions
}
from
"vuex"
;
import
{
fileTypeIcon
}
from
"../../../config"
;
import
{
fileTypeIcon
}
from
"../../../config"
;
import
{
strEllipsis
}
from
"../../../utils"
;
import
{
s
electFile
,
s
trEllipsis
}
from
"../../../utils"
;
export
default
{
export
default
{
name
:
"FileItem"
,
name
:
"FileItem"
,
props
:
[
'data'
],
props
:
[
'data'
],
data
()
{
data
()
{
return
{
return
{}
}
},
watch
:
{
},
},
watch
:
{},
computed
:
{
computed
:
{
fileIcon
()
{
fileIcon
()
{
let
icon
=
fileTypeIcon
[
this
.
data
.
ext
];
let
icon
=
fileTypeIcon
[
this
.
data
.
ext
];
...
@@ -43,7 +42,7 @@
...
@@ -43,7 +42,7 @@
thumbnailUrl
()
{
thumbnailUrl
()
{
return
this
.
data
.
url
;
return
this
.
data
.
url
;
},
},
ellipsisName
(){
ellipsisName
()
{
return
strEllipsis
(
this
.
data
.
name
,
14
,
5
);
return
strEllipsis
(
this
.
data
.
name
,
14
,
5
);
},
},
},
},
...
@@ -78,11 +77,23 @@
...
@@ -78,11 +77,23 @@
}).
catch
(()
=>
{
}).
catch
(()
=>
{
});
});
},
},
onClickReplace
()
{
selectFile
((
files
)
=>
{
let
file
=
files
[
0
];
this
.
replaceAsset
({
file
:
file
,
uuid
:
this
.
data
.
uuid
,
});
})
},
...
mapMutations
([
...
mapMutations
([
'deleteAsset'
,
'deleteAsset'
,
'modifyAsset'
,
'modifyAsset'
,
'assetDragStart'
'assetDragStart'
,
]),
]),
...
mapActions
([
'replaceAsset'
])
}
}
}
}
</
script
>
</
script
>
...
...
src/views/Editor/behavior-editor/BehaviorEditor.vue
View file @
480c0363
...
@@ -10,7 +10,10 @@
...
@@ -10,7 +10,10 @@
:splitpanes-size=
"80"
/>
:splitpanes-size=
"80"
/>
</split-panes>
</split-panes>
<div
class=
"center full-size background"
splitpanes-min=
"20"
:splitpanes-size=
"70"
>
<div
class=
"center full-size background"
splitpanes-min=
"20"
:splitpanes-size=
"70"
>
<div
class=
"top-bar"
>
<edit-path
:processStack=
"processStack"
@
pop=
"onPop"
/>
<edit-path
:processStack=
"processStack"
@
pop=
"onPop"
/>
<el-button
icon=
"el-icon-search"
circle
plain
size=
"mini"
@
click=
"onClickSearch"
></el-button>
</div>
<!--
<div
class=
"operate-bar"
>
<!--
<div
class=
"operate-bar"
>
<el-button-group>
<el-button-group>
<el-button
size=
"mini"
icon=
"el-icon-zoom-out"
@
click=
"setScale(-0.1)"
/>
<el-button
size=
"mini"
icon=
"el-icon-zoom-out"
@
click=
"setScale(-0.1)"
/>
...
@@ -25,6 +28,7 @@
...
@@ -25,6 +28,7 @@
</div>
</div>
</split-panes>
</split-panes>
<meta-editor-dialog
ref=
"metaEditorDialog"
@
input=
"onSaveMeta"
/>
<meta-editor-dialog
ref=
"metaEditorDialog"
@
input=
"onSaveMeta"
/>
<meta-search-dialog
ref=
"metaSearchDialog"
/>
</div>
</div>
</
template
>
</
template
>
...
@@ -38,11 +42,12 @@
...
@@ -38,11 +42,12 @@
import
Process
from
"./Board/Process"
;
import
Process
from
"./Board/Process"
;
import
MetaEditorDialog
from
"./MetaEditorDialog"
;
import
MetaEditorDialog
from
"./MetaEditorDialog"
;
import
events
from
"@/global-events.js"
import
events
from
"@/global-events.js"
import
MetaSearchDialog
from
"./MetaSearchDialog"
;
export
default
{
export
default
{
name
:
"BehaviorEditor"
,
name
:
"BehaviorEditor"
,
components
:
{
MetaEditorDialog
,
PropertiesEditor
,
EditPath
,
ProcessList
,
Board
,
SplitPanes
,},
components
:
{
Meta
SearchDialog
,
Meta
EditorDialog
,
PropertiesEditor
,
EditPath
,
ProcessList
,
Board
,
SplitPanes
,},
props
:
[],
props
:
[],
data
()
{
data
()
{
return
{
return
{
...
@@ -99,6 +104,9 @@
...
@@ -99,6 +104,9 @@
this
.
$refs
.
board
.
edit
(
process
,
this
.
resolveProcess
);
this
.
$refs
.
board
.
edit
(
process
,
this
.
resolveProcess
);
this
.
$refs
.
properties
.
edit
();
this
.
$refs
.
properties
.
edit
();
},
},
onClickSearch
(){
this
.
$refs
.
metaSearchDialog
.
show
();
},
onEditMeta
(
meta
)
{
onEditMeta
(
meta
)
{
this
.
metaInEditing
=
meta
;
this
.
metaInEditing
=
meta
;
this
.
$refs
.
metaEditorDialog
.
edit
(
meta
);
this
.
$refs
.
metaEditorDialog
.
edit
(
meta
);
...
...
src/views/Editor/behavior-editor/Board.vue
View file @
480c0363
...
@@ -115,7 +115,13 @@
...
@@ -115,7 +115,13 @@
},
},
addSubProcess
(
uuid
,
data
)
{
addSubProcess
(
uuid
,
data
)
{
const
process
=
new
Process
(
this
.
process
,
data
,
this
.
resolveProcess
);
const
process
=
new
Process
(
this
.
process
,
data
,
this
.
resolveProcess
);
if
(
process
.
meta
)
{
this
.
$set
(
this
.
subProcessMap
,
uuid
,
process
);
this
.
$set
(
this
.
subProcessMap
,
uuid
,
process
);
}
else
{
console
.
log
(
'节点丢失:'
,
uuid
);
}
},
},
showInlineChoose
()
{
showInlineChoose
()
{
return
this
.
$confirm
(
this
.
$t
(
'As inline'
));
return
this
.
$confirm
(
this
.
$t
(
'As inline'
));
...
@@ -192,8 +198,8 @@
...
@@ -192,8 +198,8 @@
this
.
addProcessFromCopy
(
dataStr
);
this
.
addProcessFromCopy
(
dataStr
);
}
}
},
},
addProcessFromCopy
(
avatar
){
addProcessFromCopy
(
avatar
)
{
if
(
typeof
avatar
===
'string'
)
{
if
(
typeof
avatar
===
'string'
)
{
avatar
=
JSON
.
parse
(
avatar
);
avatar
=
JSON
.
parse
(
avatar
);
}
}
...
@@ -249,6 +255,17 @@
...
@@ -249,6 +255,17 @@
outputIndex
,
outputIndex
,
});
});
this
.
drawState
.
lineID
++
;
this
.
drawState
.
lineID
++
;
}
else
{
for
(
let
uuid
in
this
.
subProcessMap
)
{
const
process
=
this
.
subProcessMap
[
uuid
];
for
(
let
key
in
process
.
data
.
output
)
{
let
item
=
process
.
data
.
output
[
key
];
let
index
=
item
.
indexOf
(
outputID
);
if
(
index
>=
0
){
item
.
splice
(
index
,
1
);
}
}
}
}
}
},
},
onPinHover
(
x
,
y
,
pin
)
{
onPinHover
(
x
,
y
,
pin
)
{
...
@@ -299,6 +316,14 @@
...
@@ -299,6 +316,14 @@
this
.
$delete
(
this
.
subProcessMap
,
process
.
uuid
);
this
.
$delete
(
this
.
subProcessMap
,
process
.
uuid
);
this
.
$delete
(
this
.
process
.
meta
.
sub
,
process
.
uuid
);
this
.
$delete
(
this
.
process
.
meta
.
sub
,
process
.
uuid
);
let
remain
=
0
;
for
(
let
key
in
this
.
process
.
meta
.
sub
){
let
p
=
this
.
process
.
meta
.
sub
[
key
];
if
(
p
.
meta
===
meta
.
id
)
{
remain
++
;
}
}
for
(
let
id
in
this
.
lines
)
{
for
(
let
id
in
this
.
lines
)
{
const
line
=
this
.
lines
[
id
];
const
line
=
this
.
lines
[
id
];
const
{
prev
,
next
}
=
line
;
const
{
prev
,
next
}
=
line
;
...
@@ -309,18 +334,20 @@
...
@@ -309,18 +334,20 @@
}
}
if
(
meta
.
isDivider
||
meta
.
isInline
)
{
//如果是分流节点或者内联节点还要删除对应的meta
if
(
meta
.
isDivider
||
meta
.
isInline
)
{
//如果是分流节点或者内联节点还要删除对应的meta
if
(
remain
===
0
){
this
.
deleteProcessMeta
({
this
.
deleteProcessMeta
({
meta
,
meta
,
process
:
this
.
process
,
process
:
this
.
process
,
});
});
}
}
}
},
},
onProcessNodeCopy
(
data
,
meta
)
{
onProcessNodeCopy
(
data
,
meta
)
{
if
(
meta
.
isInline
)
{
//内联直接复制
if
(
meta
.
isInline
)
{
//内联直接复制
let
avatar
=
clonePureObj
(
data
);
let
avatar
=
clonePureObj
(
data
);
this
.
addProcessFromCopy
(
avatar
);
this
.
addProcessFromCopy
(
avatar
);
}
else
{
}
else
{
copy
(
JSON
.
stringify
(
data
),
{
format
:
'process-data'
});
copy
(
JSON
.
stringify
(
data
),
{
format
:
'process-data'
});
this
.
$message
({
this
.
$message
({
message
:
this
.
$t
(
'Copied process to clipboard'
),
message
:
this
.
$t
(
'Copied process to clipboard'
),
...
...
src/views/Editor/behavior-editor/MetaSearchDialog.vue
0 → 100644
View file @
480c0363
<
template
>
<el-dialog
:title=
"$t('Meta Search')"
width=
"80%"
:visible
.
sync=
"visible"
:append-to-body=
"true"
custom-class=
"behavior-editor-dialog"
>
<div
style=
"padding: 10px;"
>
<el-input
size=
"mini"
v-model=
"keyword"
>
<el-button
slot=
"append"
icon=
"el-icon-search"
@
click=
"search"
></el-button>
</el-input>
<div
style=
"height: 50vh;"
>
</div>
</div>
<div
slot=
"footer"
class=
"dialog-footer"
>
<el-button
size=
"mini"
plain
@
click=
"close"
>
{{
$t
(
'Close'
)
}}
</el-button>
</div>
</el-dialog>
</
template
>
<
script
>
export
default
{
name
:
"MetaSearchDialog"
,
data
()
{
return
{
visible
:
false
,
keyword
:
''
,
}
},
methods
:{
show
(){
this
.
visible
=
true
;
},
close
(){
this
.
visible
=
false
;
},
search
(){
},
}
}
</
script
>
<
style
scoped
>
</
style
>
\ No newline at end of file
src/views/Editor/behavior-editor/PropertiesEditor.vue
View file @
480c0363
...
@@ -5,7 +5,7 @@
...
@@ -5,7 +5,7 @@
</el-input>
</el-input>
<el-scrollbar
class=
"scrollbar"
wrap-class=
"wrap-x-hidden"
<el-scrollbar
class=
"scrollbar"
wrap-class=
"wrap-x-hidden"
view-class=
"scrollbar-view"
>
view-class=
"scrollbar-view"
>
<el-form
v-model=
"process"
size=
"mini"
label-width=
"1
5
0px"
label-position=
"left"
@
submit
.
native
.
prevent
>
<el-form
v-model=
"process"
size=
"mini"
label-width=
"1
0
0px"
label-position=
"left"
@
submit
.
native
.
prevent
>
<component
v-for=
"(property, key) in process.meta.props"
<component
v-for=
"(property, key) in process.meta.props"
:is=
"getInput(property)"
:is=
"getInput(property)"
v-model=
"process.data.props[key]"
v-model=
"process.data.props[key]"
...
...
src/views/Home.vue
View file @
480c0363
<
template
>
<
template
>
<div
class=
"home"
>
<div
class=
"home"
>
<p
class=
"editor-name"
style=
"font-weight: bold"
>
{{
env
.
name
}}
<span
<div
class=
"editor-name"
style=
"font-weight: bold"
>
{{
env
.
name
}}
class=
"editor-version"
>
{{
env
.
version
}}
</span></p>
<span
class=
"editor-version"
>
{{
env
.
version
}}
</span>
</div>
<main>
<main>
<div
class=
"project-list"
>
<div
class=
"project-list"
>
<el-table
<el-table
...
@@ -33,6 +34,11 @@
...
@@ -33,6 +34,11 @@
type=
"success"
icon=
"el-icon-document-copy"
type=
"success"
icon=
"el-icon-document-copy"
size=
"small"
circle
plain
>
size=
"small"
circle
plain
>
</el-button>
</el-button>
<el-button
@
click
.
native
.
prevent=
"exportProject(scope.row)"
type=
"warning"
icon=
"el-icon-receiving"
size=
"small"
circle
plain
>
</el-button>
<!--
<el-button
<!--
<el-button
@
click
.
native
.
prevent=
"onDeleteProject(scope.row)"
@
click
.
native
.
prevent=
"onDeleteProject(scope.row)"
type=
"danger"
icon=
"el-icon-delete"
type=
"danger"
icon=
"el-icon-delete"
...
@@ -42,8 +48,18 @@
...
@@ -42,8 +48,18 @@
</el-table-column>
</el-table-column>
</el-table>
</el-table>
</div>
</div>
<div
class=
"bottom-bar"
>
<div>
<div>
<el-button
@
click=
"showCreateProjectDialog()"
>
{{$t('Create')}}
</el-button>
<el-button
type=
"primary"
@
click=
"showCreateProjectDialog()"
>
{{$t('Create')}}
</el-button>
<el-button
@
click=
"importProject()"
>
{{$t('Import')}}
</el-button>
</div>
<el-pagination
@
current-change=
"handleCurrentChange"
:current-page
.
sync=
"currentPage"
:page-size=
"pageSize"
layout=
"prev, pager, next, jumper"
:total=
"env.projectCount"
>
</el-pagination>
</div>
</div>
<create-project-dialog
ref=
"createProjectDialog"
@
success=
"onCreateProject"
/>
<create-project-dialog
ref=
"createProjectDialog"
@
success=
"onCreateProject"
/>
<duplicate-project-dialog
ref=
"duplicateProjectDialog"
@
success=
"onDuplicateProject"
/>
<duplicate-project-dialog
ref=
"duplicateProjectDialog"
@
success=
"onDuplicateProject"
/>
...
@@ -54,9 +70,10 @@
...
@@ -54,9 +70,10 @@
<
script
>
<
script
>
import
{
mapState
,
mapActions
}
from
'vuex'
import
{
mapState
,
mapActions
}
from
'vuex'
import
CreateProjectDialog
from
"./Home/CreateProjectDialog"
;
import
CreateProjectDialog
from
"./Home/CreateProjectDialog"
;
import
{
playWaiting
}
from
"../utils"
;
import
{
playWaiting
,
readTextFile
,
saveAs
,
selectFile
}
from
"../utils"
;
import
moment
from
"moment"
;
import
moment
from
"moment"
;
import
DuplicateProjectDialog
from
"./Home/DuplicateProjectDialog"
;
import
DuplicateProjectDialog
from
"./Home/DuplicateProjectDialog"
;
import
{
PAGE_SIZE
}
from
"../config"
;
export
default
{
export
default
{
name
:
"Home"
,
name
:
"Home"
,
...
@@ -64,10 +81,13 @@
...
@@ -64,10 +81,13 @@
data
()
{
data
()
{
return
{
return
{
appVersion
:
'v1.0.0'
,
appVersion
:
'v1.0.0'
,
currentPage
:
1
,
pageSize
:
PAGE_SIZE
,
}
}
},
},
mounted
()
{
mounted
()
{
playWaiting
(
this
.
prepare
(),
this
.
$t
(
'Preparing'
)).
catch
(
e
=>
{});
playWaiting
(
this
.
prepare
(),
this
.
$t
(
'Preparing'
)).
catch
(
e
=>
{
});
},
},
computed
:
{
computed
:
{
...
mapState
([
...
mapState
([
...
@@ -76,10 +96,10 @@
...
@@ -76,10 +96,10 @@
]),
]),
},
},
methods
:
{
methods
:
{
prepare
(){
prepare
()
{
return
Promise
.
all
([
return
Promise
.
all
([
this
.
updateEnv
(),
this
.
updateEnv
(),
this
.
updateProjects
(
),
this
.
handleCurrentChange
(
1
),
])
])
},
},
moment
(
time
)
{
moment
(
time
)
{
...
@@ -88,6 +108,21 @@
...
@@ -88,6 +108,21 @@
showCreateProjectDialog
()
{
showCreateProjectDialog
()
{
this
.
$refs
.
createProjectDialog
.
show
();
this
.
$refs
.
createProjectDialog
.
show
();
},
},
importProject
()
{
selectFile
((
files
)
=>
{
readTextFile
(
files
[
0
])
.
then
(
txt
=>
{
let
data
=
JSON
.
parse
(
txt
);
return
playWaiting
(
this
.
createProject
(
data
),
this
.
$t
(
'Importing project'
));
}
)
});
},
async
exportProject
({
id
})
{
const
project
=
await
playWaiting
(
this
.
fetchProject
(
id
),
this
.
$t
(
'Exporting project'
));
saveAs
(
new
Blob
([
JSON
.
stringify
(
project
)]),
project
.
name
+
'.json'
);
},
showDuplicateProjectDialog
(
project
)
{
showDuplicateProjectDialog
(
project
)
{
this
.
$refs
.
duplicateProjectDialog
.
show
(
project
);
this
.
$refs
.
duplicateProjectDialog
.
show
(
project
);
},
},
...
@@ -100,10 +135,12 @@
...
@@ -100,10 +135,12 @@
cancelButtonText
:
this
.
$t
(
'Cancel'
),
cancelButtonText
:
this
.
$t
(
'Cancel'
),
type
:
'warning'
type
:
'warning'
}).
then
(
}).
then
(
()
=>
{
()
=>
{
playWaiting
(
this
.
deleteProject
(
project
.
id
),
this
.
$t
(
'Deleting'
)).
catch
(
e
=>
{});
playWaiting
(
this
.
deleteProject
(
project
.
id
),
this
.
$t
(
'Deleting'
)).
catch
(
e
=>
{
});
},
},
()
=>
{}
()
=>
{
}
)
)
},
},
onCreateProject
(
projectID
)
{
onCreateProject
(
projectID
)
{
...
@@ -115,8 +152,18 @@
...
@@ -115,8 +152,18 @@
editProject
(
projectID
)
{
editProject
(
projectID
)
{
this
.
$router
.
push
({
name
:
'editor'
,
params
:
{
projectID
}});
this
.
$router
.
push
({
name
:
'editor'
,
params
:
{
projectID
}});
},
},
async
handleCurrentChange
(
page
)
{
const
loading
=
this
.
$loading
({
lock
:
true
,
text
:
this
.
$t
(
'In processing'
),
});
await
this
.
fetchProjects
({
currentPage
:
page
,
pageSize
:
this
.
pageSize
});
loading
.
close
();
},
...
mapActions
([
...
mapActions
([
'updateProjects'
,
'fetchProjects'
,
'fetchProject'
,
'createProject'
,
'deleteProject'
,
'deleteProject'
,
'updateEnv'
,
'updateEnv'
,
]),
]),
...
...
src/views/Preview.vue
0 → 100644
View file @
480c0363
<
template
>
<iframe
ref=
"iframe"
class=
"player-wrapper"
>
</iframe>
</
template
>
<
script
>
export
default
{
name
:
"Preview"
,
data
()
{
return
{
ts
:
''
,
}
},
mounted
()
{
if
(
!
this
.
ts
){
this
.
ts
=
localStorage
.
getItem
(
'preview-ts'
);
}
document
.
addEventListener
(
"visibilitychange"
,
this
.
onVisibilityChange
);
setTimeout
(()
=>
{
this
.
buildPage
();
},
100
);
},
destroyed
(){
document
.
removeEventListener
(
"visibilitychange"
,
this
.
onVisibilityChange
);
},
methods
:
{
onVisibilityChange
(
e
){
if
(
!
document
.
hidden
){
let
ts
=
localStorage
.
getItem
(
'preview-ts'
);
if
(
this
.
ts
!==
ts
){
this
.
$refs
.
iframe
.
contentDocument
.
location
.
reload
();
document
.
location
.
reload
();
this
.
ts
=
ts
;
}
}
},
buildPage
()
{
const
{
projectID
}
=
this
.
$route
.
params
;
const
storeKey
=
'preview-project-'
+
projectID
;
let
data
=
localStorage
.
getItem
(
storeKey
);
let
dataObj
=
JSON
.
parse
(
data
);
let
{
options
:
{
tpl
,
pageTitle
,
containerId
}}
=
dataObj
.
data
;
const
launchCode
=
`engine.launchWithLocalStorage("
${
projectID
}
");`
;
tpl
=
tpl
.
replace
(
'$PAGE_TITLE$'
,
pageTitle
)
.
replace
(
'$CONTAINER_ID$'
,
containerId
)
.
replace
(
'$SCRIPTS$'
,
''
)
.
replace
(
'engine.launch(
\'
//yun.duiba.com.cn/aurora/$VERSION$-data.json
\'
);'
,
launchCode
);
const
doc
=
this
.
$refs
.
iframe
.
contentDocument
;
doc
.
write
(
tpl
);
},
}
}
</
script
>
<
style
scoped
>
.player-wrapper
{
border
:
0
;
width
:
100%
;
height
:
100%
;
}
</
style
>
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment