Showing
7 changed files
with
289 additions
and
35 deletions
... | ... | @@ -8,6 +8,7 @@ |
8 | 8 | |
9 | 9 | <body> |
10 | 10 | <link rel="stylesheet" href="css/main.css" /> |
11 | + <link rel="stylesheet" href="./js/libs/spin/spin.css"> | |
11 | 12 | <link rel="stylesheet" href="js/libs/codemirror/codemirror.css" /> |
12 | 13 | <link rel="stylesheet" href="js/libs/codemirror/theme/monokai.css" /> |
13 | 14 | <link rel="stylesheet" href="js/libs/codemirror/addon/dialog.css" /> | ... | ... |
... | ... | @@ -5,6 +5,7 @@ import html2canvas from 'html2canvas' |
5 | 5 | import { fetchRouteParamsLocation } from '@/utils' |
6 | 6 | import { uploadFile } from '@/api/external/contentSave/content' |
7 | 7 | import { base64toFile } from '../utils/Base64ToFile.js' |
8 | +import { useSpin } from '../js/libs/spin/useSpin.js' | |
8 | 9 | |
9 | 10 | function MenubarFile(editor) { |
10 | 11 | const strings = editor.strings |
... | ... | @@ -72,7 +73,7 @@ function MenubarFile(editor) { |
72 | 73 | const loader = new THREE.FileLoader() |
73 | 74 | |
74 | 75 | for (let i = 0; i < examples.length; i++) { |
75 | - ;(function (i) { | |
76 | + ; (function (i) { | |
76 | 77 | const example = examples[i] |
77 | 78 | |
78 | 79 | const option = new UIRow() |
... | ... | @@ -148,31 +149,38 @@ function MenubarFile(editor) { |
148 | 149 | .onClick(async function () { |
149 | 150 | // 获取缩略图片 |
150 | 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 | 185 | options.add(option) |
178 | 186 | ... | ... |
... | ... | @@ -8,10 +8,13 @@ const API = { |
8 | 8 | * @description: 3D模型 保存 api |
9 | 9 | */ |
10 | 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 | 9 | import { Menubar } from './js/Menubar.js' |
10 | 10 | import { Resizer } from './js/Resizer.js' |
11 | 11 | import { getThreeJsModel } from './js/libs/http/api.js' |
12 | +import { useSpin } from './js/libs/spin/useSpin.js' | |
12 | 13 | |
13 | 14 | window.URL = window.URL || window.webkitURL |
14 | 15 | window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder |
... | ... | @@ -53,10 +54,18 @@ editor.storage.init(async function () { |
53 | 54 | const file_uuid = params.get('three_file_uuid') |
54 | 55 | const actionType = params.get('action_type') |
55 | 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 | 69 | const selected = editor.config.getKey('selected') |
61 | 70 | if (selected !== undefined) { |
62 | 71 | editor.selectByUuid(selected) |
... | ... | @@ -214,5 +223,5 @@ if (hash.slice(1, 6) === 'file=') { |
214 | 223 | if ('serviceWorker' in navigator) { |
215 | 224 | try { |
216 | 225 | navigator.serviceWorker.register('sw.js') |
217 | - } catch (error) {} | |
226 | + } catch (error) { } | |
218 | 227 | } | ... | ... |