nicecode-v2/packages/meta/lib/ImageEditor/viewer/render.js
2024-01-10 15:15:12 +08:00

285 lines
9.5 KiB
JavaScript

var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/ImageEditor/viewer/render.ts
var render_exports = {};
__export(render_exports, {
default: () => render_default
});
module.exports = __toCommonJS(render_exports);
var import_css = require("rc-util/lib/Dom/css");
var import_func = require("@zhst/func");
var import_utils = require("../utils");
var import_constants = require("./constants");
var render_default = {
// store
image: null,
canvas: null,
containerData: {
width: 0,
height: 0
},
animationFrame: null,
backgroundColor: "#fff",
targetTransform: {
translateX: 0,
translateY: 0,
scale: 0,
rotate: 0
// rotate: 90,
},
//method
async render() {
await this.initImg();
this.initCanvas();
this.startRaf();
},
initImg() {
return new Promise((resolve, reject) => {
const { image: propImage } = this.options;
if ((0, import_func.isString)(propImage)) {
const image = new Image();
image.crossOrigin = "anonymous";
image.src = propImage;
image.onload = () => {
this.image = image;
resolve(image);
};
image.onerror = (err) => {
reject(err);
};
} else {
this.image = propImage;
resolve(propImage);
}
});
},
initCanvas() {
if (!this.image)
return;
const { element, canvas, limit = {}, options } = this;
const containerData = {
width: (0, import_css.getOuterWidth)(element),
height: (0, import_css.getOuterHeight)(element)
};
this.containerData = containerData;
(0, import_css.set)(canvas, containerData);
canvas.width = containerData.width;
canvas.height = containerData.height;
const fitTransform = this.calcFitScreen();
this.targetTransform = Object.assign({}, this.targetTransform, fitTransform);
(0, import_utils.dispatchEvent)(this.element, import_constants.EVENT_VIEWER_TRANSFORM_CHANGE, (0, import_func.cloneDeep)(this.targetTransform));
const { fitScaleAsMinScale = false } = options;
if (fitScaleAsMinScale) {
this.limit = Object.assign({ minScale: this.targetTransform.scale }, this.limit);
}
},
startRaf() {
window.cancelAnimationFrame(this.animationFrame);
const loop = () => {
this.renderCanvas();
window.cancelAnimationFrame(this.animationFrame);
this.animationFrame = window.requestAnimationFrame(loop);
};
loop();
},
renderCanvas(_ctx) {
if (!this.image || !this.canvas)
return;
const { containerData, canvas, targetTransform, options } = this;
const { translateX, translateY, scale, rotate } = targetTransform;
const ctx = _ctx ? _ctx : canvas.getContext("2d");
ctx.clearRect(0, 0, containerData.width, containerData.height);
ctx.fillStyle = options.backgroundColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.setTransform(scale, 0, 0, scale, translateX, translateY);
const centerX = this.image.width / 2;
const centerY = this.image.height / 2;
ctx.translate(centerX, centerY);
ctx.rotate(rotate / 180 * Math.PI);
ctx.translate(-centerX, -centerY);
ctx.drawImage(this.image, 0, 0);
ctx.restore();
ctx.save();
this.renderShape(ctx);
ctx.restore();
},
scaleTo(offsetScale) {
const { containerData } = this;
this.calcTransform({
scaleCenter: {
x: containerData.width / 2,
y: containerData.height / 2,
step: offsetScale
}
});
},
//暂时只支持90deg旋转 否则limit 不能做
rotateTo(T) {
if (!this.image)
return;
const { targetTransform } = this;
const { rotate } = targetTransform;
const newDeg = (0, import_func.isFunction)(T) ? T(rotate) : T;
this.calcTransform({
rotate: newDeg
});
},
reset() {
this.targetTransform.rotate = 0;
const fitTransform = this.calcFitScreen();
this.targetTransform = Object.assign({}, this.targetTransform, fitTransform);
(0, import_utils.dispatchEvent)(this.element, import_constants.EVENT_VIEWER_TRANSFORM_CHANGE, (0, import_func.cloneDeep)(this.targetTransform));
},
getImgSize() {
if (!this.image)
return;
return { w: this.image.width, h: this.image.height };
},
calcFitScreen() {
if (!this.image)
return;
const w = this.containerData.width;
const h = this.containerData.height;
const iw = this.image.width;
const ih = this.image.height;
const { rotate = 0 } = this.targetTransform;
const wToh = w / h;
let imgwToh = iw / ih;
if (rotate % 180 !== 0) {
imgwToh = ih / iw;
}
let scale;
let translateX = 0;
let translateY = 0;
if (imgwToh > wToh) {
scale = w / iw;
translateX = 0;
translateY = (h - ih * scale) / 2;
if (rotate % 180 !== 0) {
scale = w / ih;
translateX = (ih - iw) / 2 * scale;
translateY = (h - iw * scale) / 2 + (iw - ih) / 2 * scale;
}
} else {
scale = h / ih;
translateX = (w - iw * scale) / 2;
translateY = 0;
if (rotate % 180 !== 0) {
scale = h / iw;
translateX = (w - ih * scale) / 2 + (ih - iw) / 2 * scale;
translateY = (iw - ih) / 2 * scale;
}
}
const fitTransform = {
translateX,
translateY,
scale
};
return fitTransform;
},
calcTransform(newTransform, cropBox) {
if (!this.image)
return;
const { translateX, translateY, scaleCenter, rotate } = newTransform;
if (!(0, import_func.isNil)(scaleCenter)) {
const { targetTransform: targetTransform2, limit = {} } = this;
let { minScale = 0.1, maxScale = Number.MAX_VALUE } = limit;
if (cropBox) {
let { width: iw, height: ih } = this.image;
if (targetTransform2.rotate % 180 !== 0)
[iw, ih] = [ih, iw];
const { width: cw, height: ch } = cropBox;
const corpMinScale = Math.max(cw / iw, ch / ih);
minScale = Math.max(corpMinScale, minScale);
}
const { x, y, step } = scaleCenter;
const preScale = targetTransform2.scale;
let newScale = targetTransform2.scale + step;
newScale = Math.min(maxScale, Math.max(newScale, minScale));
const newStep = newScale - preScale;
if (newScale != preScale) {
const offsetX = (x - targetTransform2.translateX) / targetTransform2.scale * newStep;
const offsetY = (y - targetTransform2.translateY) / targetTransform2.scale * newStep;
this.targetTransform.translateX = this.targetTransform.translateX - offsetX;
this.targetTransform.translateY = this.targetTransform.translateY - offsetY;
}
this.targetTransform.scale = newScale;
}
if (!(0, import_func.isNil)(translateX)) {
this.targetTransform.translateX += translateX;
}
if (!(0, import_func.isNil)(translateY)) {
this.targetTransform.translateY += translateY;
}
if (!(0, import_func.isNil)(rotate)) {
this.targetTransform.rotate = rotate;
}
const { targetTransform, containerData } = this;
const minMargin = 50;
let imgWidth = this.image.width;
let imgHeight = this.image.height;
if (this.targetTransform.rotate % 180 !== 0) {
imgWidth = this.image.height;
imgHeight = this.image.width;
}
const minX = minMargin - imgWidth * targetTransform.scale;
const maxX = containerData.width - minMargin;
const minY = minMargin - imgHeight * targetTransform.scale;
const maxY = containerData.height - minMargin;
this.targetTransform.translateX = Math.min(
maxX,
Math.max(this.targetTransform.translateX, minX)
);
this.targetTransform.translateY = Math.min(
maxY,
Math.max(this.targetTransform.translateY, minY)
);
if (cropBox) {
const { width: cw, height: ch, top, left } = cropBox;
const { width: iw, height: ih } = this.image;
let imgLeftTop = { x: 0, y: 0 };
let imgRightBottom = { x: iw, y: ih };
if (this.targetTransform.rotate % 180 !== 0) {
imgLeftTop = {
x: (iw - ih) / 2,
y: (ih - iw) / 2
};
imgRightBottom = {
x: (iw + ih) / 2,
y: (iw + ih) / 2
};
}
const maxX2 = left - imgLeftTop.x * this.targetTransform.scale;
const maxY2 = top - imgLeftTop.y * this.targetTransform.scale;
const minX2 = left + cw - imgRightBottom.x * this.targetTransform.scale;
const minY2 = top + ch - imgRightBottom.y * this.targetTransform.scale;
this.targetTransform.translateX = Math.min(
maxX2,
Math.max(this.targetTransform.translateX, minX2)
);
this.targetTransform.translateY = Math.min(
maxY2,
Math.max(this.targetTransform.translateY, minY2)
);
}
(0, import_utils.dispatchEvent)(this.element, import_constants.EVENT_VIEWER_TRANSFORM_CHANGE, (0, import_func.cloneDeep)(this.targetTransform));
}
};