111
This commit is contained in:
@@ -1,156 +0,0 @@
|
|||||||
<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>
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="test">
|
|
||||||
<!-- <div class="control" v-for="(item, index) in list" :key="index">
|
|
||||||
<div>
|
|
||||||
<span>偏移X</span>
|
|
||||||
<input type="number" v-model="item.offsetX" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span>偏移Y</span>
|
|
||||||
<input type="number" v-model="item.offsetY" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span>角度</span>
|
|
||||||
<input type="number" v-model="item.angle" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span>缩放</span>
|
|
||||||
<input type="number" v-model="item.scale" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span>水平间距</span>
|
|
||||||
<input type="number" v-model="item.gapX" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span>垂直间距</span>
|
|
||||||
<input type="number" v-model="item.gapY" />
|
|
||||||
</div>
|
|
||||||
<h2>---------整体--------</h2>
|
|
||||||
<div>
|
|
||||||
<span>缩放</span>
|
|
||||||
<input type="number" v-model="item.object.scale" step="0.1" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span>X</span>
|
|
||||||
<input type="number" v-model="item.object.left" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span>Y</span>
|
|
||||||
<input type="number" v-model="item.object.top" />
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
<div class="box">
|
|
||||||
<pingpu :list="list" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import pingpu from "./pingpu.vue";
|
|
||||||
const list = ref([
|
|
||||||
{
|
|
||||||
ifSingle: false,
|
|
||||||
level2Type: "Pattern",
|
|
||||||
designType: "Library",
|
|
||||||
path: "/src/assets/images/canvas/yinhua1.jpg",
|
|
||||||
location: [0, 0],
|
|
||||||
scale: [1, 1],
|
|
||||||
angle: 0,
|
|
||||||
name: "Print2",
|
|
||||||
priority: 1,
|
|
||||||
object: {
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
scaleX: 1,
|
|
||||||
scaleY: 1,
|
|
||||||
opacity: 1,
|
|
||||||
angle: 0,
|
|
||||||
flipX: false,
|
|
||||||
flipY: false,
|
|
||||||
blendMode: "multiply",
|
|
||||||
gapX: 0,
|
|
||||||
gapY: 0,
|
|
||||||
},
|
|
||||||
gap: [0, 0],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang='less' scoped>
|
|
||||||
.test {
|
|
||||||
> .control {
|
|
||||||
margin-left: 10px;
|
|
||||||
margin-top: 10px;
|
|
||||||
> div {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
> span {
|
|
||||||
width: 80px;
|
|
||||||
}
|
|
||||||
> input {
|
|
||||||
padding-left: 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
> .box {
|
|
||||||
width: 300px;
|
|
||||||
height: 500px;
|
|
||||||
overflow: hidden;
|
|
||||||
border: 1px solid #000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
Reference in New Issue
Block a user