Showing
7 changed files
with
289 additions
and
35 deletions
@@ -8,6 +8,7 @@ | @@ -8,6 +8,7 @@ | ||
8 | 8 | ||
9 | <body> | 9 | <body> |
10 | <link rel="stylesheet" href="css/main.css" /> | 10 | <link rel="stylesheet" href="css/main.css" /> |
11 | + <link rel="stylesheet" href="./js/libs/spin/spin.css"> | ||
11 | <link rel="stylesheet" href="js/libs/codemirror/codemirror.css" /> | 12 | <link rel="stylesheet" href="js/libs/codemirror/codemirror.css" /> |
12 | <link rel="stylesheet" href="js/libs/codemirror/theme/monokai.css" /> | 13 | <link rel="stylesheet" href="js/libs/codemirror/theme/monokai.css" /> |
13 | <link rel="stylesheet" href="js/libs/codemirror/addon/dialog.css" /> | 14 | <link rel="stylesheet" href="js/libs/codemirror/addon/dialog.css" /> |
@@ -5,6 +5,7 @@ import html2canvas from 'html2canvas' | @@ -5,6 +5,7 @@ import html2canvas from 'html2canvas' | ||
5 | import { fetchRouteParamsLocation } from '@/utils' | 5 | import { fetchRouteParamsLocation } from '@/utils' |
6 | import { uploadFile } from '@/api/external/contentSave/content' | 6 | import { uploadFile } from '@/api/external/contentSave/content' |
7 | import { base64toFile } from '../utils/Base64ToFile.js' | 7 | import { base64toFile } from '../utils/Base64ToFile.js' |
8 | +import { useSpin } from '../js/libs/spin/useSpin.js' | ||
8 | 9 | ||
9 | function MenubarFile(editor) { | 10 | function MenubarFile(editor) { |
10 | const strings = editor.strings | 11 | const strings = editor.strings |
@@ -72,7 +73,7 @@ function MenubarFile(editor) { | @@ -72,7 +73,7 @@ function MenubarFile(editor) { | ||
72 | const loader = new THREE.FileLoader() | 73 | const loader = new THREE.FileLoader() |
73 | 74 | ||
74 | for (let i = 0; i < examples.length; i++) { | 75 | for (let i = 0; i < examples.length; i++) { |
75 | - ;(function (i) { | 76 | + ; (function (i) { |
76 | const example = examples[i] | 77 | const example = examples[i] |
77 | 78 | ||
78 | const option = new UIRow() | 79 | const option = new UIRow() |
@@ -148,31 +149,38 @@ function MenubarFile(editor) { | @@ -148,31 +149,38 @@ function MenubarFile(editor) { | ||
148 | .onClick(async function () { | 149 | .onClick(async function () { |
149 | // 获取缩略图片 | 150 | // 获取缩略图片 |
150 | const range = document.querySelector('#viewport').children[3] | 151 | const range = document.querySelector('#viewport').children[3] |
151 | - // 生成图片 | ||
152 | - const canvasImage = await html2canvas(range, { | ||
153 | - backgroundColor: null, | ||
154 | - allowTaint: true, | ||
155 | - useCORS: true, | ||
156 | - logging: false | ||
157 | - }) | ||
158 | - // 上传预览图 | ||
159 | - const uploadParams = new FormData() | ||
160 | - uploadParams.append( | ||
161 | - 'file', | ||
162 | - base64toFile(canvasImage.toDataURL(), `${fetchRouteParamsLocation()}_index_preview.png`) | ||
163 | - ) | ||
164 | - const uploadRes = await uploadFile(uploadParams) | ||
165 | - const file_json = editor.toJSON() | ||
166 | - const paramsStr = window.location.search | ||
167 | - const params = new URLSearchParams(paramsStr) | ||
168 | - const file_uuid = params.get('three_file_uuid') | ||
169 | - await saveOrUpdateThreeJsModel({ | ||
170 | - id: file_uuid, | ||
171 | - imageUrl: uploadRes?.fileDownloadUri, | ||
172 | - data: file_json | ||
173 | - }) | ||
174 | - const { success } = useMessage() | ||
175 | - success('保存成功') | 152 | + const { spin, stop } = useSpin() |
153 | + try { | ||
154 | + spin() | ||
155 | + // 生成图片 | ||
156 | + const canvasImage = await html2canvas(range, { | ||
157 | + backgroundColor: null, | ||
158 | + allowTaint: true, | ||
159 | + useCORS: true, | ||
160 | + logging: false | ||
161 | + }) | ||
162 | + // 上传预览图 | ||
163 | + const uploadParams = new FormData() | ||
164 | + uploadParams.append( | ||
165 | + 'file', | ||
166 | + base64toFile(canvasImage.toDataURL(), `${fetchRouteParamsLocation()}_index_preview.png`) | ||
167 | + ) | ||
168 | + const uploadRes = await uploadFile(uploadParams) | ||
169 | + const file_json = editor.toJSON() | ||
170 | + const paramsStr = window.location.search | ||
171 | + const params = new URLSearchParams(paramsStr) | ||
172 | + const file_uuid = params.get('three_file_uuid') | ||
173 | + console.log(file_json) | ||
174 | + await saveOrUpdateThreeJsModel({ | ||
175 | + id: file_uuid, | ||
176 | + imageUrl: uploadRes?.fileDownloadUri, | ||
177 | + data: file_json | ||
178 | + }) | ||
179 | + const { success } = useMessage() | ||
180 | + success('保存成功') | ||
181 | + } finally { | ||
182 | + stop() | ||
183 | + } | ||
176 | }) | 184 | }) |
177 | options.add(option) | 185 | options.add(option) |
178 | 186 |
@@ -8,10 +8,13 @@ const API = { | @@ -8,10 +8,13 @@ const API = { | ||
8 | * @description: 3D模型 保存 api | 8 | * @description: 3D模型 保存 api |
9 | */ | 9 | */ |
10 | export function saveOrUpdateThreeJsModel(params) { | 10 | export function saveOrUpdateThreeJsModel(params) { |
11 | - return defHttp.post({ | ||
12 | - url: `${API['URL']}?id=${params['id']}&imageUrl=${params['imageUrl']}`, | ||
13 | - data: params['data'] | ||
14 | - }) | 11 | + return defHttp.post( |
12 | + { | ||
13 | + url: `${API['URL']}?id=${params['id']}&imageUrl=${params['imageUrl']}`, | ||
14 | + data: params['data'], | ||
15 | + timeout: 30 * 1000 | ||
16 | + }, | ||
17 | + ) | ||
15 | } | 18 | } |
16 | 19 | ||
17 | /** | 20 | /** |
editor/js/libs/spin/spin.css
0 → 100644
1 | +/** | ||
2 | + * Minified by jsDelivr using clean-css v5.3.2. | ||
3 | + * Original file: /npm/spin.js@4.1.2/spin.css | ||
4 | + * | ||
5 | + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files | ||
6 | + */ | ||
7 | +@keyframes spinner-line-fade-more { | ||
8 | + | ||
9 | + 0%, | ||
10 | + 100% { | ||
11 | + opacity: 0 | ||
12 | + } | ||
13 | + | ||
14 | + 1% { | ||
15 | + opacity: 1 | ||
16 | + } | ||
17 | +} | ||
18 | + | ||
19 | +@keyframes spinner-line-fade-quick { | ||
20 | + | ||
21 | + 0%, | ||
22 | + 100%, | ||
23 | + 39% { | ||
24 | + opacity: .25 | ||
25 | + } | ||
26 | + | ||
27 | + 40% { | ||
28 | + opacity: 1 | ||
29 | + } | ||
30 | +} | ||
31 | + | ||
32 | +@keyframes spinner-line-fade-default { | ||
33 | + | ||
34 | + 0%, | ||
35 | + 100% { | ||
36 | + opacity: .22 | ||
37 | + } | ||
38 | + | ||
39 | + 1% { | ||
40 | + opacity: 1 | ||
41 | + } | ||
42 | +} | ||
43 | + | ||
44 | +@keyframes spinner-line-shrink { | ||
45 | + | ||
46 | + 0%, | ||
47 | + 100%, | ||
48 | + 25% { | ||
49 | + transform: scale(.5); | ||
50 | + opacity: .25 | ||
51 | + } | ||
52 | + | ||
53 | + 26% { | ||
54 | + transform: scale(1); | ||
55 | + opacity: 1 | ||
56 | + } | ||
57 | +} | ||
58 | + | ||
59 | +/*# sourceMappingURL=/sm/1d0379dd77ad25552d64b70cd02d2d2833a1804214c1f482eb413fd2b8c115d4.map */ |
editor/js/libs/spin/spin.js
0 → 100644
1 | +/** | ||
2 | + * Minified by jsDelivr using Terser v5.19.2. | ||
3 | + * Original file: /npm/spin.js@4.1.2/spin.js | ||
4 | + * | ||
5 | + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files | ||
6 | + */ | ||
7 | +var __assign = this && this.__assign || function () { | ||
8 | + return __assign = Object.assign || function (t) { | ||
9 | + for (var e, s = 1, n = arguments.length; s < n; s++) | ||
10 | + for (var i in e = arguments[s]) | ||
11 | + Object.prototype.hasOwnProperty.call(e, i) && (t[i] = e[i]); | ||
12 | + return t | ||
13 | + } | ||
14 | + , | ||
15 | + __assign.apply(this, arguments) | ||
16 | +} | ||
17 | + , defaults = { | ||
18 | + lines: 12, | ||
19 | + length: 7, | ||
20 | + width: 5, | ||
21 | + radius: 10, | ||
22 | + scale: 1, | ||
23 | + corners: 1, | ||
24 | + color: "#000", | ||
25 | + fadeColor: "transparent", | ||
26 | + animation: "spinner-line-fade-default", | ||
27 | + rotate: 0, | ||
28 | + direction: 1, | ||
29 | + speed: 1, | ||
30 | + zIndex: 2e9, | ||
31 | + className: "spinner", | ||
32 | + top: "50%", | ||
33 | + left: "50%", | ||
34 | + shadow: "0 0 1px transparent", | ||
35 | + position: "absolute" | ||
36 | + } | ||
37 | + , Spinner = function () { | ||
38 | + function t(t) { | ||
39 | + void 0 === t && (t = {}), | ||
40 | + this.opts = __assign(__assign({}, defaults), t) | ||
41 | + } | ||
42 | + return t.prototype.spin = function (t) { | ||
43 | + return this.stop(), | ||
44 | + this.el = document.createElement("div"), | ||
45 | + this.el.className = this.opts.className, | ||
46 | + this.el.setAttribute("role", "progressbar"), | ||
47 | + this.el.style.position = this.opts.position, | ||
48 | + this.el.style.width = "0", | ||
49 | + this.el.style.zIndex = this.opts.zIndex.toString(), | ||
50 | + this.el.style.left = this.opts.left, | ||
51 | + this.el.style.top = this.opts.top, | ||
52 | + this.el.style.transform = "scale(".concat(this.opts.scale, ")"), | ||
53 | + t && t.insertBefore(this.el, t.firstChild || null), | ||
54 | + drawLines(this.el, this.opts), | ||
55 | + this | ||
56 | + } | ||
57 | + , | ||
58 | + t.prototype.stop = function () { | ||
59 | + return this.el && (this.el.parentNode && this.el.parentNode.removeChild(this.el), | ||
60 | + this.el = void 0), | ||
61 | + this | ||
62 | + } | ||
63 | + , | ||
64 | + t | ||
65 | + }(); | ||
66 | +export { Spinner }; | ||
67 | +function getColor(t, e) { | ||
68 | + return "string" == typeof t ? t : t[e % t.length] | ||
69 | +} | ||
70 | +function drawLines(t, e) { | ||
71 | + var s = Math.round(e.corners * e.width * 500) / 1e3 + "px" | ||
72 | + , n = "none"; | ||
73 | + !0 === e.shadow ? n = "0 2px 4px #000" : "string" == typeof e.shadow && (n = e.shadow); | ||
74 | + for (var i = parseBoxShadow(n), o = 0; o < e.lines; o++) { | ||
75 | + var r = ~~(360 / e.lines * o + e.rotate) | ||
76 | + , a = document.createElement("div"); | ||
77 | + a.style.position = "absolute", | ||
78 | + a.style.top = "".concat(-e.width / 2, "px"), | ||
79 | + a.style.width = e.length + e.width + "px", | ||
80 | + a.style.height = e.width + "px", | ||
81 | + a.style.background = getColor(e.fadeColor, o), | ||
82 | + a.style.borderRadius = s, | ||
83 | + a.style.transformOrigin = "left", | ||
84 | + a.style.transform = "rotate(".concat(r, "deg) translateX(").concat(e.radius, "px)"); | ||
85 | + var l = o * e.direction / e.lines / e.speed; | ||
86 | + l -= 1 / e.speed; | ||
87 | + var h = document.createElement("div"); | ||
88 | + h.style.width = "100%", | ||
89 | + h.style.height = "100%", | ||
90 | + h.style.background = getColor(e.color, o), | ||
91 | + h.style.borderRadius = s, | ||
92 | + h.style.boxShadow = normalizeShadow(i, r), | ||
93 | + h.style.animation = "".concat(1 / e.speed, "s linear ").concat(l, "s infinite ").concat(e.animation), | ||
94 | + a.appendChild(h), | ||
95 | + t.appendChild(a) | ||
96 | + } | ||
97 | +} | ||
98 | +function parseBoxShadow(t) { | ||
99 | + for (var e = /^\s*([a-zA-Z]+\s+)?(-?\d+(\.\d+)?)([a-zA-Z]*)\s+(-?\d+(\.\d+)?)([a-zA-Z]*)(.*)$/, s = [], n = 0, i = t.split(","); n < i.length; n++) { | ||
100 | + var o = i[n].match(e); | ||
101 | + if (null !== o) { | ||
102 | + var r = +o[2] | ||
103 | + , a = +o[5] | ||
104 | + , l = o[4] | ||
105 | + , h = o[7]; | ||
106 | + 0 !== r || l || (l = h), | ||
107 | + 0 !== a || h || (h = l), | ||
108 | + l === h && s.push({ | ||
109 | + prefix: o[1] || "", | ||
110 | + x: r, | ||
111 | + y: a, | ||
112 | + xUnits: l, | ||
113 | + yUnits: h, | ||
114 | + end: o[8] | ||
115 | + }) | ||
116 | + } | ||
117 | + } | ||
118 | + return s | ||
119 | +} | ||
120 | +function normalizeShadow(t, e) { | ||
121 | + for (var s = [], n = 0, i = t; n < i.length; n++) { | ||
122 | + var o = i[n] | ||
123 | + , r = convertOffset(o.x, o.y, e); | ||
124 | + s.push(o.prefix + r[0] + o.xUnits + " " + r[1] + o.yUnits + o.end) | ||
125 | + } | ||
126 | + return s.join(", ") | ||
127 | +} | ||
128 | +function convertOffset(t, e, s) { | ||
129 | + var n = s * Math.PI / 180 | ||
130 | + , i = Math.sin(n) | ||
131 | + , o = Math.cos(n); | ||
132 | + return [Math.round(1e3 * (t * o + e * i)) / 1e3, Math.round(1e3 * (-t * i + e * o)) / 1e3] | ||
133 | +} | ||
134 | +//# sourceMappingURL=/sm/6ba007f8215048c7e8c098294081de9cb1287363cf4b90ab212f48050f156783.map |
editor/js/libs/spin/useSpin.js
0 → 100644
1 | +import { Spinner } from './spin' | ||
2 | + | ||
3 | +export function useSpin(el = 'viewport') { | ||
4 | + const target = el instanceof Element ? el : document.getElementById(el) | ||
5 | + const spinner = new Spinner({ color: '#fff', lines: 12 }); | ||
6 | + const mask = createMask() | ||
7 | + | ||
8 | + function createMask() { | ||
9 | + const mask = document.createElement('div') | ||
10 | + mask.style.position = 'absolute' | ||
11 | + mask.style.inset = 0 | ||
12 | + mask.style.display = 'flex' | ||
13 | + mask.style.alignItems = 'center' | ||
14 | + mask.style.justifyContent = 'center' | ||
15 | + mask.style.backgroundColor = 'rgba(0, 0, 0, 0.5)' | ||
16 | + mask.style.cursor = 'pointer' | ||
17 | + mask.style.pointerEvents = 'none' | ||
18 | + | ||
19 | + return mask | ||
20 | + } | ||
21 | + | ||
22 | + function spin() { | ||
23 | + if (!target) { | ||
24 | + throw new Error('Spin not found target') | ||
25 | + } | ||
26 | + | ||
27 | + target.appendChild(mask) | ||
28 | + spinner.spin(target) | ||
29 | + } | ||
30 | + | ||
31 | + function stop() { | ||
32 | + spinner.stop() | ||
33 | + target.removeChild(mask) | ||
34 | + } | ||
35 | + | ||
36 | + return { | ||
37 | + spin, | ||
38 | + stop | ||
39 | + } | ||
40 | +} |
@@ -9,6 +9,7 @@ import { Sidebar } from './js/Sidebar.js' | @@ -9,6 +9,7 @@ import { Sidebar } from './js/Sidebar.js' | ||
9 | import { Menubar } from './js/Menubar.js' | 9 | import { Menubar } from './js/Menubar.js' |
10 | import { Resizer } from './js/Resizer.js' | 10 | import { Resizer } from './js/Resizer.js' |
11 | import { getThreeJsModel } from './js/libs/http/api.js' | 11 | import { getThreeJsModel } from './js/libs/http/api.js' |
12 | +import { useSpin } from './js/libs/spin/useSpin.js' | ||
12 | 13 | ||
13 | window.URL = window.URL || window.webkitURL | 14 | window.URL = window.URL || window.webkitURL |
14 | window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder | 15 | window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder |
@@ -53,10 +54,18 @@ editor.storage.init(async function () { | @@ -53,10 +54,18 @@ editor.storage.init(async function () { | ||
53 | const file_uuid = params.get('three_file_uuid') | 54 | const file_uuid = params.get('three_file_uuid') |
54 | const actionType = params.get('action_type') | 55 | const actionType = params.get('action_type') |
55 | if (actionType === 'create') return | 56 | if (actionType === 'create') return |
56 | - const fileData = await getThreeJsModel(file_uuid) | ||
57 | - if (!fileData) return | ||
58 | - if (!fileData['content']) return | ||
59 | - await editor.fromJSON(fileData['content']) | 57 | + |
58 | + const { spin, stop } = useSpin() | ||
59 | + try { | ||
60 | + spin() | ||
61 | + const fileData = await getThreeJsModel(file_uuid) | ||
62 | + if (!fileData) return | ||
63 | + if (!fileData['content']) return | ||
64 | + await editor.fromJSON(fileData['content']) | ||
65 | + } finally { | ||
66 | + stop() | ||
67 | + } | ||
68 | + | ||
60 | const selected = editor.config.getKey('selected') | 69 | const selected = editor.config.getKey('selected') |
61 | if (selected !== undefined) { | 70 | if (selected !== undefined) { |
62 | editor.selectByUuid(selected) | 71 | editor.selectByUuid(selected) |
@@ -214,5 +223,5 @@ if (hash.slice(1, 6) === 'file=') { | @@ -214,5 +223,5 @@ if (hash.slice(1, 6) === 'file=') { | ||
214 | if ('serviceWorker' in navigator) { | 223 | if ('serviceWorker' in navigator) { |
215 | try { | 224 | try { |
216 | navigator.serviceWorker.register('sw.js') | 225 | navigator.serviceWorker.register('sw.js') |
217 | - } catch (error) {} | 226 | + } catch (error) { } |
218 | } | 227 | } |