mg-vue-cropper
Version:
A mg vue-cropper Component.
860 lines (859 loc) • 32.9 kB
JavaScript
import { resolveDirective as V, createElementBlock as f, openBlock as w, normalizeStyle as g, createElementVNode as h, createCommentVNode as y, withDirectives as x, vShow as k, normalizeClass as F, Fragment as q, toDisplayString as W, resolveComponent as j, createVNode as E, renderSlot as A } from "vue";
const G = {
name: "drag",
mounted(t, e, s) {
t.onmousedown = (o) => {
o.stopPropagation(), o.preventDefault();
let r = t.offsetLeft, i = t.offsetTop;
const a = document.querySelector(e.value.rangeDomSelector), n = window.getComputedStyle(a), l = window.getComputedStyle(t), c = window.parseFloat(n.width) - window.parseFloat(l.width), m = window.parseFloat(n.height) - window.parseFloat(l.height), u = o.clientX - t.offsetLeft, v = o.clientY - t.offsetTop;
document.onmousemove = (S) => {
r = S.clientX - u, i = S.clientY - v, r < 0 ? r = 0 : r > c && (r = c), i < 0 ? i = 0 : i > m && (i = m), t.style.left = r + "px", t.style.top = i + "px";
}, document.onmouseup = (S) => {
e.value && e.value.callback && e.value.callback({
left: r,
top: i
}), document.onmousemove = null, document.onmouseup = null;
};
};
}
}, J = {
name: "resize",
mounted(t, e, s) {
t.onmousedown = (o) => {
o.stopPropagation(), o.preventDefault();
const r = e.value.type || "se", i = o.clientX, a = o.clientY;
let n = 0, l = 0;
const c = t.parentNode, m = window.getComputedStyle(c), u = window.parseFloat(m.left), v = window.parseFloat(m.top), S = window.parseFloat(m.width), b = window.parseFloat(m.height), $ = {
left: u + S
}, B = {
left: u + S,
top: v + b
}, _ = {
top: v + b
};
let I = u, D = v, d = S, p = b;
const Y = document.querySelector(e.value.rangeDomSelector), H = window.getComputedStyle(Y), L = e.value.bindComponent.minCutRenderSize.width, P = e.value.bindComponent.minCutRenderSize.height;
let O = window.parseFloat(H.width) - c.offsetLeft, N = window.parseFloat(H.height) - c.offsetTop;
r === "nw" ? (O = B.left, N = B.top) : r === "ne" ? N = _.top : r === "sw" && (O = $.left);
let z = 1;
const C = e.value.bindComponent.$cropperRoot.equiRatio;
C && (z = S / b), document.onmousemove = (U) => {
n = U.clientX - i, l = U.clientY - a, r === "nw" ? (n = -n, l = -l) : r === "ne" ? l = -l : r === "sw" && (n = -n), d = S + n, p = b + l, C && (p = d / z), d < L && (d = L, C && (p = d / z)), p < P && (p = P, C && (d = p * z)), d > O && (d = O, C && (p = d / z)), p > N && (p = N, C && (d = p * z)), r === "nw" ? (I = B.left - d, D = B.top - p) : r === "ne" ? D = _.top - p : r === "sw" && (I = $.left - d), c.style.left = `${I}px`, c.style.top = `${D}px`, c.style.width = `${d}px`, c.style.height = `${p}px`;
}, document.onmouseup = (U) => {
e.value && e.value.callback && e.value.callback({
left: I,
top: D,
width: d,
height: p
}), document.onmousemove = null, document.onmouseup = null;
};
};
}
}, R = (t = 0, e = 0, s = 0, o = 0) => {
let r = t, i = e;
if (r > s || i > o) {
const a = t / e, n = Math.min(s / r, o / i);
r / s >= i / o ? (r *= n, i = r / a) : (i *= n, r = i * a);
}
return {
width: r,
height: i
};
}, M = (t, e) => {
const s = t.__vccOpts || t;
for (const [o, r] of e)
s[o] = r;
return s;
}, K = {
name: "CropperTool",
directives: {
Drag: G,
Resize: J
},
inject: ["$cropperRoot"],
data() {
return {
/** 旋转原图的blob url(0°直接使用原图)
* blobUrl1 90° -270°
* blobUrl2 180° -180°
* blobUrl3 270° -90°
*/
rotateOriginalBlobUrls: {
blobUrl1: "",
blobUrl2: "",
blobUrl3: ""
},
// 素材的原始宽高(单位px)
materialNaturalSize: {
width: 0,
height: 0
},
// 素材缩放渲染后的实际宽高(单位px), 初始化时需要占满父容器
materialRenderSize: {
width: "100%",
height: "100%"
},
// 素材的旋转角度(初始化时为null)
imgRotateDeg: null,
// 裁剪框的宽高和坐标(单位px)
cutBox: {
width: 16,
height: 16,
left: 0,
top: 0
},
// 裁剪框显隐(默认隐藏,等待图片加载完毕再确定位置并显示)
cutBoxVisible: !1,
// 图片是否加载完成
imgLoaded: !1,
// 贴图显隐(缩略图)
chartletVisible: !1,
// 贴图的原始宽高和坐标(单位px)
chartletNaturalSize: {
width: 0,
height: 0,
left: this.$cropperRoot.chartletInitLeft,
top: this.$cropperRoot.chartletInitTop
},
bindComponent: this
};
},
computed: {
// 实际显示的图片url
realOriginalUrl() {
let t = this.$cropperRoot.originalUrl;
return this.imgRotateDeg === 90 || this.imgRotateDeg === -270 ? t = this.rotateOriginalBlobUrls.blobUrl1 : this.imgRotateDeg === 180 || this.imgRotateDeg === -180 ? t = this.rotateOriginalBlobUrls.blobUrl2 : (this.imgRotateDeg === 270 || this.imgRotateDeg === -90) && (t = this.rotateOriginalBlobUrls.blobUrl3), t;
},
// 素材原始宽高比
materialNaturalRatio() {
return this.materialNaturalSize.width / this.materialNaturalSize.height;
},
// 素材相对于原始尺寸的缩放比例
regionScale() {
let t = 1;
return typeof this.materialRenderSize.width == "number" && typeof this.materialNaturalSize.width == "number" && (t = this.materialRenderSize.width / this.materialNaturalSize.width), t;
},
// 裁剪框的最小尺寸(缩放后)
minCutRenderSize() {
const t = Math.max(this.$cropperRoot.minCutWidth * this.regionScale, 16), e = Math.max(this.$cropperRoot.minCutHeight * this.regionScale, 16), s = R(t, e, this.materialRenderSize.width, this.materialRenderSize.height);
return {
width: s.width,
height: s.height
};
},
// 裁剪框的原始宽高和坐标(相对于原图)
cutBoxOriginal() {
return {
width: this.cutBox.width / this.regionScale,
height: this.cutBox.height / this.regionScale,
left: this.cutBox.left / this.regionScale,
top: this.cutBox.top / this.regionScale,
// 裁剪框宽高比
ratio: this.cutBox.width / this.cutBox.height
};
},
cropperToolStyle() {
const t = {
width: "100%",
backgroundColor: this.$cropperRoot.colorBg
};
return (this.$cropperRoot.previewVisible || this.$cropperRoot.$slots.default) && (t.width = "calc(71.43% - 30px)", t.marginRight = "30px"), t;
},
materialContainerStyle() {
return {
width: typeof this.materialRenderSize.width == "number" ? `${this.materialRenderSize.width}px` : this.materialRenderSize.width,
height: typeof this.materialRenderSize.height == "number" ? `${this.materialRenderSize.height}px` : this.materialRenderSize.height,
opacity: this.imgLoaded ? 1 : 0
};
},
cutBoxStyle() {
return {
width: `${this.cutBox.width}px`,
height: `${this.cutBox.height}px`,
left: `${this.cutBox.left}px`,
top: `${this.cutBox.top}px`,
borderColor: this.$cropperRoot.colorPrimary
};
},
handleBtnStyle() {
return {
backgroundColor: this.$cropperRoot.colorPrimary
};
},
// 贴图缩放后的信息
chartletRenderInfo() {
let t = this.chartletNaturalSize.width * this.regionScale, e = this.chartletNaturalSize.height * this.regionScale;
const s = this.chartletNaturalSize.left * this.regionScale, o = this.chartletNaturalSize.top * this.regionScale, r = this.materialRenderSize.width * 0.3, i = this.materialRenderSize.height * 0.3;
if (t > r || e > i) {
const a = R(t, e, r, i);
t = a.width, e = a.height;
}
return {
width: t,
height: e,
left: s,
top: o
};
},
chartletContainerStyle() {
return {
width: `${this.chartletRenderInfo.width}px`,
height: `${this.chartletRenderInfo.height}px`,
left: `${this.chartletRenderInfo.left}px`,
top: `${this.chartletRenderInfo.top}px`
};
}
},
watch: {
"$cropperRoot.originalUrl"() {
this.resetCompData(), this.rotateOriginalBlobUrls.blobUrl1 = "", this.rotateOriginalBlobUrls.blobUrl2 = "", this.rotateOriginalBlobUrls.blobUrl3 = "", this.imgRotateDeg = null;
},
realOriginalUrl() {
this.resetCompData();
},
"$cropperRoot.currentChartlet.name"() {
this.chartletVisible = !1;
}
},
methods: {
errorHandle(t) {
this.imgRotateDeg === null && this.$emit("img-onerror", t);
},
abortHandle(t) {
this.imgRotateDeg === null && this.$emit("img-onabort", t);
},
loadHandle(t) {
this.initMaterialRenderSize(), this.initCutBox(), this.$cropperRoot.rotateVisible && this.imgRotateDeg === null && this.autoDrawRotateOriginalImg(), this.$emit("draw-img"), this.imgRotateDeg === null && this.$emit("img-onload", t), this.imgLoaded = !0;
},
// 获取并设置素材缩放渲染后的实际宽高
initMaterialRenderSize() {
const t = window.getComputedStyle(this.$refs.imgDom);
this.materialNaturalSize.width = this.$refs.imgDom.naturalWidth, this.materialNaturalSize.height = this.$refs.imgDom.naturalHeight, this.materialRenderSize.width = window.parseFloat(t.width), this.materialRenderSize.height = window.parseFloat(t.height);
},
// 初始化裁剪框的位置和尺寸(缩放后)
initCutBox() {
const t = Math.max(this.$cropperRoot.initCutWidth * this.regionScale, 16), e = Math.max(this.$cropperRoot.initCutHeight * this.regionScale, 16), s = R(t, e, this.materialRenderSize.width, this.materialRenderSize.height);
let o = this.$cropperRoot.initCutLeft * this.regionScale, r = this.$cropperRoot.initCutTop * this.regionScale;
const i = this.materialRenderSize.width - s.width, a = this.materialRenderSize.height - s.height;
o > i && (o = i), r > a && (r = a), this.cutBox.left = o, this.cutBox.top = r, this.cutBox.width = s.width, this.cutBox.height = s.height, this.cutBoxVisible = !0;
},
// 静默预绘制旋转原图
async autoDrawRotateOriginalImg() {
try {
const t = this.$parent.$refs.cropperPreview.drawRotateOriginalImg, e = await t(90, this.materialNaturalSize.width, this.materialNaturalSize.height), s = await t(180, this.materialNaturalSize.width, this.materialNaturalSize.height), o = await t(270, this.materialNaturalSize.width, this.materialNaturalSize.height);
this.rotateOriginalBlobUrls.blobUrl1 = e.blobUrl, this.rotateOriginalBlobUrls.blobUrl2 = s.blobUrl, this.rotateOriginalBlobUrls.blobUrl3 = o.blobUrl;
} catch (t) {
throw new Error(t);
}
},
// 拖拽结束后的回调(通常用于同步信息到数据)
dragCallback(t) {
this.cutBox.left = t.left, this.cutBox.top = t.top, this.$emit("draw-img");
},
// 缩放结束后的回调(通常用于同步信息到数据)
resizeCallback(t) {
this.cutBox.left = t.left, this.cutBox.top = t.top, this.cutBox.width = t.width, this.cutBox.height = t.height, this.$emit("draw-img");
},
// 顺时针旋转
rotateCwHandle() {
if (!this.imgLoaded) return;
let t = (this.imgRotateDeg || 0) + 90;
t >= 360 && (t = 0), this.imgRotateDeg = t;
},
// 逆时针旋转
rotateCcwHandle() {
if (!this.imgLoaded) return;
let t = (this.imgRotateDeg || 0) - 90;
t <= -360 && (t = 0), this.imgRotateDeg = t;
},
// 手动设置裁剪框的尺寸
setCutBoxSize({ width: t, height: e }) {
if (console.log(t, e, this.$cropperRoot, 123456), typeof t != "number" || typeof e != "number") return;
this.cutBoxVisible = !1;
const s = Math.max(t * this.regionScale, 16), o = Math.max(e * this.regionScale, 16), r = R(s, o, this.materialRenderSize.width, this.materialRenderSize.height);
this.cutBox.left = 0, this.cutBox.top = 0, this.cutBox.width = r.width, this.cutBox.height = r.height, this.cutBoxVisible = !0, this.$emit("draw-img");
},
// 手动设置裁剪框的位置
setCutBoxPos({ left: t, top: e }) {
if (typeof t != "number" || typeof e != "number") return;
this.cutBoxVisible = !1, t *= this.regionScale, e *= this.regionScale;
const s = this.materialRenderSize.width - this.cutBox.width, o = this.materialRenderSize.height - this.cutBox.height;
t > s && (t = s), e > o && (e = o), this.cutBox.left = t, this.cutBox.top = e, this.cutBoxVisible = !0, this.$emit("draw-img");
},
chartletLoadHandle(t) {
const e = t.target;
this.chartletNaturalSize.width = e.naturalWidth, this.chartletNaturalSize.height = e.naturalHeight, this.chartletNaturalSize.left = this.$cropperRoot.chartletInitLeft, this.chartletNaturalSize.top = this.$cropperRoot.chartletInitTop, this.$nextTick(() => {
this.chartletVisible = !0;
});
},
// 手动设置贴图的位置
setChartletPos({ left: t, top: e }) {
if (typeof t != "number" || typeof e != "number") return;
const s = this.materialNaturalSize.width - this.chartletRenderInfo.width / this.regionScale, o = this.materialNaturalSize.height - this.chartletRenderInfo.height / this.regionScale;
t > s && (t = s), e > o && (e = o), this.chartletNaturalSize.left = t, this.chartletNaturalSize.top = e;
},
resetCompData() {
this.cutBoxVisible = !1, this.imgLoaded = !1, this.materialNaturalSize.width = 0, this.materialNaturalSize.height = 0, this.materialRenderSize.width = "100%", this.materialRenderSize.height = "100%", this.cutBox.width = 16, this.cutBox.height = 16, this.cutBox.left = 0, this.cutBox.top = 0, this.chartletNaturalSize.left = this.$cropperRoot.chartletInitLeft, this.chartletNaturalSize.top = this.$cropperRoot.chartletInitTop, this.$emit("draw-img");
}
}
}, Q = ["src"], Z = { class: "resize-btn nw" }, tt = { class: "resize-btn ne" }, et = { class: "resize-btn se" }, it = { class: "resize-btn sw" }, rt = ["src"], ot = {
key: 0,
class: "rotate-container"
}, at = { class: "rotate-btns" };
function st(t, e, s, o, r, i) {
const a = V("resize"), n = V("drag");
return w(), f("div", {
style: g(i.cropperToolStyle),
class: "cropper-tool"
}, [
h("div", {
class: "material-container",
style: g(i.materialContainerStyle)
}, [
h("img", {
ref: "imgDom",
draggable: "false",
src: i.realOriginalUrl,
onLoad: e[0] || (e[0] = (...l) => i.loadHandle && i.loadHandle(...l)),
onError: e[1] || (e[1] = (...l) => i.errorHandle && i.errorHandle(...l)),
onAbort: e[2] || (e[2] = (...l) => i.abortHandle && i.abortHandle(...l)),
crossorigin: "anonymous"
}, null, 40, Q),
i.$cropperRoot.chartletOn ? y("", !0) : x((w(), f("div", {
key: 0,
class: "cut-box",
style: g(i.cutBoxStyle)
}, [
x((w(), f("div", Z, [
h("span", {
class: "handle-x",
style: g(i.handleBtnStyle)
}, null, 4),
h("span", {
class: "handle-y",
style: g(i.handleBtnStyle)
}, null, 4)
])), [
[a, { type: "nw", rangeDomSelector: ".material-container", bindComponent: r.bindComponent, callback: i.resizeCallback }]
]),
x((w(), f("div", tt, [
h("span", {
class: "handle-x",
style: g(i.handleBtnStyle)
}, null, 4),
h("span", {
class: "handle-y",
style: g(i.handleBtnStyle)
}, null, 4)
])), [
[a, { type: "ne", rangeDomSelector: ".material-container", bindComponent: r.bindComponent, callback: i.resizeCallback }]
]),
x((w(), f("div", et, [
h("span", {
class: "handle-x",
style: g(i.handleBtnStyle)
}, null, 4),
h("span", {
class: "handle-y",
style: g(i.handleBtnStyle)
}, null, 4)
])), [
[a, { type: "se", rangeDomSelector: ".material-container", bindComponent: r.bindComponent, callback: i.resizeCallback }]
]),
x((w(), f("div", it, [
h("span", {
class: "handle-x",
style: g(i.handleBtnStyle)
}, null, 4),
h("span", {
class: "handle-y",
style: g(i.handleBtnStyle)
}, null, 4)
])), [
[a, { type: "sw", rangeDomSelector: ".material-container", bindComponent: r.bindComponent, callback: i.resizeCallback }]
])
], 4)), [
[k, r.cutBoxVisible],
[n, { rangeDomSelector: ".material-container", callback: i.dragCallback }]
]),
i.$cropperRoot.chartletOn ? x((w(), f("div", {
key: 1,
class: "chartlet-container",
style: g(i.chartletContainerStyle)
}, [
h("img", {
ref: "chartletDom",
src: i.$cropperRoot.currentChartlet.url,
draggable: "false",
onLoad: e[3] || (e[3] = (...l) => i.chartletLoadHandle && i.chartletLoadHandle(...l)),
crossorigin: "anonymous"
}, null, 40, rt)
], 4)), [
[k, r.chartletVisible]
]) : y("", !0)
], 4),
i.$cropperRoot.rotateVisible ? (w(), f("div", ot, [
e[8] || (e[8] = h("span", { class: "rotate-title" }, "旋转", -1)),
h("div", at, [
h("span", {
class: F({ "is-disabled": !r.imgLoaded }),
onClick: e[4] || (e[4] = (...l) => i.rotateCcwHandle && i.rotateCcwHandle(...l))
}, e[6] || (e[6] = [
h("svg", {
t: "1602643918605",
class: "icon",
viewBox: "0 0 1024 1024",
version: "1.1",
xmlns: "http://www.w3.org/2000/svg",
"p-id": "7392",
"xmlns:xlink": "http://www.w3.org/1999/xlink",
width: "16",
height: "16"
}, [
h("path", {
d: "M809.437867 190.464C647.850667 28.8768 393.6256 15.906133 216.541867 150.596267V76.663467a68.1984 68.1984 0 1 0-136.533334 0v208.145066a68.061867 68.061867 0 0 0 68.266667 68.266667h208.213333a68.1984 68.1984 0 1 0 0-136.533333h-55.978666a349.866667 349.866667 0 0 1 436.497066 46.353066 349.934933 349.934933 0 0 1 0 494.3872 349.934933 349.934933 0 0 1-494.3872 0A349.5936 349.5936 0 0 1 141.038933 486.058667a51.2 51.2 0 1 0-102.1952-7.031467A451.925333 451.925333 0 1 0 809.437867 190.464",
fill: "#999999",
"p-id": "7393"
})
], -1)
]), 2),
h("span", {
class: F({ "is-disabled": !r.imgLoaded }),
onClick: e[5] || (e[5] = (...l) => i.rotateCwHandle && i.rotateCwHandle(...l))
}, e[7] || (e[7] = [
h("svg", {
t: "1602643926245",
class: "icon",
viewBox: "0 0 1024 1024",
version: "1.1",
xmlns: "http://www.w3.org/2000/svg",
"p-id": "7532",
"xmlns:xlink": "http://www.w3.org/1999/xlink",
width: "16",
height: "16"
}, [
h("path", {
d: "M190.600533 190.464C352.119467 28.8768 606.344533 15.906133 783.428267 150.596267V76.663467a68.1984 68.1984 0 1 1 136.533333 0v208.145066a68.061867 68.061867 0 0 1-68.266667 68.266667H643.549867a68.1984 68.1984 0 1 1 0-136.533333h55.978666a349.866667 349.866667 0 0 0-436.565333 46.353066 349.934933 349.934933 0 0 0 0 494.3872 349.934933 349.934933 0 0 0 494.3872 0 349.5936 349.5936 0 0 0 101.5808-271.223466 51.2 51.2 0 1 1 102.1952-7.031467A451.925333 451.925333 0 1 1 190.600533 190.464",
fill: "#999999",
"p-id": "7533"
})
], -1)
]), 2)
])
])) : y("", !0)
], 4);
}
const lt = /* @__PURE__ */ M(K, [["render", st], ["__scopeId", "data-v-3008b434"]]), nt = {
name: "CropperPreview",
data() {
return {
canvaSize: {
width: 220,
height: 126
},
originalCanvasSize: {
width: 220,
height: 126
},
// 裁剪出的图片分辨率
cutImgDpi: "16*16",
// 裁剪出的图片比例
cutImgRatio: "1:1",
// 常见分辨率表(预留误差范围0.1)
imgRatioMap: {
"9:21": (t) => t > 0.4 && t < 0.49,
// 0.428571...
"1:2": (t) => t > 0.49 && t < 0.55,
// 0.5
"9:16": (t) => t > 0.55 && t < 0.6,
// 0.5625
"2:3": (t) => t > 0.6 && t < 0.7,
// 0.666666...
"3:4": (t) => t > 0.7 && t < 0.79,
// 0.75
"4:5": (t) => t > 0.79 && t < 0.85,
// 0.8
"1:1": (t) => t > 0.95 && t < 1.05,
// 1
"5:4": (t) => t > 1.2 && t < 1.3,
// 1.25
"4:3": (t) => t > 1.3 && t < 1.4,
// 1.333333...
"3:2": (t) => t > 1.45 && t < 1.55,
// 1.5
"16:9": (t) => t > 1.7 && t < 1.8,
// 1.777777...
"2:1": (t) => t > 1.95 && t < 2.05,
// 2
"21:9": (t) => t > 2.3 && t < 2.4
// 2.333333...
},
resizeObserver: null
};
},
inject: ["$cropperRoot"],
computed: {
canvasContainerStyle() {
const t = this.$cropperRoot.previewHeight;
return {
height: typeof t == "number" ? `${t}px` : t
};
}
},
mounted() {
!this.$cropperRoot.chartletOn && this.$cropperRoot.previewVisible && this.$refs.canvasContainer && (this.resizeObserver = new ResizeObserver(() => {
this.initCanvasSize();
}), this.resizeObserver.observe(this.$refs.canvasContainer));
},
beforeUnmount() {
this.resizeObserver && this.$refs.canvasContainer && this.resizeObserver.unobserve(this.$refs.canvasContainer);
},
methods: {
transformRatio(t, e) {
let s = "", o = parseInt(t.toFixed(2) * 100, 10), r = parseInt(e.toFixed(2) * 100, 10), i = Math.min(o, r);
for (let a = i; a > 1; a--)
!(o % a) && !(r % a) && (o = o / a, r = r / a, i = Math.min(o, r));
s = `${o}:${r}`;
for (const a in this.imgRatioMap) {
const n = this.imgRatioMap[a];
if (n(o / r)) {
s = a;
break;
}
}
return s;
},
initCanvasSize() {
this.canvaSize.width = this.$refs.canvasContainer.offsetWidth, this.canvaSize.height = this.$refs.canvasContainer.offsetHeight, console.log(this.canvaSize, this.$refs.canvasContainer.offsetWidth);
},
setCutImgInfo(t, e) {
t = Math.floor(t), e = Math.floor(e), this.cutImgDpi = `${t}*${e}`, this.cutImgRatio = this.transformRatio(t, e);
},
// 绘制预览图
drawImg() {
if (this.$cropperRoot.chartletOn || !this.$cropperRoot.previewVisible) return;
const e = this.$refs.previewCanvas.getContext("2d"), s = this.$parent.$refs.cropperTool.$refs.imgDom;
e.clearRect(0, 0, this.canvaSize.width, this.canvaSize.height), e.resetTransform();
const o = this.$parent.$refs.cropperTool.cutBoxOriginal, r = R(o.width, o.height, this.canvaSize.width, this.canvaSize.height), i = r.width, a = r.height;
let n = 0, l = 0;
i < this.canvaSize.width && (n = (this.canvaSize.width - i) / 2), a < this.canvaSize.height && (l = (this.canvaSize.height - a) / 2), this.setCutImgInfo(o.width, o.height), this.$nextTick(() => {
e.drawImage(s, o.left, o.top, o.width, o.height, n, l, i, a);
});
},
// 绘制原图
drawOriginalImg() {
return new Promise((t, e) => {
const o = this.$refs.originalCanvas.getContext("2d"), r = this.$parent.$refs.cropperTool.$refs.imgDom;
o.clearRect(0, 0, this.originalCanvasSize.width, this.originalCanvasSize.height), o.resetTransform();
const i = () => {
const n = this.$parent.$refs.cropperTool.materialNaturalSize;
this.originalCanvasSize.width = n.width, this.originalCanvasSize.height = n.height, this.$nextTick(() => {
if (o.drawImage(r, 0, 0), this.$parent.hasChartlet) {
const l = this.$parent.$refs.cropperTool.$refs.chartletDom, c = this.$parent.$refs.cropperTool.chartletNaturalSize, m = this.$parent.$refs.cropperTool.chartletRenderInfo, u = this.$parent.$refs.cropperTool.regionScale, v = c.left, S = c.top, b = m.width / u, $ = m.height / u;
o.drawImage(l, v, S, b, $);
}
t();
});
}, a = () => {
const n = this.$parent.$refs.cropperTool.cutBoxOriginal;
this.originalCanvasSize.width = n.width, this.originalCanvasSize.height = n.height, this.$nextTick(() => {
o.drawImage(r, n.left, n.top, n.width, n.height, 0, 0, n.width, n.height), t();
});
};
this.$cropperRoot.chartletOn ? i() : a();
});
},
/**
* 绘制旋转原图
* @params drawDeg Number 绘制的旋转图度数
* @params naturalWidth Number 素材的原始宽
* @params naturalHeight Number 素材的原始高
*/
drawRotateOriginalImg(t, e, s) {
return new Promise((o, r) => {
const i = this.$refs.originalCanvas, a = i.getContext("2d"), n = this.$parent.$refs.cropperTool.$refs.imgDom;
a.clearRect(0, 0, this.originalCanvasSize.width, this.originalCanvasSize.height), a.resetTransform();
const l = e, c = s, m = [-90, -270, 90, 270].includes(t);
this.originalCanvasSize.width = m ? c : l, this.originalCanvasSize.height = m ? l : c, this.$nextTick(() => {
a.translate(this.originalCanvasSize.width / 2, this.originalCanvasSize.height / 2), a.rotate(t * Math.PI / 180), a.drawImage(n, -l / 2, -c / 2, l, c), i.toBlob((u) => {
const v = URL.createObjectURL(u);
u && v ? o({
blob: u,
blobUrl: v
}) : r(new Error("Failed to save img."));
});
});
});
},
saveImg() {
return new Promise((t, e) => {
this.drawOriginalImg().then(() => {
this.$refs.originalCanvas.toBlob((o) => {
const r = URL.createObjectURL(o);
if (o && r) {
const i = {
blob: o,
blobUrl: r,
naturalSize: { ...this.$parent.$refs.cropperTool.materialNaturalSize }
};
if (this.$cropperRoot.chartletOn)
i.hasChartlet = this.$parent.hasChartlet;
else {
const a = this.$parent.$refs.cropperTool.cutBoxOriginal, n = {
leftTop: {
x: a.left,
y: a.top
},
rightTop: {
x: a.left + a.width,
y: a.top
},
rightBottom: {
x: a.left + a.width,
y: a.top + a.height
},
leftBottom: {
x: a.left,
y: a.top + a.height
}
}, l = {
width: a.width,
height: a.height
};
i.cutPos = n, i.cutSize = l;
}
t(i);
} else
e(new Error("Failed to save img."));
});
});
});
},
downloadImg(t) {
this.drawOriginalImg().then(() => {
this.$refs.originalCanvas.toBlob((s) => {
const o = URL.createObjectURL(s), r = document.createElement("a");
t || (t = (/* @__PURE__ */ new Date()).getTime()), r.download = t, r.href = o, document.body.appendChild(r), r.click(), r.remove();
});
});
}
}
}, ht = { class: "cropper-preview" }, ct = ["width", "height"], dt = { class: "preview-info" }, pt = { class: "info-value" }, gt = { class: "info-value" }, mt = { class: "original-canvas-container" }, ut = ["width", "height"];
function ft(t, e, s, o, r, i) {
return w(), f("div", ht, [
!i.$cropperRoot.chartletOn && i.$cropperRoot.previewVisible ? (w(), f(q, { key: 0 }, [
e[2] || (e[2] = h("div", { class: "preview-title" }, "效果预览", -1)),
h("div", {
ref: "canvasContainer",
class: "canvas-container",
style: g(i.canvasContainerStyle)
}, [
h("canvas", {
width: r.canvaSize.width,
height: r.canvaSize.height,
ref: "previewCanvas"
}, null, 8, ct)
], 4),
h("div", dt, [
h("div", null, [
e[0] || (e[0] = h("span", { class: "info-label" }, "分辨率:", -1)),
h("span", pt, W(r.cutImgDpi), 1)
]),
h("div", null, [
e[1] || (e[1] = h("span", { class: "info-label" }, "图片比例:", -1)),
h("span", gt, W(r.cutImgRatio), 1)
])
])
], 64)) : y("", !0),
h("div", mt, [
h("canvas", {
width: r.originalCanvasSize.width,
height: r.originalCanvasSize.height,
ref: "originalCanvas"
}, null, 8, ut)
])
]);
}
const wt = /* @__PURE__ */ M(nt, [["render", ft], ["__scopeId", "data-v-56e3a6cf"]]), St = {
name: "MgCropper",
components: {
CropperTool: lt,
CropperPreview: wt
},
provide() {
return {
$cropperRoot: this
};
},
props: {
width: {
type: Number,
default: 770
},
height: {
type: Number,
default: 300
},
colorPrimary: {
type: String,
default: "#6676FF"
},
colorBg: {
type: String,
default: "rgba(0, 0, 0, 0.8)"
},
// Img original url
originalUrl: {
type: String,
required: !0,
default: ""
},
// Need equi-ratio
equiRatio: {
type: Boolean,
default: !1
},
minCutWidth: {
type: Number,
default: 16
},
minCutHeight: {
type: Number,
default: 16
},
initCutWidth: {
type: Number,
default: 16
},
initCutHeight: {
type: Number,
default: 16
},
initCutLeft: {
type: Number,
default: 0
},
initCutTop: {
type: Number,
default: 0
},
rotateVisible: {
type: Boolean,
default: !1
},
previewVisible: {
type: Boolean,
default: !1
},
previewHeight: {
type: [String, Number],
default: "42%"
},
/**
* v2.0.x
* chartlet
*/
chartletOn: {
type: Boolean,
default: !1
},
chartletList: {
type: Array,
default() {
return [];
}
},
currentChartlet: {
type: Object,
default() {
return {
name: "",
url: ""
};
}
},
chartletInitLeft: {
type: Number,
default: 10
},
chartletInitTop: {
type: Number,
default: 10
}
},
computed: {
styleObj() {
return {
width: `${this.width}px`,
height: `${this.height}px`
};
},
hasChartlet() {
return !!this.currentChartlet.url;
}
},
methods: {
drawImgHandle() {
this.$nextTick(() => this.$refs.cropperPreview.drawImg());
},
saveImg() {
return this.$refs.cropperPreview.saveImg();
},
downloadImg(...t) {
return this.$refs.cropperPreview.downloadImg(...t);
},
setCutBoxSize(...t) {
return this.$refs.cropperTool.setCutBoxSize(...t);
},
setCutBoxPos(...t) {
return this.$refs.cropperTool.setCutBoxPos(...t);
},
setChartletPos(...t) {
return this.$refs.cropperTool.setChartletPos(...t);
}
}
}, vt = {
key: 0,
class: "right-slot"
};
function bt(t, e, s, o, r, i) {
const a = j("cropper-tool"), n = j("cropper-preview");
return w(), f("div", {
class: "mg-cropper",
style: g(i.styleObj)
}, [
E(a, {
ref: "cropperTool",
onDrawImg: i.drawImgHandle,
onImgOnload: e[0] || (e[0] = (l) => t.$emit("img-onload", l)),
onImgOnerror: e[1] || (e[1] = (l) => t.$emit("img-onerror", l)),
onImgOnabort: e[2] || (e[2] = (l) => t.$emit("img-onabort", l))
}, null, 8, ["onDrawImg"]),
x(E(n, { ref: "cropperPreview" }, null, 512), [
[k, !t.$slots.default && s.previewVisible]
]),
t.$slots.default ? (w(), f("div", vt, [
A(t.$slots, "default", {}, void 0, !0)
])) : y("", !0)
], 4);
}
const T = /* @__PURE__ */ M(St, [["render", bt], ["__scopeId", "data-v-dbd1a6f4"]]);
T.install = function(t) {
t.component(T.name, T);
};
const xt = "3.0.7", X = [
T
], zt = function(t, e = {}) {
X.forEach((s) => {
t.component(s.name, s);
});
}, Rt = {
version: xt,
install: zt,
...X
};
export {
T as cropper,
Rt as default,
zt as install
};