Skip to content

Commit

Permalink
Merge pull request tbolis#101 from tarik-djurdjevic/rectangle_label_tool
Browse files Browse the repository at this point in the history
Rectangle label tool
  • Loading branch information
tbolis authored Apr 8, 2020
2 parents aeb079d + f2e5e62 commit c233250
Show file tree
Hide file tree
Showing 9 changed files with 482 additions and 142 deletions.
1 change: 1 addition & 0 deletions examples/main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ class SketchFieldDemo extends React.Component {
<MenuItem value={Tools.Rectangle} key="Rectangle">Rectangle</MenuItem>
<MenuItem value={Tools.Circle} key="Circle">Circle</MenuItem>
<MenuItem value={Tools.Pan} key="Pan">Pan</MenuItem>
<MenuItem value={Tools.RectangleLabel} key="Pan">RectangleLabel</MenuItem>
</TextField>
</div>
</div>
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-sketch",
"version": "0.5.1",
"name": "@tarik.djurdjevic/react-sketch",
"version": "0.5.6",
"description": "Sketch Element for React based applications, backed-up by fabricjs as its core",
"keywords": [
"react",
Expand Down Expand Up @@ -31,7 +31,7 @@
"lint": "eslint ./src",
"lint:fix": "eslint --fix ./src",
"precommit": "lint-staged",
"prepublish": "npm run test && npm run build",
"prepublish": "npm run build",
"prebuild": "rimraf dist",
"start": "node webpack/server.js",
"start:debug": "weinre --boundHost `my-local-ip` ",
Expand Down Expand Up @@ -92,7 +92,7 @@
"babel-jest": "23.6.0",
"babel-loader": "8.0.4",
"babel-plugin-lodash": "3.3.4",
"canvas": "^1.6.12",
"canvas": "^2.6.0",
"cross-env": "^5.2.0",
"css-loader": "^1.0.1",
"enzyme": "3.7.0",
Expand All @@ -105,7 +105,7 @@
"eslint-plugin-jsx-a11y": "6.1.2",
"eslint-plugin-react": "7.11.1",
"eslint-watch": "4.0.2",
"fabric": "2.4.3",
"fabric": "^3.5.1",
"flexboxgrid": "^6.3.1",
"html-webpack-plugin": "^3.2.0",
"jasmine-core": "^3.3.0",
Expand Down
115 changes: 88 additions & 27 deletions src/SketchField.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import Rectangle from './rectangle';
import Circle from './circle';
import Pan from './pan';
import Tool from './tools';
import RectangleLabel from './rectangle-label';
import DefaultTool from './defaul-tool';

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

Expand Down Expand Up @@ -54,6 +56,26 @@ class SketchField extends PureComponent {
width: PropTypes.number,
// Sketch height
height: PropTypes.number,
// event object added
onObjectAdded: PropTypes.func,
// event object modified
onObjectModified: PropTypes.func,
// event object removed
onObjectRemoved: PropTypes.func,
// event mouse down
onMouseDown: PropTypes.func,
// event mouse move
onMouseMove: PropTypes.func,
// event mouse up
onMouseUp: PropTypes.func,
// event mouse out
onMouseOut: PropTypes.func,
// event object move
onObjectMoving: PropTypes.func,
// event object scale
onObjectScaling: PropTypes.func,
// event object rotating
onObjectRotating: PropTypes.func,
// Class name to pass to container div of canvas
className: PropTypes.string,
// Style options to pass to container div of canvas
Expand All @@ -67,10 +89,20 @@ class SketchField extends PureComponent {
backgroundColor: 'transparent',
opacity: 1.0,
undoSteps: 25,
tool: Tool.Pencil,
widthCorrection: 2,
tool: null,
widthCorrection: 0,
heightCorrection: 0,
forceValue: false
forceValue: false,
onObjectAdded:()=>null,
onObjectModified:()=>null,
onObjectRemoved:()=>null,
onMouseDown:()=>null,
onMouseMove:()=>null,
onMouseUp:()=>null,
onMouseOut:()=>null,
onObjectMoving:()=>null,
onObjectScaling:()=>null,
onObjectRotating:()=>null,
};

state = {
Expand All @@ -84,8 +116,10 @@ class SketchField extends PureComponent {
this._tools[Tool.Line] = new Line(fabricCanvas);
this._tools[Tool.Arrow] = new Arrow(fabricCanvas);
this._tools[Tool.Rectangle] = new Rectangle(fabricCanvas);
this._tools[Tool.RectangleLabel] = new RectangleLabel(fabricCanvas);
this._tools[Tool.Circle] = new Circle(fabricCanvas);
this._tools[Tool.Pan] = new Pan(fabricCanvas)
this._tools[Tool.Pan] = new Pan(fabricCanvas);
this._tools[Tool.DefaultTool] = new DefaultTool(fabricCanvas);
};

/**
Expand Down Expand Up @@ -141,6 +175,7 @@ class SketchField extends PureComponent {
* Action when an object is added to the canvas
*/
_onObjectAdded = (e) => {
const {onObjectAdded} = this.props;
if (!this.state.action) {
this.setState({ action: true });
return
Expand All @@ -153,30 +188,35 @@ class SketchField extends PureComponent {
let state = JSON.stringify(objState);
// object, previous state, current state
this._history.keep([obj, state, state])
onObjectAdded(e);
};

/**
* Action when an object is moving around inside the canvas
*/
_onObjectMoving = (e) => {

const {onObjectMoving} = this.props;
onObjectMoving(e);
};

/**
* Action when an object is scaling inside the canvas
*/
_onObjectScaling = (e) => {

const {onObjectScaling} = this.props;
onObjectScaling(e);
};

/**
* Action when an object is rotating inside the canvas
*/
_onObjectRotating = (e) => {

const {onObjectRotating} = this.props;
onObjectRotating(e);
};

_onObjectModified = (e) => {
const {onObjectModified} = this.props;
let obj = e.target;
obj.__version += 1;
let prevState = JSON.stringify(obj.__originalState);
Expand All @@ -185,48 +225,58 @@ class SketchField extends PureComponent {
obj.__originalState = objState;
let currState = JSON.stringify(objState);
this._history.keep([obj, prevState, currState]);
onObjectModified(e);
};

/**
* Action when an object is removed from the canvas
*/
_onObjectRemoved = (e) => {
const {onObjectRemoved} = this.props;
let obj = e.target;
if (obj.__removed) {
obj.__version += 1;
return
}
obj.__version = 0;
onObjectRemoved(e);
};

/**
* Action when the mouse button is pressed down
*/
_onMouseDown = (e) => {
const{onMouseDown} = this.props;
this._selectedTool.doMouseDown(e);
onMouseDown(e);
};

/**
* Action when the mouse cursor is moving around within the canvas
*/
_onMouseMove = (e) => {
const {onMouseMove} = this.props;
this._selectedTool.doMouseMove(e);
onMouseMove(e);
};

/**
* Action when the mouse cursor is moving out from the canvas
*/
_onMouseOut = (e) => {
const {onMouseOut} = this.props;
this._selectedTool.doMouseOut(e);
if (this.props.onChange) {
let onChange = this.props.onChange;
setTimeout(() => {
onChange(e.e)
}, 10)
}
onMouseOut(e);
};

_onMouseUp = (e) => {
const {onMouseUp} = this.props;
this._selectedTool.doMouseUp(e);
// Update the final state to new-generated object
// Ignore Path object since it would be created after mouseUp
Expand All @@ -245,6 +295,7 @@ class SketchField extends PureComponent {
onChange(e.e)
}, 10)
}
onMouseUp(e);
};

/**
Expand All @@ -253,13 +304,13 @@ class SketchField extends PureComponent {
* @param e the resize event
* @private
*/
_resize = (e) => {
_resize = (e, canvasWidth = null, canvasHeight = null) => {
if (e) e.preventDefault();
let { widthCorrection, heightCorrection } = this.props;
let canvas = this._fc;
let { offsetWidth, clientHeight } = this._container;
let prevWidth = canvas.getWidth();
let prevHeight = canvas.getHeight();
let prevWidth = canvasWidth || canvas.getWidth();
let prevHeight = canvasHeight || canvas.getHeight();
let wfactor = ((offsetWidth - widthCorrection) / prevWidth).toFixed(2);
let hfactor = ((clientHeight - heightCorrection) / prevHeight).toFixed(2);
canvas.setWidth(offsetWidth - widthCorrection);
Expand Down Expand Up @@ -437,6 +488,10 @@ class SketchField extends PureComponent {
let canvas = this._fc;
setTimeout(() => {
canvas.loadFromJSON(json, () => {
if(this.props.tool === Tool.DefaultTool){
canvas.isDrawingMode = canvas.selection = false;
canvas.forEachObject((o) => o.selectable = o.evented = false);
}
canvas.renderAll();
if (this.props.onChange) {
this.props.onChange()
Expand Down Expand Up @@ -565,6 +620,11 @@ class SketchField extends PureComponent {
canvas.add(iText);
};

callEvent = (e, eventFunction) => {
if(this._selectedTool)
eventFunction(e);
}

componentDidMount = () => {
let {
tool,
Expand All @@ -586,7 +646,8 @@ class SketchField extends PureComponent {
this._backgroundColor(backgroundColor)

let selectedTool = this._tools[tool];
selectedTool.configureCanvas(this.props);
if(selectedTool)
selectedTool.configureCanvas(this.props);
this._selectedTool = selectedTool;

// Control resize
Expand All @@ -596,16 +657,16 @@ class SketchField extends PureComponent {
this._history = new History(undoSteps);

// Events binding
canvas.on('object:added', this._onObjectAdded);
canvas.on('object:modified', this._onObjectModified);
canvas.on('object:removed', this._onObjectRemoved);
canvas.on('mouse:down', this._onMouseDown);
canvas.on('mouse:move', this._onMouseMove);
canvas.on('mouse:up', this._onMouseUp);
canvas.on('mouse:out', this._onMouseOut);
canvas.on('object:moving', this._onObjectMoving);
canvas.on('object:scaling', this._onObjectScaling);
canvas.on('object:rotating', this._onObjectRotating);
canvas.on('object:added', e => this.callEvent(e, this._onObjectAdded));
canvas.on('object:modified', e => this.callEvent(e, this._onObjectModified));
canvas.on('object:removed', e => this.callEvent(e, this._onObjectRemoved));
canvas.on('mouse:down', e => this.callEvent(e, this._onMouseDown));
canvas.on('mouse:move', e => this.callEvent(e, this._onMouseMove));
canvas.on('mouse:up', e => this.callEvent(e, this._onMouseUp));
canvas.on('mouse:out', e => this.callEvent(e, this._onMouseOut));
canvas.on('object:moving', e => this.callEvent(e, this._onObjectMoving));
canvas.on('object:scaling', e => this.callEvent(e, this._onObjectScaling));
canvas.on('object:rotating', e => this.callEvent(e, this._onObjectRotating));
// IText Events fired on Adding Text
// canvas.on("text:event:changed", console.log)
// canvas.on("text:selection:changed", console.log)
Expand All @@ -632,13 +693,14 @@ class SketchField extends PureComponent {
}

if (this.props.tool !== prevProps.tool) {
this._selectedTool = this._tools[this.props.tool] || this._tools[Tool.Pencil]
this._selectedTool = this._tools[this.props.tool];
//Bring the cursor back to default if it is changed by a tool
this._fc.defaultCursor = 'default';
if(this._selectedTool){
this._selectedTool.configureCanvas(this.props);
}
}

//Bring the cursor back to default if it is changed by a tool
this._fc.defaultCursor = 'default';
this._selectedTool.configureCanvas(this.props);

if (this.props.backgroundColor !== prevProps.backgroundColor) {
this._backgroundColor(this.props.backgroundColor)
}
Expand All @@ -659,7 +721,6 @@ class SketchField extends PureComponent {
let canvasDivStyle = Object.assign({}, style ? style : {},
width ? { width: width } : {},
height ? { height: height } : { height: 512 });

return (
<div
className={className}
Expand Down
19 changes: 19 additions & 0 deletions src/defaul-tool.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*eslint no-unused-vars: 0*/

import FabricCanvasTool from './fabrictool'

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

class DefaultTool extends FabricCanvasTool {
configureCanvas(props) {
let canvas = this._canvas;
canvas.isDrawingMode = canvas.selection = false;
canvas.forEachObject((o) => o.selectable = o.evented = false);
canvas.discardActiveObject();
canvas.defaultCursor = 'pointer';
canvas.renderAll();
}

}

export default DefaultTool;
35 changes: 35 additions & 0 deletions src/rectangle-label-object.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* eslint no-unused-vars: 0 */

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

class RectangleLabelObject {
constructor(canvas, text, rectProps, textProps){
this._canvas = canvas;
this._text = text;
this._rectObj = new fabric.Rect(rectProps);
this._textObj = new fabric.Textbox(text, textProps);
canvas.on({'object:scaling': this.update});
canvas.on({'object:moving' : this.update});
}

update = (e) => {
//e.target.set({scaleX:1, scaleY:1})
if(!this._textObj || !this._rectObj) return;
if(e.target === this._rectObj){
this._textObj.set({
'width' : this._rectObj.getScaledWidth(),
'scaleX' : 1,
'scaleY' : 1,
'top' : this._rectObj.top - this._textObj.getScaledHeight(),
'left' : this._rectObj.left,
})
}
}

setText(text) {
this._text = text;
this._textObj.set({ text });
}
}

export default RectangleLabelObject;
Loading

0 comments on commit c233250

Please sign in to comment.