<template>
	<div class="pingpu" ref="el"><canvas ref="canvasRef"></canvas></div>
</template>

<script setup>
	import { fabric } from "fabric-with-all";
	import { ref, watch, onMounted } from "vue";
	const props = defineProps({
		url: { type: String, required: true },
		offsetX: { type: Number, default: 0 }, // px
		offsetY: { type: Number, default: 0 }, // px
		angle: { type: Number, default: 0 }, // 角度
		scale: { type: Number, default: 100 }, // %
		gapX: { type: Number, default: 0 }, // px
		gapY: { type: Number, default: 0 }, // px
	});
	watch(
		() => props.url,
		() => getOriginalImage()
	);
	watch(
		() => [
			props.offsetX,
			props.offsetY,
			props.angle,
			props.scale,
			props.gapX,
			props.gapY,
		],
		() => setCanvasData()
	);
	const el = ref(null);
	const canvasRef = ref(null);
	const canvas = ref(null);
	const observer = ref(null);
	const id = "asfs123121sfe";
	onMounted(async () => {
		initCanvas();
		await getOriginalImage();
		setCanvasData();
		let throttleTimeout = null;
		let lastRunTime = 0;
		let trailingTimeout = null;
		observer.value = new ResizeObserver((entries) => {
			const now = Date.now();
			const throttleDelay = 100;
			if (!throttleTimeout) {
				updateCanvasSize();
				lastRunTime = now;
				throttleTimeout = setTimeout(() => {
					throttleTimeout = null;
				}, throttleDelay);
			} else {
				clearTimeout(trailingTimeout);
				trailingTimeout = setTimeout(() => {
					updateCanvasSize();
					lastRunTime = Date.now();
				}, throttleDelay);
			}
		});
		observer.value.observe(el.value);
	});
	onBeforeUnmount(() => {
		observer.value.disconnect();
	});
	const initCanvas = () => {
		canvas.value = new fabric.Canvas(canvasRef.value, {
			selection: false,
			evented: false,
		});
		canvas.value.setWidth(el.value.offsetWidth);
		canvas.value.setHeight(el.value.offsetHeight);
	};
	const updateCanvasSize = () => {
		canvas.value.setWidth(el.value.offsetWidth);
		canvas.value.setHeight(el.value.offsetHeight);
		setCanvasData();
	};
	const originalImage = ref(null);
	const getOriginalImage = () => {
		return new Promise((resolve, reject) => {
			fabric.Image.fromURL(
				props.url,
				(object) => {
					const imgElement = object.getElement();
					// 创建透明 Canvas
					const tcanvas = document.createElement("canvas");
					tcanvas.width = imgElement.width;
					tcanvas.height = imgElement.height;
					const ctx = tcanvas.getContext("2d");
					ctx.clearRect(0, 0, tcanvas.width, tcanvas.height);
					ctx.drawImage(imgElement, 0, 0);
					originalImage.value = tcanvas;
					resolve(tcanvas);
				},
				{ crossOrigin: "anonymous" }
			);
		});
	};
	const setCanvasData = () => {
		canvas.value.getObjects().forEach((obj) => {
			if (obj.id === id) canvas.value.remove(obj);
		});
		const image = originalImage.value;
		const cwidth = canvas.value.width;
		const cheight = canvas.value.height;
		const offsetX = props.offsetX;
		const offsetY = props.offsetY;
		const scaleX = ((cwidth / image.width) * (props.scale / 100)) / 5;
		const scaleY = ((cheight / image.height) * (props.scale / 100)) / 5;
		const scale = cwidth > cheight ? scaleX : scaleY;
		const angle = props.angle;
		const gapX = props.gapX;
		const gapY = props.gapY;
		const patternTransform = fabric.util.composeMatrix({
			scaleX: scale,
			scaleY: scale,
			angle: angle,
		});
		// 创建透明 Canvas
		const tcanvas = document.createElement("canvas");
		tcanvas.width = image.width + gapX;
		tcanvas.height = image.height + gapY;
		const ctx = tcanvas.getContext("2d");
		ctx.clearRect(0, 0, tcanvas.width, tcanvas.height);
		ctx.drawImage(image, 0, 0);
		const pattern = new fabric.Pattern({
			source: tcanvas,
			repeat: "repeat",
			patternTransform,
			offsetX, // 水平偏移
			offsetY, // 垂直偏移
		});
		const rect = new fabric.Rect({
			id,
			width: cwidth,
			height: cheight,
			top: 0,
			left: 0,
			// scaleX: 1,
			// scaleY: 1,
			fill: pattern,
			evented: false,
			selectable: false,
		});
		canvas.value.add(rect);
		canvas.value.renderAll();
	};
</script>

<style lang='less' scoped>
	.pingpu {
		width: 100%;
		height: 100%;
	}
</style>