react-scratchingcard 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -3
- package/dist/index.d.ts +23 -2
- package/dist/index.js +123 -20
- package/dist/index.js.map +1 -1
- package/dist/index.modern.js +123 -20
- package/dist/index.modern.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ yarn add react-scratchingcard
|
|
|
35
35
|
|
|
36
36
|
```tsx
|
|
37
37
|
import React, { useRef } from 'react';
|
|
38
|
-
import ScratchCard from 'react-
|
|
38
|
+
import ScratchCard from 'react-scratchingcard';
|
|
39
39
|
|
|
40
40
|
import * as IMG from './img.jpg';
|
|
41
41
|
|
|
@@ -100,7 +100,7 @@ const App = () => {
|
|
|
100
100
|
or you can use CUSTOM_BRUSH_PRESET object
|
|
101
101
|
|
|
102
102
|
```tsx
|
|
103
|
-
import { CUSTOM_BRUSH_PRESET } from 'react-
|
|
103
|
+
import { CUSTOM_BRUSH_PRESET } from 'react-scratchingcard';
|
|
104
104
|
|
|
105
105
|
const App = () => {
|
|
106
106
|
return (
|
|
@@ -128,7 +128,8 @@ const App = () => {
|
|
|
128
128
|
|-------------------|-----------------|-------------|
|
|
129
129
|
| width | number | |
|
|
130
130
|
| height | number | |
|
|
131
|
-
| image | File
|
|
131
|
+
| image | File \| string \| {src?: string, default?: string} | |
|
|
132
|
+
| imageCrossOrigin | ?'' \| 'anonymous' \| 'use-credentials' | |
|
|
132
133
|
| finishPercent | ?number | 70 |
|
|
133
134
|
| brushSize | ?number | 20 |
|
|
134
135
|
| fadeOutOnComplete | ?boolean | true |
|
|
@@ -136,6 +137,23 @@ const App = () => {
|
|
|
136
137
|
| customBrush | ?CustomBrush | |
|
|
137
138
|
| customCheckZone | ?CustomCheckZone| |
|
|
138
139
|
|
|
140
|
+
### Remote URL
|
|
141
|
+
|
|
142
|
+
```tsx
|
|
143
|
+
<ScratchCard
|
|
144
|
+
width={320}
|
|
145
|
+
height={226}
|
|
146
|
+
image='https://cdn.example.com/scratch-cover.jpg'
|
|
147
|
+
imageCrossOrigin='anonymous'
|
|
148
|
+
>
|
|
149
|
+
<h1>Scratch card</h1>
|
|
150
|
+
</ScratchCard>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Note: pour calculer le pourcentage gratté (`finishPercent`) avec une image distante, le serveur distant doit autoriser CORS.
|
|
154
|
+
|
|
155
|
+
Le composant n'impose plus CORS par defaut pour une URL distante. `imageCrossOrigin` est utile seulement si ton serveur renvoie deja les en-tetes CORS voulus.
|
|
156
|
+
|
|
139
157
|
### CustomBrush
|
|
140
158
|
|
|
141
159
|
| **name** | **type** |
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,10 @@ declare type CustomBrush = {
|
|
|
8
8
|
width: number;
|
|
9
9
|
height: number;
|
|
10
10
|
};
|
|
11
|
+
declare type ImageSource = string | File | {
|
|
12
|
+
src?: string;
|
|
13
|
+
default?: string;
|
|
14
|
+
};
|
|
11
15
|
declare type CustomCheckZone = {
|
|
12
16
|
x: number;
|
|
13
17
|
y: number;
|
|
@@ -17,7 +21,8 @@ declare type CustomCheckZone = {
|
|
|
17
21
|
interface Props {
|
|
18
22
|
width: number;
|
|
19
23
|
height: number;
|
|
20
|
-
image:
|
|
24
|
+
image: ImageSource;
|
|
25
|
+
imageCrossOrigin?: '' | 'anonymous' | 'use-credentials';
|
|
21
26
|
finishPercent?: number;
|
|
22
27
|
onComplete?: () => void;
|
|
23
28
|
brushSize?: number;
|
|
@@ -37,11 +42,27 @@ declare class Scratch extends Component<Props, State> {
|
|
|
37
42
|
canvas: HTMLCanvasElement;
|
|
38
43
|
brushImage?: any;
|
|
39
44
|
image: HTMLImageElement;
|
|
45
|
+
objectUrl: string | null;
|
|
46
|
+
scratchedCells: Set<string>;
|
|
47
|
+
scratchableCellCount: number;
|
|
40
48
|
isFinished: boolean;
|
|
41
49
|
constructor(props: Props);
|
|
50
|
+
componentDidUpdate(prevProps: Props): void;
|
|
51
|
+
componentWillUnmount(): void;
|
|
52
|
+
revokeObjectUrl(): void;
|
|
53
|
+
resolveImageSource(image: ImageSource): string;
|
|
54
|
+
loadImage(): void;
|
|
42
55
|
componentDidMount(): void;
|
|
43
56
|
reset: () => void;
|
|
44
|
-
|
|
57
|
+
getCheckZone(): {
|
|
58
|
+
x: number;
|
|
59
|
+
y: number;
|
|
60
|
+
width: number;
|
|
61
|
+
height: number;
|
|
62
|
+
};
|
|
63
|
+
initializeScratchGrid(): void;
|
|
64
|
+
markScratchArea(x: number, y: number, width: number, height: number): void;
|
|
65
|
+
getFilledPercentage(): number;
|
|
45
66
|
getMouse(e: any, canvas: HTMLCanvasElement): {
|
|
46
67
|
x: number;
|
|
47
68
|
y: number;
|
package/dist/index.js
CHANGED
|
@@ -19,6 +19,8 @@ function _setPrototypeOf(o, p) {
|
|
|
19
19
|
return _setPrototypeOf(o, p);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
var SCRATCH_GRID_SIZE = 4;
|
|
23
|
+
|
|
22
24
|
var Scratch = /*#__PURE__*/function (_Component) {
|
|
23
25
|
_inheritsLoose(Scratch, _Component);
|
|
24
26
|
|
|
@@ -28,6 +30,9 @@ var Scratch = /*#__PURE__*/function (_Component) {
|
|
|
28
30
|
_this = _Component.call(this, props) || this;
|
|
29
31
|
_this.isDrawing = false;
|
|
30
32
|
_this.lastPoint = null;
|
|
33
|
+
_this.objectUrl = null;
|
|
34
|
+
_this.scratchedCells = new Set();
|
|
35
|
+
_this.scratchableCellCount = 0;
|
|
31
36
|
_this.isFinished = false;
|
|
32
37
|
|
|
33
38
|
_this.reset = function () {
|
|
@@ -36,7 +41,13 @@ var Scratch = /*#__PURE__*/function (_Component) {
|
|
|
36
41
|
|
|
37
42
|
_this.ctx.drawImage(_this.image, 0, 0, _this.props.width, _this.props.height);
|
|
38
43
|
|
|
44
|
+
_this.initializeScratchGrid();
|
|
45
|
+
|
|
39
46
|
_this.isFinished = false;
|
|
47
|
+
|
|
48
|
+
_this.setState({
|
|
49
|
+
finished: false
|
|
50
|
+
});
|
|
40
51
|
};
|
|
41
52
|
|
|
42
53
|
_this.handleMouseDown = function (e) {
|
|
@@ -66,18 +77,24 @@ var Scratch = /*#__PURE__*/function (_Component) {
|
|
|
66
77
|
|
|
67
78
|
if (_this.brushImage && _this.props.customBrush) {
|
|
68
79
|
_this.ctx.drawImage(_this.brushImage, x, y, _this.props.customBrush.width, _this.props.customBrush.height);
|
|
80
|
+
|
|
81
|
+
_this.markScratchArea(x, y, _this.props.customBrush.width, _this.props.customBrush.height);
|
|
69
82
|
} else {
|
|
70
83
|
_this.ctx.beginPath();
|
|
71
84
|
|
|
72
85
|
_this.ctx.arc(x, y, _this.props.brushSize || 20, 0, 2 * Math.PI, false);
|
|
73
86
|
|
|
74
87
|
_this.ctx.fill();
|
|
88
|
+
|
|
89
|
+
var radius = _this.props.brushSize || 20;
|
|
90
|
+
|
|
91
|
+
_this.markScratchArea(x - radius, y - radius, radius * 2, radius * 2);
|
|
75
92
|
}
|
|
76
93
|
}
|
|
77
94
|
|
|
78
95
|
_this.lastPoint = currentPoint;
|
|
79
96
|
|
|
80
|
-
_this.handlePercentage(_this.
|
|
97
|
+
_this.handlePercentage(_this.getFilledPercentage());
|
|
81
98
|
};
|
|
82
99
|
|
|
83
100
|
_this.handleMouseUp = function () {
|
|
@@ -93,24 +110,80 @@ var Scratch = /*#__PURE__*/function (_Component) {
|
|
|
93
110
|
|
|
94
111
|
var _proto = Scratch.prototype;
|
|
95
112
|
|
|
96
|
-
_proto.
|
|
113
|
+
_proto.componentDidUpdate = function componentDidUpdate(prevProps) {
|
|
114
|
+
if (prevProps.image !== this.props.image) {
|
|
115
|
+
this.loadImage();
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
_proto.componentWillUnmount = function componentWillUnmount() {
|
|
120
|
+
this.revokeObjectUrl();
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
_proto.revokeObjectUrl = function revokeObjectUrl() {
|
|
124
|
+
if (this.objectUrl) {
|
|
125
|
+
URL.revokeObjectURL(this.objectUrl);
|
|
126
|
+
this.objectUrl = null;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
_proto.resolveImageSource = function resolveImageSource(image) {
|
|
131
|
+
this.revokeObjectUrl();
|
|
132
|
+
|
|
133
|
+
if (typeof image === 'string') {
|
|
134
|
+
return image;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (image instanceof File) {
|
|
138
|
+
this.objectUrl = URL.createObjectURL(image);
|
|
139
|
+
return this.objectUrl;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (image && typeof image.src === 'string') {
|
|
143
|
+
return image.src;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (image && typeof image["default"] === 'string') {
|
|
147
|
+
return image["default"];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return '';
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
_proto.loadImage = function loadImage() {
|
|
97
154
|
var _this2 = this;
|
|
98
155
|
|
|
99
|
-
this.isDrawing = false;
|
|
100
|
-
this.lastPoint = null;
|
|
101
|
-
this.ctx = this.canvas.getContext('2d');
|
|
102
156
|
this.image = new Image();
|
|
103
|
-
|
|
157
|
+
|
|
158
|
+
if (this.props.imageCrossOrigin !== undefined) {
|
|
159
|
+
this.image.crossOrigin = this.props.imageCrossOrigin;
|
|
160
|
+
}
|
|
104
161
|
|
|
105
162
|
this.image.onload = function () {
|
|
163
|
+
_this2.ctx.globalCompositeOperation = 'source-over';
|
|
164
|
+
|
|
165
|
+
_this2.ctx.clearRect(0, 0, _this2.props.width, _this2.props.height);
|
|
166
|
+
|
|
106
167
|
_this2.ctx.drawImage(_this2.image, 0, 0, _this2.props.width, _this2.props.height);
|
|
107
168
|
|
|
169
|
+
_this2.initializeScratchGrid();
|
|
170
|
+
|
|
171
|
+
_this2.isFinished = false;
|
|
172
|
+
|
|
108
173
|
_this2.setState({
|
|
109
|
-
loaded: true
|
|
174
|
+
loaded: true,
|
|
175
|
+
finished: false
|
|
110
176
|
});
|
|
111
177
|
};
|
|
112
178
|
|
|
113
|
-
this.image.src = this.props.image;
|
|
179
|
+
this.image.src = this.resolveImageSource(this.props.image);
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
_proto.componentDidMount = function componentDidMount() {
|
|
183
|
+
this.isDrawing = false;
|
|
184
|
+
this.lastPoint = null;
|
|
185
|
+
this.ctx = this.canvas.getContext('2d');
|
|
186
|
+
this.loadImage();
|
|
114
187
|
|
|
115
188
|
if (this.props.customBrush) {
|
|
116
189
|
this.brushImage = new Image(this.props.customBrush.width, this.props.customBrush.height);
|
|
@@ -118,11 +191,7 @@ var Scratch = /*#__PURE__*/function (_Component) {
|
|
|
118
191
|
}
|
|
119
192
|
};
|
|
120
193
|
|
|
121
|
-
_proto.
|
|
122
|
-
if (!stride || stride < 1) {
|
|
123
|
-
stride = 1;
|
|
124
|
-
}
|
|
125
|
-
|
|
194
|
+
_proto.getCheckZone = function getCheckZone() {
|
|
126
195
|
var x = 0;
|
|
127
196
|
var y = 0;
|
|
128
197
|
var width = this.canvas.width;
|
|
@@ -135,17 +204,51 @@ var Scratch = /*#__PURE__*/function (_Component) {
|
|
|
135
204
|
height = this.props.customCheckZone.height;
|
|
136
205
|
}
|
|
137
206
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
207
|
+
return {
|
|
208
|
+
x: x,
|
|
209
|
+
y: y,
|
|
210
|
+
width: width,
|
|
211
|
+
height: height
|
|
212
|
+
};
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
_proto.initializeScratchGrid = function initializeScratchGrid() {
|
|
216
|
+
var zone = this.getCheckZone();
|
|
217
|
+
var columns = Math.ceil(zone.width / SCRATCH_GRID_SIZE);
|
|
218
|
+
var rows = Math.ceil(zone.height / SCRATCH_GRID_SIZE);
|
|
219
|
+
this.scratchedCells = new Set();
|
|
220
|
+
this.scratchableCellCount = columns * rows;
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
_proto.markScratchArea = function markScratchArea(x, y, width, height) {
|
|
224
|
+
var zone = this.getCheckZone();
|
|
225
|
+
var startX = Math.max(zone.x, x);
|
|
226
|
+
var startY = Math.max(zone.y, y);
|
|
227
|
+
var endX = Math.min(zone.x + zone.width, x + width);
|
|
228
|
+
var endY = Math.min(zone.y + zone.height, y + height);
|
|
141
229
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
230
|
+
if (startX >= endX || startY >= endY) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
var startColumn = Math.floor((startX - zone.x) / SCRATCH_GRID_SIZE);
|
|
235
|
+
var endColumn = Math.floor((endX - zone.x - 1) / SCRATCH_GRID_SIZE);
|
|
236
|
+
var startRow = Math.floor((startY - zone.y) / SCRATCH_GRID_SIZE);
|
|
237
|
+
var endRow = Math.floor((endY - zone.y - 1) / SCRATCH_GRID_SIZE);
|
|
238
|
+
|
|
239
|
+
for (var row = startRow; row <= endRow; row++) {
|
|
240
|
+
for (var column = startColumn; column <= endColumn; column++) {
|
|
241
|
+
this.scratchedCells.add(column + ":" + row);
|
|
145
242
|
}
|
|
146
243
|
}
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
_proto.getFilledPercentage = function getFilledPercentage() {
|
|
247
|
+
if (this.scratchableCellCount === 0) {
|
|
248
|
+
return 0;
|
|
249
|
+
}
|
|
147
250
|
|
|
148
|
-
return Math.round(
|
|
251
|
+
return Math.round(this.scratchedCells.size / this.scratchableCellCount * 100);
|
|
149
252
|
};
|
|
150
253
|
|
|
151
254
|
_proto.getMouse = function getMouse(e, canvas) {
|