Skip to content

Commit 378f53e

Browse files
committed
abstract cropper on classes and restructure the worktree in a library way
1 parent bf90cde commit 378f53e

19 files changed

+284
-223
lines changed

Diff for: index.html

+2-3
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22
<html lang="en">
33
<head>
44
<meta charset="UTF-8" />
5-
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
65
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7-
<title>Vite + Vue + TS</title>
6+
<title>vue-cropper</title>
87
</head>
98
<body>
109
<div id="app"></div>
11-
<script type="module" src="/src/main.ts"></script>
10+
<script type="module" src="/playground/main.ts"></script>
1211
</body>
1312
</html>

Diff for: package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"version": "0.0.0",
55
"type": "module",
66
"scripts": {
7-
"dev": "vite",
7+
"dev": "vite --force --config vite.playground.ts",
88
"build": "vue-tsc && vite build",
99
"preview": "vite preview"
1010
},

Diff for: playground/App.vue

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<script setup lang="ts">
2+
import {VueCropper} from '../src'
3+
</script>
4+
5+
<template>
6+
<vue-cropper src="image2.jpeg" :width="600" />
7+
</template>
8+

Diff for: src/main.ts renamed to playground/main.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { createApp } from 'vue'
2-
import './style.css'
32
import App from './App.vue'
43

54
createApp(App).mount('#app')

Diff for: public/image2.jpeg

599 KB
Loading

Diff for: src/App.vue

-29
This file was deleted.

Diff for: src/assets/vue.svg

-1
This file was deleted.

Diff for: src/components/HelloWorld.vue

-185
This file was deleted.

Diff for: src/components/VueCropper.vue

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<script setup lang="ts">
2+
import { watch } from "vue";
3+
import { PolygonCropper } from "./croppers";
4+
5+
const props = defineProps<{
6+
src: string,
7+
width?: number,
8+
height?: number,
9+
points?: {x: number, y: number}[]
10+
}>()
11+
12+
13+
const cropper = new PolygonCropper(props.src, props.width, props.height, props.points)
14+
cropper.render()
15+
16+
17+
watch(() => [props.src, props.width], () => {
18+
cropper.src = props.src
19+
cropper.width = props.width!
20+
cropper.render()
21+
})
22+
23+
</script>
24+
25+
<template>
26+
<div>
27+
<canvas id="CANVASID" ></canvas>
28+
</div>
29+
</template>
30+
31+

Diff for: src/components/croppers/cropper.ts

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { fabric } from "fabric";
2+
3+
abstract class Cropper {
4+
protected image?: fabric.Image
5+
protected canvas?: fabric.Canvas
6+
7+
public src: string
8+
public width: number
9+
public height: number
10+
11+
constructor(src: string, width: number = 0, height: number = 0) {
12+
this.src = src
13+
this.width = width
14+
this.height = height
15+
}
16+
17+
protected getObjectByName(name: string): fabric.Object | null {
18+
const objects = this.canvas!.getObjects().filter(value => value.name == name)
19+
if (objects.length > 0) return objects[0]
20+
return null
21+
}
22+
23+
public async render() {}
24+
25+
protected async setCanvas() {
26+
this.image = await this.createImage(this.src);
27+
28+
if (!this.canvas) {
29+
// Instance of canvas if not exists
30+
this.canvas = new fabric.Canvas("CANVASID", { selection: false });
31+
} else {
32+
// If instance of canvas exists clear all data and draw objects from scratch
33+
this.canvas.clear()
34+
this.canvas.remove(...this.canvas.getObjects())
35+
}
36+
37+
this.canvas.setDimensions({
38+
width: this.image.width! * this.scale,
39+
height: this.image.height! * this.scale,
40+
})
41+
42+
this.canvas.setOverlayImage(this.image, this.canvas.renderAll.bind(this.canvas), {
43+
scaleX: this.canvas.width! / this.image.width!,
44+
scaleY: this.canvas.height! / this.image.height!,
45+
globalCompositeOperation: "destination-atop",
46+
});
47+
}
48+
49+
private createImage(src: string): Promise<fabric.Image> {
50+
return new Promise((resolve, reject) => {
51+
try {
52+
fabric.Image.fromURL(src, (oimg) => {
53+
resolve(oimg);
54+
});
55+
} catch (error) {
56+
reject(error);
57+
}
58+
});
59+
}
60+
61+
protected drawMask() {
62+
let overlay = this.getObjectByName("overlay")
63+
if (!overlay) {
64+
overlay = new fabric.Rect({
65+
name: "overlay",
66+
left: 0,
67+
top: 0,
68+
width: this.canvas!.width,
69+
height: this.canvas!.height,
70+
fill: "rgba(0, 0, 0, 0.7)",
71+
evented: false,
72+
globalCompositeOperation: "source-over",
73+
});
74+
this.canvas!.add(overlay);
75+
}
76+
}
77+
78+
get scale() {
79+
if (this.image) {
80+
if (this.width > 0)
81+
return this.width / this.image.width!
82+
if (this.height > 0)
83+
return this.height / this.image.height!
84+
return 1
85+
}
86+
return 1
87+
}
88+
}
89+
90+
export default Cropper

Diff for: src/components/croppers/index.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import PolygonCropper from "./polygon";
2+
3+
export { PolygonCropper };

0 commit comments

Comments
 (0)