zyy-free-layout
Version:
[vue3+ts]自由拖动布局
1,091 lines (987 loc) • 33.6 kB
JavaScript
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 };