UNPKG

zyy-free-layout

Version:

[vue3+ts]自由拖动布局

1,091 lines (987 loc) 33.6 kB
import { provide, reactive, unref, inject, defineComponent, computed, h, ref, onMounted, watch, onBeforeUnmount } from 'vue'; var WidgetState; (function(WidgetState2) { WidgetState2[WidgetState2["notAdded"] = -1] = "notAdded"; WidgetState2[WidgetState2["normal"] = 0] = "normal"; WidgetState2[WidgetState2["selected"] = 1] = "selected"; })(WidgetState || (WidgetState = {})); function onMouseMove(onMoveStart, onMove, onMoveEnd) { let isFirst = true; let isMove = false; const moMouseMove = (event) => { if (isFirst) { onMoveStart && onMoveStart(event); isFirst = false; isMove = true; } onMove && onMove(event); }; const onMouseup = (event) => { window.removeEventListener("mousemove", moMouseMove); window.removeEventListener("mouseup", onMouseup); isMove && onMoveEnd && onMoveEnd(event); }; window.addEventListener("mousemove", moMouseMove); window.addEventListener("mouseup", onMouseup); } class Widget { constructor(options, service) { this.service = service; this.container = null; this.levels = 0; this.dragOffset = { x: 0, y: 0 }; this.id = options.id; this.tag = options.tag; this.x = Math.floor(options.x); this.y = Math.floor(options.y); this.width = Math.floor(options.width); this.height = Math.floor(options.height); this.state = options.state; this.disableDrag = options.disableDrag; this.disableResize = options.disableResize; this.moving = options.moving; this.resizing = options.resizing; this.customDragNode = options.customDragNode; options.levels !== void 0 && (this.levels = options.levels); options.dragOffset && (this.dragOffset = options.dragOffset); options.initState && (this.initState = options.initState); } setOptions(options) { Object.assign(this, Object.assign(Object.assign({}, options), { x: Math.floor(options.x), y: Math.floor(options.y), width: Math.floor(options.width), height: Math.floor(options.height) })); } setPosition(x, y) { this.x = Math.floor(x); this.y = Math.floor(y); } setSize(width, height) { this.width = Math.floor(width); this.height = Math.floor(height); } toJson() { return { id: this.id, tag: this.tag, x: this.x, y: this.y, width: this.width, height: this.height, state: this.state, disableDrag: this.disableDrag, disableResize: this.disableResize, moving: this.moving, resizing: this.resizing, dragOffset: this.dragOffset, levels: this.levels, customDragNode: this.customDragNode, initState: this.initState }; } startDrag(startEvent) { if (this.disableDrag) return; const res = !this.service.dragService || this.service.dragService.widgetMouseDown({ service: this.service, widget: this, event: startEvent, startEvent }); if (!res) return; onMouseMove(() => { const { x, y } = this.service.mousePToPageP(startEvent.clientX, startEvent.clientY); this.dragOffset.x = x - this.x; this.dragOffset.y = y - this.y; this.moving = true; this.service.dragService && this.service.dragService.widgetMoveStart(this.toJson(), { service: this.service, widget: this, event: startEvent, startEvent }); this.service.$emit("drag-start", this); }, (event) => { const { x, y } = this.service.mousePToPageP(event.clientX, event.clientY); const option = this.toJson(); option.x = x - this.dragOffset.x; option.y = y - this.dragOffset.y; const result = this.service.dragService ? this.service.dragService.widgetMove(option, { service: this.service, widget: this, event, startEvent }) : option; if (!result) return; this.setOptions(result); this.service.$emit("moving", this); }, (event) => { const { x, y } = this.service.mousePToPageP(event.clientX, event.clientY); const option = this.toJson(); option.x = x - this.dragOffset.x; option.y = y - this.dragOffset.y; option.moving = false; const result = this.service.dragService ? this.service.dragService.widgetMoveEnd(option, { service: this.service, widget: this, event, startEvent }) : option; if (!result) return; this.setOptions(result); this.service.$emit("moved", this); }); } } // Unique ID creation requires a high quality random # generator. In the browser we therefore // require the crypto API and do not support built-in fallback to lower quality random number // generators (like Math.random()). let getRandomValues; const rnds8 = new Uint8Array(16); function rng() { // lazy load so that environments that need to polyfill have a chance to do so if (!getRandomValues) { // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto); if (!getRandomValues) { throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported'); } } return getRandomValues(rnds8); } var REGEX = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; function validate(uuid) { return typeof uuid === 'string' && REGEX.test(uuid); } /** * Convert array of 16 byte values to UUID string format of the form: * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */ const byteToHex = []; for (let i = 0; i < 256; ++i) { byteToHex.push((i + 0x100).toString(16).slice(1)); } function unsafeStringify(arr, offset = 0) { // Note: Be careful editing this code! It's been tuned for performance // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]; } function parse(uuid) { if (!validate(uuid)) { throw TypeError('Invalid UUID'); } let v; const arr = new Uint8Array(16); // Parse ########-....-....-....-............ arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24; arr[1] = v >>> 16 & 0xff; arr[2] = v >>> 8 & 0xff; arr[3] = v & 0xff; // Parse ........-####-....-....-............ arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8; arr[5] = v & 0xff; // Parse ........-....-####-....-............ arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8; arr[7] = v & 0xff; // Parse ........-....-....-####-............ arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8; arr[9] = v & 0xff; // Parse ........-....-....-....-############ // (Use "/" to avoid 32-bit truncation when bit-shifting high-order bytes) arr[10] = (v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000 & 0xff; arr[11] = v / 0x100000000 & 0xff; arr[12] = v >>> 24 & 0xff; arr[13] = v >>> 16 & 0xff; arr[14] = v >>> 8 & 0xff; arr[15] = v & 0xff; return arr; } function stringToBytes(str) { str = unescape(encodeURIComponent(str)); // UTF8 escape const bytes = []; for (let i = 0; i < str.length; ++i) { bytes.push(str.charCodeAt(i)); } return bytes; } const DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'; const URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; function v35(name, version, hashfunc) { function generateUUID(value, namespace, buf, offset) { var _namespace; if (typeof value === 'string') { value = stringToBytes(value); } if (typeof namespace === 'string') { namespace = parse(namespace); } if (((_namespace = namespace) === null || _namespace === void 0 ? void 0 : _namespace.length) !== 16) { throw TypeError('Namespace must be array-like (16 iterable integer values, 0-255)'); } // Compute hash of namespace and value, Per 4.3 // Future: Use spread syntax when supported on all platforms, e.g. `bytes = // hashfunc([...namespace, ... value])` let bytes = new Uint8Array(16 + value.length); bytes.set(namespace); bytes.set(value, namespace.length); bytes = hashfunc(bytes); bytes[6] = bytes[6] & 0x0f | version; bytes[8] = bytes[8] & 0x3f | 0x80; if (buf) { offset = offset || 0; for (let i = 0; i < 16; ++i) { buf[offset + i] = bytes[i]; } return buf; } return unsafeStringify(bytes); } // Function#name is not settable on some platforms (#270) try { generateUUID.name = name; // eslint-disable-next-line no-empty } catch (err) {} // For CommonJS default export support generateUUID.DNS = DNS; generateUUID.URL = URL; return generateUUID; } /* * Browser-compatible JavaScript MD5 * * Modification of JavaScript MD5 * https://github.com/blueimp/JavaScript-MD5 * * Copyright 2011, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: * https://opensource.org/licenses/MIT * * Based on * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message * Digest Algorithm, as defined in RFC 1321. * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet * Distributed under the BSD License * See http://pajhome.org.uk/crypt/md5 for more info. */ function md5(bytes) { if (typeof bytes === 'string') { const msg = unescape(encodeURIComponent(bytes)); // UTF8 escape bytes = new Uint8Array(msg.length); for (let i = 0; i < msg.length; ++i) { bytes[i] = msg.charCodeAt(i); } } return md5ToHexEncodedArray(wordsToMd5(bytesToWords(bytes), bytes.length * 8)); } /* * Convert an array of little-endian words to an array of bytes */ function md5ToHexEncodedArray(input) { const output = []; const length32 = input.length * 32; const hexTab = '0123456789abcdef'; for (let i = 0; i < length32; i += 8) { const x = input[i >> 5] >>> i % 32 & 0xff; const hex = parseInt(hexTab.charAt(x >>> 4 & 0x0f) + hexTab.charAt(x & 0x0f), 16); output.push(hex); } return output; } /** * Calculate output length with padding and bit length */ function getOutputLength(inputLength8) { return (inputLength8 + 64 >>> 9 << 4) + 14 + 1; } /* * Calculate the MD5 of an array of little-endian words, and a bit length. */ function wordsToMd5(x, len) { /* append padding */ x[len >> 5] |= 0x80 << len % 32; x[getOutputLength(len) - 1] = len; let a = 1732584193; let b = -271733879; let c = -1732584194; let d = 271733878; for (let i = 0; i < x.length; i += 16) { const olda = a; const oldb = b; const oldc = c; const oldd = d; a = md5ff(a, b, c, d, x[i], 7, -680876936); d = md5ff(d, a, b, c, x[i + 1], 12, -389564586); c = md5ff(c, d, a, b, x[i + 2], 17, 606105819); b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330); a = md5ff(a, b, c, d, x[i + 4], 7, -176418897); d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426); c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341); b = md5ff(b, c, d, a, x[i + 7], 22, -45705983); a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416); d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417); c = md5ff(c, d, a, b, x[i + 10], 17, -42063); b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162); a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682); d = md5ff(d, a, b, c, x[i + 13], 12, -40341101); c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290); b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329); a = md5gg(a, b, c, d, x[i + 1], 5, -165796510); d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632); c = md5gg(c, d, a, b, x[i + 11], 14, 643717713); b = md5gg(b, c, d, a, x[i], 20, -373897302); a = md5gg(a, b, c, d, x[i + 5], 5, -701558691); d = md5gg(d, a, b, c, x[i + 10], 9, 38016083); c = md5gg(c, d, a, b, x[i + 15], 14, -660478335); b = md5gg(b, c, d, a, x[i + 4], 20, -405537848); a = md5gg(a, b, c, d, x[i + 9], 5, 568446438); d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690); c = md5gg(c, d, a, b, x[i + 3], 14, -187363961); b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501); a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467); d = md5gg(d, a, b, c, x[i + 2], 9, -51403784); c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473); b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734); a = md5hh(a, b, c, d, x[i + 5], 4, -378558); d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463); c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562); b = md5hh(b, c, d, a, x[i + 14], 23, -35309556); a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060); d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353); c = md5hh(c, d, a, b, x[i + 7], 16, -155497632); b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640); a = md5hh(a, b, c, d, x[i + 13], 4, 681279174); d = md5hh(d, a, b, c, x[i], 11, -358537222); c = md5hh(c, d, a, b, x[i + 3], 16, -722521979); b = md5hh(b, c, d, a, x[i + 6], 23, 76029189); a = md5hh(a, b, c, d, x[i + 9], 4, -640364487); d = md5hh(d, a, b, c, x[i + 12], 11, -421815835); c = md5hh(c, d, a, b, x[i + 15], 16, 530742520); b = md5hh(b, c, d, a, x[i + 2], 23, -995338651); a = md5ii(a, b, c, d, x[i], 6, -198630844); d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415); c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905); b = md5ii(b, c, d, a, x[i + 5], 21, -57434055); a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571); d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606); c = md5ii(c, d, a, b, x[i + 10], 15, -1051523); b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799); a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359); d = md5ii(d, a, b, c, x[i + 15], 10, -30611744); c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380); b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649); a = md5ii(a, b, c, d, x[i + 4], 6, -145523070); d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379); c = md5ii(c, d, a, b, x[i + 2], 15, 718787259); b = md5ii(b, c, d, a, x[i + 9], 21, -343485551); a = safeAdd(a, olda); b = safeAdd(b, oldb); c = safeAdd(c, oldc); d = safeAdd(d, oldd); } return [a, b, c, d]; } /* * Convert an array bytes to an array of little-endian words * Characters >255 have their high-byte silently ignored. */ function bytesToWords(input) { if (input.length === 0) { return []; } const length8 = input.length * 8; const output = new Uint32Array(getOutputLength(length8)); for (let i = 0; i < length8; i += 8) { output[i >> 5] |= (input[i / 8] & 0xff) << i % 32; } return output; } /* * Add integers, wrapping at 2^32. This uses 16-bit operations internally * to work around bugs in some JS interpreters. */ function safeAdd(x, y) { const lsw = (x & 0xffff) + (y & 0xffff); const msw = (x >> 16) + (y >> 16) + (lsw >> 16); return msw << 16 | lsw & 0xffff; } /* * Bitwise rotate a 32-bit number to the left. */ function bitRotateLeft(num, cnt) { return num << cnt | num >>> 32 - cnt; } /* * These functions implement the four basic operations the algorithm uses. */ function md5cmn(q, a, b, x, s, t) { return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b); } function md5ff(a, b, c, d, x, s, t) { return md5cmn(b & c | ~b & d, a, b, x, s, t); } function md5gg(a, b, c, d, x, s, t) { return md5cmn(b & d | c & ~d, a, b, x, s, t); } function md5hh(a, b, c, d, x, s, t) { return md5cmn(b ^ c ^ d, a, b, x, s, t); } function md5ii(a, b, c, d, x, s, t) { return md5cmn(c ^ (b | ~d), a, b, x, s, t); } v35('v3', 0x30, md5); const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto); var native = { randomUUID }; function v4(options, buf, offset) { if (native.randomUUID && !buf && !options) { return native.randomUUID(); } options = options || {}; const rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` rnds[6] = rnds[6] & 0x0f | 0x40; rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided if (buf) { offset = offset || 0; for (let i = 0; i < 16; ++i) { buf[offset + i] = rnds[i]; } return buf; } return unsafeStringify(rnds); } // Adapted from Chris Veness' SHA1 code at // http://www.movable-type.co.uk/scripts/sha1.html function f(s, x, y, z) { switch (s) { case 0: return x & y ^ ~x & z; case 1: return x ^ y ^ z; case 2: return x & y ^ x & z ^ y & z; case 3: return x ^ y ^ z; } } function ROTL(x, n) { return x << n | x >>> 32 - n; } function sha1(bytes) { const K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6]; const H = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0]; if (typeof bytes === 'string') { const msg = unescape(encodeURIComponent(bytes)); // UTF8 escape bytes = []; for (let i = 0; i < msg.length; ++i) { bytes.push(msg.charCodeAt(i)); } } else if (!Array.isArray(bytes)) { // Convert Array-like to Array bytes = Array.prototype.slice.call(bytes); } bytes.push(0x80); const l = bytes.length / 4 + 2; const N = Math.ceil(l / 16); const M = new Array(N); for (let i = 0; i < N; ++i) { const arr = new Uint32Array(16); for (let j = 0; j < 16; ++j) { arr[j] = bytes[i * 64 + j * 4] << 24 | bytes[i * 64 + j * 4 + 1] << 16 | bytes[i * 64 + j * 4 + 2] << 8 | bytes[i * 64 + j * 4 + 3]; } M[i] = arr; } M[N - 1][14] = (bytes.length - 1) * 8 / Math.pow(2, 32); M[N - 1][14] = Math.floor(M[N - 1][14]); M[N - 1][15] = (bytes.length - 1) * 8 & 0xffffffff; for (let i = 0; i < N; ++i) { const W = new Uint32Array(80); for (let t = 0; t < 16; ++t) { W[t] = M[i][t]; } for (let t = 16; t < 80; ++t) { W[t] = ROTL(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1); } let a = H[0]; let b = H[1]; let c = H[2]; let d = H[3]; let e = H[4]; for (let t = 0; t < 80; ++t) { const s = Math.floor(t / 20); const T = ROTL(a, 5) + f(s, b, c, d) + e + K[s] + W[t] >>> 0; e = d; d = c; c = ROTL(b, 30) >>> 0; b = a; a = T; } H[0] = H[0] + a >>> 0; H[1] = H[1] + b >>> 0; H[2] = H[2] + c >>> 0; H[3] = H[3] + d >>> 0; H[4] = H[4] + e >>> 0; } return [H[0] >> 24 & 0xff, H[0] >> 16 & 0xff, H[0] >> 8 & 0xff, H[0] & 0xff, H[1] >> 24 & 0xff, H[1] >> 16 & 0xff, H[1] >> 8 & 0xff, H[1] & 0xff, H[2] >> 24 & 0xff, H[2] >> 16 & 0xff, H[2] >> 8 & 0xff, H[2] & 0xff, H[3] >> 24 & 0xff, H[3] >> 16 & 0xff, H[3] >> 8 & 0xff, H[3] & 0xff, H[4] >> 24 & 0xff, H[4] >> 16 & 0xff, H[4] >> 8 & 0xff, H[4] & 0xff]; } v35('v5', 0x50, sha1); class FreeLayoutService { constructor(options, container, $emit, renderWidget, dragService) { this.container = container; this.$emit = $emit; this.renderWidget = renderWidget; this.options = { width: 500, height: 300, unit: "px", disableDrag: false, disableResize: false }; provide(FreeLayoutService.token, this); this.setDragService(dragService); this.options = Object.assign(this.options, options); this.model = reactive({ pageRect: { x: 0, y: 0, width: this.options.width, height: this.options.height }, newWidget: null, widgets: [], selectedArea: null }); } setDragService(dragService) { var _a; this.dragService = dragService; (_a = this.dragService) === null || _a === void 0 ? void 0 : _a.registerFreeService(this); } getRect() { return this.model.pageRect; } setPosition(x, y) { if (x !== void 0) { this.model.pageRect.x = x; } if (y !== void 0) { this.model.pageRect.y = y; } } setSize(width, height) { if (width !== void 0) { this.model.pageRect.width = width; } if (height !== void 0) { this.model.pageRect.height = height; } } createNewWidget(option, startEvent) { const id = option.id || v4(); const options = Object.assign(Object.assign({}, option), { id, x: 0, y: 0, state: WidgetState.notAdded, moving: true }); const widget = new Widget(options, this); onMouseMove(void 0, (event) => { var _a, _b; const { x, y } = this.mousePToPageP(event.clientX, event.clientY); options.x = x - (((_a = options.dragOffset) === null || _a === void 0 ? void 0 : _a.x) || 0); options.y = y - (((_b = options.dragOffset) === null || _b === void 0 ? void 0 : _b.y) || 0); const result = this.dragService ? this.dragService.newWidgetMove(options, { service: this, widget: this.model.newWidget || widget, event, startEvent }) : options; if (!result) return; if (!this.model.newWidget) { widget.setOptions(result); this.model.newWidget = widget; this.$emit("createWidget", this.model.newWidget); } else { this.model.newWidget.setOptions(result); } }, (event) => { const options2 = this.model.newWidget.toJson(); options2.state = WidgetState.normal; options2.moving = false; const result = this.dragService ? this.dragService.newWidgetMoveEnd(options2, { service: this, widget: this.model.newWidget, event, startEvent }) : options2; this.deleteNewWidget(); if (!result) return; this.addWidget(result); this.$emit("attached", widget); }); } deleteNewWidget() { this.model.newWidget = null; } addWidget(options) { const widget = new Widget(options, this); if (this.options.disableDrag) { widget.disableDrag = this.options.disableDrag; } else { widget.disableDrag = options.disableDrag; } if (this.options.disableResize) { widget.disableResize = this.options.disableResize; } else { widget.disableResize = options.disableResize; } this.model.widgets.push(widget); return widget; } getWidgets() { return this.model.widgets; } getWidget(id) { return this.model.widgets.find((widget) => widget.id === id); } deleteWidget(id) { const idx = this.model.widgets.findIndex((widget) => widget.id === id); if (idx > -1) { const delWidget = this.model.widgets.splice(idx, 1); this.$emit("delete", delWidget[0]); } } clearWidget() { this.model.widgets = []; } createSelectedArea() { this.model.selectedArea = null; this.clearSelectedWidgets(); const startPoint = { x: 0, y: 0 }; onMouseMove((event) => { const { x, y } = this.mousePToPageP(event.clientX, event.clientY); startPoint.x = x; startPoint.y = y; }, (event) => { const { x, y } = this.mousePToPageP(event.clientX, event.clientY); const width = Math.abs(x - startPoint.x); const height = Math.abs(y - startPoint.y); const areaPoint = { x: 0, y: 0 }; if (startPoint.x < x) { areaPoint.x = startPoint.x; } else { areaPoint.x = x; } if (startPoint.y < y) { areaPoint.y = startPoint.y; } else { areaPoint.y = y; } if (!this.model.selectedArea) { this.model.selectedArea = { x: areaPoint.x, y: areaPoint.y, width, height }; } else { this.model.selectedArea.x = areaPoint.x; this.model.selectedArea.y = areaPoint.y; this.model.selectedArea.width = width; this.model.selectedArea.height = height; } this.setSelectedWidgets(this.model.selectedArea); }, () => { this.model.selectedArea = null; }); } setSelectedWidgets(selectedArea) { this.model.widgets.forEach((widget) => { const { x, y, width, height } = selectedArea; if (!(widget.x > x + width || widget.x + widget.width < x || widget.y > y + height || widget.y + widget.height < y)) { widget.state = WidgetState.selected; } else { widget.state = WidgetState.normal; } }); } getSelectedWidgets() { return this.model.widgets.filter((widget) => widget.state === WidgetState.selected); } clearSelectedWidgets() { this.model.widgets.forEach((widget) => widget.state = WidgetState.normal); } mousePToPageP(mouseX, mouseY) { var _a; const { x, y } = ((_a = unref(this.container)) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect()) || { x: this.model.pageRect.x, y: this.model.pageRect.y }; return { x: mouseX - x, y: mouseY - y }; } } FreeLayoutService.token = Symbol(); FreeLayoutService.inject = () => inject(FreeLayoutService.token); var DragContainer = defineComponent({ name: "DragContainer", props: { widget: { type: Object, required: true }, widgetClass: { type: Function }, widgetStyle: { type: Function } }, setup(props) { const service = FreeLayoutService.inject(); const containerClass = computed(() => { let className = "drag_container"; if (props.widget.state === WidgetState.selected) { className += " selected"; } if (props.widget.moving) { className += " moving"; } if (props.widgetClass) { const classList = props.widgetClass(props.widget); className += " "; className += classList.join(" "); } return className; }); const cssTransform = () => { const panelPoint = { x: props.widget.x, y: props.widget.y }; return `translate(${panelPoint.x}px,${panelPoint.y}px)`; }; return { containerClass, cssTransform, service }; }, render() { var _a; const levels = this.$props.widget.moving ? 99999 : this.$props.widget.levels; const style = this.$props.widgetStyle && this.$props.widgetStyle(this.$props.widget); return h("div", { ref: (el) => this.$props.widget.container = el, class: this.containerClass, style: Object.assign({ transform: this.cssTransform(), width: `${this.$props.widget.width}px`, height: `${this.$props.widget.height}px`, zIndex: levels }, style), onMousedown: (e) => { !this.$props.widget.customDragNode && this.$props.widget.startDrag(e); }, onClick: (e) => { var _a2; return (_a2 = this.service) === null || _a2 === void 0 ? void 0 : _a2.$emit("widgetClick", this.widget, e); } }, [((_a = this.service) === null || _a === void 0 ? void 0 : _a.renderWidget) && this.service.renderWidget(this.$props.widget)]); } }); var FreeLayout = defineComponent({ components: { DragContainer }, props: { widgets: { type: Array, default: () => [] }, renderWidget: { type: Function, default: () => h("div", "\u8BF7\u91CD\u5199 renderWidget \u65B9\u6CD5") }, dragService: { type: Object }, width: { type: Number }, height: { type: Number }, background: { type: String, default: "#ffffff" }, disableDrag: { type: Boolean, default: false }, disableResize: { type: Boolean, default: false }, selectedArea: { type: Object, default: () => ({ disabled: false, border: "1px solid #b3e5fc", background: "rgba(179,229,252,0.2)" }) }, widgetClass: { type: Function }, widgetStyle: { type: Function } }, emits: ["createWidget", "attached", "drag-start", "moving", "moved", "delete", "widgetClick"], setup(props, { emit }) { const container = ref(null); const service = new FreeLayoutService({ width: props.width, height: props.height, disableDrag: props.disableDrag, disableResize: props.disableResize }, container, emit, props.renderWidget, props.dragService); onMounted(() => { service.dragService && service.dragService.onMounted(); }); watch([() => props.width, () => props.height], ([width, height]) => { service.setSize(width, height); }); function renderNewWidget() { if (!service.model.newWidget) return h("div"); return h(DragContainer, { key: service.model.newWidget.id, widget: service.model.newWidget, widgetClass: props.widgetClass, widgetStyle: props.widgetStyle }); } function renderWidgets() { return service.model.widgets.map((widget) => h(DragContainer, { key: widget.id, widget, widgetClass: props.widgetClass, widgetStyle: props.widgetStyle })); } function renderSelectedArea() { return h("div", { style: { position: "absolute", left: `${service.model.selectedArea.x}px`, top: `${service.model.selectedArea.y}px`, width: `${service.model.selectedArea.width}px`, height: `${service.model.selectedArea.height}px`, border: props.selectedArea.border, background: props.selectedArea.background } }); } return { service, container, renderNewWidget, renderWidgets, renderSelectedArea }; }, render() { return h("div", { ref: "container", class: "free-layout", style: { left: this.service.model.pageRect.x + this.service.options.unit, top: this.service.model.pageRect.y + this.service.options.unit, width: this.service.model.pageRect.width + this.service.options.unit, height: this.service.model.pageRect.height + this.service.options.unit, background: this.$props.background }, onmousedown: (e) => { var _a; if (e.target !== this.container || ((_a = this.$props.selectedArea) === null || _a === void 0 ? void 0 : _a.disabled)) return; this.service.createSelectedArea(); } }, [ this.$slots.widgetBefore && this.$slots.widgetBefore(), this.service.model.newWidget && this.renderNewWidget(), this.renderWidgets(), this.$slots.widgetAfter && this.$slots.widgetAfter(), this.service.model.selectedArea && this.renderSelectedArea() ]); } }); class DragService { constructor() { this.freeService = null; } registerFreeService(freeService) { this.freeService = freeService; } onMounted() { } widgetMouseDown(_) { return true; } } function useFreeLayoutResize(options) { const containerRef = ref(null); const freeLayoutRef = ref(null); const getSizeHandler = () => { if (!containerRef.value || !freeLayoutRef.value) return; const [top, right, bottom, left] = (options === null || options === void 0 ? void 0 : options.padding) || [0, 0, 0, 0]; const freeService = freeLayoutRef.value.service; const rect = containerRef.value.getBoundingClientRect(); const pageRect = freeService.model.pageRect; pageRect.x = left; pageRect.y = top; if (options === null || options === void 0 ? void 0 : options.autoWidth) { pageRect.width = rect.width - right - left; } else if (options === null || options === void 0 ? void 0 : options.horizontalCenter) { const surplus = rect.width - pageRect.width - left - right; pageRect.x = surplus < 0 ? left : left + Math.floor(surplus / 2); } if (options === null || options === void 0 ? void 0 : options.autoHeight) { pageRect.height = rect.height - top - bottom; } else if (options === null || options === void 0 ? void 0 : options.verticalCenter) { const surplus = rect.height - pageRect.height - top - bottom; pageRect.y = surplus < 0 ? top : top + Math.floor(surplus / 2); } (options === null || options === void 0 ? void 0 : options.onResize) && options.onResize(pageRect); }; onMounted(() => { if (!containerRef.value || !freeLayoutRef.value) return; register(freeLayoutRef.value.service); }); onBeforeUnmount(() => unRegister()); function registerContainer(container) { if (!container) { containerRef.value = container; unRegister(); return; } if (!freeLayoutRef.value) { console.warn("[FreeLayout registerContainer] freeLayoutRef \u4E0D\u5B58\u5728"); return; } if (!containerRef.value) { containerRef.value = container; register(freeLayoutRef.value.service); } } function register(freeService) { window.addEventListener("resize", getSizeHandler); getSizeHandler(); (options === null || options === void 0 ? void 0 : options.onRegister) && options.onRegister(freeService); } function unRegister() { window.removeEventListener("resize", getSizeHandler); (options === null || options === void 0 ? void 0 : options.onUnRegister) && options.onUnRegister(); } return { containerRef, freeLayoutRef, registerContainer, getSizeHandler }; } export { DragContainer, DragService, FreeLayout, FreeLayoutService, Widget, WidgetState, onMouseMove, useFreeLayoutResize };