Skip to content

Commit 0a524d1

Browse files
author
Thomas Bolis
committed
Adding methods to get and/or load canvas data based on json or url
1 parent cbfd6c3 commit 0a524d1

File tree

11 files changed

+573
-60
lines changed

11 files changed

+573
-60
lines changed

examples/data.json.js

Lines changed: 417 additions & 0 deletions
Large diffs are not rendered by default.

examples/data.url.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/main.jsx

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ import ClearIcon from 'material-ui/lib/svg-icons/action/delete';
1919
import SaveIcon from 'material-ui/lib/svg-icons/content/save';
2020
import RemoveIcon from 'material-ui/lib/svg-icons/content/clear';
2121

22+
import dataJson from './data.json'
23+
import dataUrl from './data.url'
24+
2225
import Tools from '../src/tools';
2326
import SketchField from '../src/SketchField';
2427

@@ -67,16 +70,45 @@ class SketchFieldDemo extends React.Component {
6770
};
6871
}
6972

73+
componentDidMount() {
74+
(function (console) {
75+
76+
console.save = function (data, filename) {
77+
78+
if (!data) {
79+
console.error('Console.save: No data')
80+
return;
81+
}
82+
83+
if (!filename) filename = 'console.json'
84+
85+
if (typeof data === "object") {
86+
data = JSON.stringify(data, undefined, 4)
87+
}
88+
89+
var blob = new Blob([data], {type: 'text/json'}),
90+
e = document.createEvent('MouseEvents'),
91+
a = document.createElement('a')
92+
93+
a.download = filename
94+
a.href = window.URL.createObjectURL(blob)
95+
a.dataset.downloadurl = ['text/json', a.download, a.href].join(':')
96+
e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
97+
a.dispatchEvent(e)
98+
}
99+
})(console)
100+
}
101+
70102
_selectTool(event, index, value) {
71103
this.setState({
72104
tool: value
73105
});
74106
}
75107

76108
_save() {
77-
let drawings = this.state.drawings;
78-
drawings.push(this._sketch.getContent());
79-
this.setState({drawings: drawings});
109+
//let drawings = this.state.drawings;
110+
//drawings.push(this._sketch.getContent());
111+
//this.setState({drawings: drawings});
80112
}
81113

82114
_renderTile(drawing, index) {
@@ -191,12 +223,12 @@ class SketchFieldDemo extends React.Component {
191223
fillColor={this.state.fillWithColor ? this.state.fillColor : 'transparent'}
192224
scaleOnResize={true}
193225
height={660}
194-
195-
196-
onChange={(c,d) => this.setState({canUndo: this._sketch.canUndo()})}
197-
226+
defaultData={dataJson}
227+
defaultDataType="json"
228+
onChange={(e) => {
229+
this.setState({canUndo: this._sketch.canUndo()})
230+
}}
198231
tool={this.state.tool}
199-
200232
/>
201233
</div>
202234
</div>

src/SketchField.jsx

Lines changed: 95 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
/*eslint no-unused-vars: 0*/
12
'use strict';
3+
24
import React from 'react';
35
import ReactDOM from 'react-dom';
6+
47
import History from './history';
58
import {uuid4} from './utils';
69

@@ -34,7 +37,11 @@ class SketchField extends React.Component {
3437
// image format when calling toDataURL
3538
imageFormat: React.PropTypes.string,
3639
// Scale the drawing when we resize the canvas
37-
scaleOnResize: React.PropTypes.bool
40+
scaleOnResize: React.PropTypes.bool,
41+
// Default initial data
42+
defaultData: React.PropTypes.object,
43+
// Type of initial data
44+
defaultDataType: React.PropTypes.oneOf(['json', 'url'])
3845
};
3946

4047
static defaultProps = {
@@ -44,7 +51,8 @@ class SketchField extends React.Component {
4451
opacity: 1.0,
4552
undoSteps: 15,
4653
scaleOnResize: true,
47-
tool: Tool.Pencil
54+
tool: Tool.Pencil,
55+
defaultDataType: 'json'
4856
};
4957

5058
constructor(props, context) {
@@ -65,18 +73,23 @@ class SketchField extends React.Component {
6573
}
6674

6775
componentDidMount() {
76+
let {tool,
77+
undoSteps,
78+
defaultData,
79+
defaultDataType} = this.props;
80+
6881
let canvas = this._fc = new fabric.Canvas(this._canvas.id);
6982
this._initTools(canvas);
7083

71-
let tool = this._tools[this.props.tool];
72-
tool.configureCanvas(this.props);
84+
let selectedTool = this._tools[tool];
85+
selectedTool.configureCanvas(this.props);
7386

7487
// Control resize
7588
window.addEventListener('resize', this._resize, false);
7689
this._resize(null);
7790

7891
// Initialize History, with maximum number of undo steps
79-
this._history = new History(this.props.undoSteps);
92+
this._history = new History(undoSteps);
8093

8194
// Events binding
8295
canvas.on('object:added', this._onObjectAdded);
@@ -86,6 +99,18 @@ class SketchField extends React.Component {
8699
canvas.on('mouse:move', this._onMouseMove);
87100
canvas.on('mouse:up', this._onMouseUp);
88101
canvas.on('mouse:out', this._onMouseOut);
102+
103+
// initialize canvas with default data
104+
setTimeout(() => {
105+
if (defaultData) {
106+
if ('json' === defaultDataType) {
107+
this.fromJson(defaultData);
108+
}
109+
if ('url' === defaultDataType) {
110+
this.fromDataURL(defaultData);
111+
}
112+
}
113+
}, 100)
89114
}
90115

91116
_initTools(fabricCanvas) {
@@ -102,11 +127,8 @@ class SketchField extends React.Component {
102127
}
103128

104129
componentWillReceiveProps(props) {
105-
//if (this.props.tool !== props.tool) {
106-
// tool has changed
107130
let tool = this._tools[props.tool] || this._tools['pencil'];
108131
tool.configureCanvas(props);
109-
//}
110132
}
111133

112134
_onObjectAdded(e) {
@@ -154,17 +176,19 @@ class SketchField extends React.Component {
154176
if (tool) {
155177
tool.doMouseUp(e);
156178
}
157-
//// there is no direct on change event
158-
//if (this.props.onChange) {
159-
// this.props.onChange(event.e, this._fc.toDataURL('png'));
160-
//}
179+
if (this.props.onChange) {
180+
this.props.onChange(event.e);
181+
}
161182
}
162183

163184
_onMouseOut(e) {
164185
let tool = this._tools[this.props.tool];
165186
if (tool) {
166187
tool.doMouseOut(e);
167188
}
189+
if (this.props.onChange) {
190+
this.props.onChange(event.e);
191+
}
168192
}
169193

170194
/**
@@ -244,6 +268,7 @@ class SketchField extends React.Component {
244268
let history = this._history;
245269
if (history.canRedo()) {
246270
let canvas = this._fc;
271+
//noinspection Eslint
247272
let [obj,prevState,currState] = history.redo();
248273
if (obj.version === 0) {
249274
this.setState({action: false}, () => {
@@ -278,12 +303,65 @@ class SketchField extends React.Component {
278303
}
279304

280305
/**
281-
* Get the current content from Canvas
306+
* Exports canvas element to a dataurl image. Note that when multiplier is used, cropping is scaled appropriately
307+
*
308+
* Available Options are
309+
* <table style="width:100%">
310+
*
311+
* <tr><td><b>Name</b></td><td><b>Type</b></td><td><b>Argument</b></td><td><b>Default</b></td><td><b>Description</b></td></tr>
312+
* <tr><td>format</td> <td>String</td> <td><optional></td><td>png</td><td>The format of the output image. Either "jpeg" or "png"</td></tr>
313+
* <tr><td>quality</td><td>Number</td><td><optional></td><td>1</td><td>Quality level (0..1). Only used for jpeg.</td></tr>
314+
* <tr><td>multiplier</td><td>Number</td><td><optional></td><td>1</td><td>Multiplier to scale by</td></tr>
315+
* <tr><td>left</td><td>Number</td><td><optional></td><td></td><td>Cropping left offset. Introduced in v1.2.14</td></tr>
316+
* <tr><td>top</td><td>Number</td><td><optional></td><td></td><td>Cropping top offset. Introduced in v1.2.14</td></tr>
317+
* <tr><td>width</td><td>Number</td><td><optional></td><td></td><td>Cropping width. Introduced in v1.2.14</td></tr>
318+
* <tr><td>height</td><td>Number</td><td><optional></td><td></td><td>Cropping height. Introduced in v1.2.14</td></tr>
319+
*
320+
* </table>
321+
*
322+
* @returns {String} URL containing a representation of the object in the format specified by options.format
323+
*/
324+
toDataURL(options) {
325+
return this._fc.toDataURL(options);
326+
}
327+
328+
/**
329+
* Returns JSON representation of canvas
330+
*
331+
* @param propertiesToInclude Array <optional>
332+
Any properties that you might want to additionally include in the output
333+
* @returns {string} JSON string
334+
*/
335+
toJSON(propertiesToInclude) {
336+
return this._fc.toJSON(propertiesToInclude);
337+
}
338+
339+
/**
340+
* Populates canvas with data from the specified JSON.
282341
*
283-
* @returns {null} the data of the canvas
342+
* JSON format must conform to the one of fabric.Canvas#toDatalessJSON
343+
*
344+
* @param json JSON string or object
345+
* @param callback Callback, invoked when json is parsed and corresponding objects (e.g: fabric.Image) are initialized
346+
* @param reviver Method for further parsing of JSON elements, called after each fabric object created.
347+
284348
*/
285-
getContent() {
286-
return this.state.content;
349+
fromJson(json) {
350+
let canvas = this._fc;
351+
canvas.loadFromJSON(json, () => canvas.renderAll());
352+
}
353+
354+
/**
355+
* This method will create an image and load the given url data
356+
*
357+
* @param data URL data to load as image
358+
* @param options options to be applied to image <optional>
359+
*/
360+
fromDataURL(data, options = {}) {
361+
let canvas = this._fc;
362+
let img = new Image();
363+
img.src = data;
364+
img.onload = () => canvas.add(new fabric.Image(img, options));
287365
}
288366

289367
/**
@@ -304,7 +382,7 @@ class SketchField extends React.Component {
304382
...other
305383
} = this.props;
306384
return (
307-
<div className={className} style={style} ref={(c) => this._canvasWrapper = c}>
385+
<div className={className} style={style}>
308386
<canvas
309387
id={uuid4()}
310388
height={height || 512}

src/circle.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
/*eslint no-unused-vars: 0*/
2+
'use strict';
3+
14
import FabricCanvasTool from './fabrictool'
25
const fabric = require('fabric').fabric;
36
import {linearDistance} from './utils';

src/fabrictool.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
/* eslint no-unused-vars: 0 */
2+
'use strict';
3+
14
/**
25
* "Abstract" like base class for a Canvas tool
36
*/

src/history.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ class History {
121121

122122
print() {
123123
if (this.debug) {
124+
/*eslint-disable no-console*/
124125
console.log(this.undoList, ' -> ' + this.current + ' <- ', this.redoList.slice(0).reverse());
125126
}
126127
}

src/line.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
/*eslint no-unused-vars: 0*/
2+
'use strict';
3+
14
import FabricCanvasTool from './fabrictool'
2-
import {pointerPosition} from './utils';
35

46
const fabric = require('fabric').fabric;
57

@@ -39,11 +41,11 @@ class Line extends FabricCanvasTool {
3941
canvas.renderAll();
4042
}
4143

42-
doMouseUp(event) {
44+
doMouseUp(o) {
4345
this.isDown = false;
4446
}
4547

46-
doMouseOut(event) {
48+
doMouseOut(o) {
4749
this.isDown = false;
4850
}
4951
}

src/pencil.js

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
'use strict';
2+
13
import FabricCanvasTool from './fabrictool'
2-
import {pointerPosition} from './utils';
34

45
class Pencil extends FabricCanvasTool {
56

@@ -10,36 +11,6 @@ class Pencil extends FabricCanvasTool {
1011
freeDrawingBrush.width = props.lineWidth;
1112
freeDrawingBrush.color = props.lineColor;
1213
}
13-
14-
doMouseUp(event) {
15-
this._isMouseDown = false;
16-
}
17-
18-
doMouseDown(event) {
19-
//let [_x, _y] = pointerPosition(event);
20-
//// store initial position of mouse
21-
//[this._startX, this._startY] = [_x, _y];
22-
//[this._x, this._y] = [_x, _y];
23-
//// Start Drawing
24-
//this._isMouseDown = true;
25-
}
26-
27-
doMouseMove(event) {
28-
//let [_prevX,_prevY] = [this._x, this._y];
29-
//let [_currX, _currY] = pointerPosition(event);
30-
//if (this._isMouseDown) {
31-
// this._ctx.beginPath();
32-
// this._ctx.moveTo(_prevX, _prevY);
33-
// this._ctx.lineTo(_currX, _currY);
34-
// this._ctx.stroke();
35-
// this._ctx.closePath();
36-
//}
37-
//[this._x, this._y] = [_currX, _currY];
38-
}
39-
40-
doMouseOut(event) {
41-
//this._isMouseDown = false;
42-
}
4314
}
4415

4516
export default Pencil;

src/rectangle.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
/*eslint no-unused-vars: 0*/
2+
'use strict';
3+
14
import FabricCanvasTool from './fabrictool'
25
const fabric = require('fabric').fabric;
36

0 commit comments

Comments
 (0)