diff --git a/README.md b/README.md index 3608337..6f91ec5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,169 @@ -react-designer -===================== +React-designer +============== + +Easy to configure, lightweight, editable vector graphics in your react components. + +- Supports polygon and shape designing (with bezier curves) +- Implemented default scale, rotate, drag, and arrange actions +- Custom object types and custom panels + + +Examples and demonstration: + + +![bezier editor](http://i.imgur.com/cqTleWB.gif) + +### Component: Designer + +This is the main canvas component which holds the all toolset and manages all drawing data. You could use this component to create drawing canvas. + +An example with default configuration: + + import Designer, {Text, Rectangle} from 'react-designer'; + + class App() { + state = { + objects: [ + {type: "text", x: 10, y: 20, text: "Hello!", fill: "red"}, + {type: "rect", x: 50, y: 70, fill: "red"} + ] + } + + render() { + return ( + this.setState({objects})} + objects={this.state.objects} /> + ) + } + } + +The `Designer` component expects the following parameters: + +| Parameter | Default | | +| :------------- |:------------------------------- | :----- | +| width | 300 | The width of document | +| height | 300 | The height of document | +| canvasWidth | null | The width of canvas. Same with document if it's null. | +| canvasHeight | null | The height of canvas. Same with document if it's null. | +| objects | [] | Your object set. | +| onUpdate | [] | Your update callback. | +| objectTypes | Text, Circle, Rectangle, Path | Mapping of object types. | +| snapToGrid | 1 | Snaps the objects accordingly this multipier. | + + +Object types are pure react components which are derived from `Vector`. + +### Component: Vector + +You can create an object type by subclassing `Vector` component. Each object types have static `meta` object which contains `icon` and `initial`, and optionally `editor` value. + +Example implementation: + + class MyRectangle extends Vector { + static meta = { + icon: , + initial: { + width: 5, + height: 5, + strokeWidth: 0, + fill: "yellow", + radius: 5, + blendMode: "normal" + } + }; + + render() { + let {object, index} = this.props; + return ( + + ); + } + } + +You can register this object type in your `Designer` instance. + + + +Apart from meta options, the vectors have `panels` static definition which contains the available panels of their. + +Here is default panels in Vector component: + + static panels = [ + SizePanel, + TextPanel, + StylePanel, + ArrangePanel + ]; + +### Component: Panel + +You could extend this component to create completely different panel instead of builtins. + +It's a pure React component. The component have `object` and `onUpdate` props. You could reach the current state with `object`, and change this state with `onChange` callback. Let's create a dummy panel. + + class MyPanel extends Panel { + render() { + let {object, onChange} = this.props; + return ( + + + + + + + + + + + ); + } + } + +### Component: Preview + +You can use `Preview` component to disable editing tool set and controllers. This component just renders the SVG output of your data. It may be useful for presenting edited or created graphic, instead of building a SVG file. + +The parameters are same with Designer component, except the onUpdate callback is not necessarry. + + + +### To-do + +I built this project to create user designed areas in my side project. So, this was a just hobby project, there may be things missing for a svg editor. I'm open to pull requests and feedback, and I need help to maintain. + +Here is a todo list that in my mind. You could extend this list. + +- Implement `Export` panel + - Export selected object + - Export document +- Write initial tests and setup test environment +- Add a key map to keep the ratio of objects when scaling +- Implement theme support for UI + +### Contributors (You can add your name here in your pull-request) + +- Fatih Erikli diff --git a/examples/App.js b/examples/App.js index af70a9b..4b34041 100644 --- a/examples/App.js +++ b/examples/App.js @@ -17,12 +17,12 @@ export default class App extends Component {

react-designer

-

Configurable design component for react

+

Easy to configure, lightweight, editable vector graphics in your react components.

@@ -54,7 +54,7 @@ class App() { } `}
-

Examples

+

Examples

Mondrian

@@ -62,7 +62,7 @@ class App() { container component.

Enabled all default drawing tool set and panels.

- Show example on github + Show example on github

@@ -78,7 +78,7 @@ class App() {

You can double-click to edit shapes.

- Show example on github + Show example on github

@@ -93,7 +93,7 @@ class App() { container component.

- Show example on github + Show example on github

@@ -119,7 +119,7 @@ class App() {

You can extend builtin components, or write entirely different objects

- Show example on github + Show example on github

@@ -138,8 +138,8 @@ class App() { For example price is instantly changing while you resizing objects or typing a text.

- Show example on github
- Show calculatePrice() function + Show example on github
+ Show calculatePrice() function

diff --git a/examples/components/Malevich.js b/examples/components/Malevich.js index 5753c0b..115a1ad 100644 --- a/examples/components/Malevich.js +++ b/examples/components/Malevich.js @@ -299,32 +299,6 @@ export default class extends Component { "type": "polygon", "x": 135, "y": 120.5625 - }, { - "fill": "rgba(178, 115, 33, 1)", - "closed": true, - "rotate": 0, - "moveX": 133, - "moveY": 4.5625, - "path": [{"x1": 133, "y1": 4.5625, "x2": 290, "y2": 338.5625, "x": 290, "y": 338.5625}, { - "x1": 290, - "y1": 338.5625, - "x2": 349, - "y2": 309.5625, - "x": 349, - "y": 309.5625 - }, {"x1": 349, "y1": 309.5625, "x2": 349, "y2": 208.5625, "x": 349, "y": 208.5625}, { - "x1": 349, - "y1": 208.5625, - "x2": 255, - "y2": 3.5625, - "x": 255, - "y": 3.5625 - }, {"x1": 255, "y1": 3.5625, "x2": 133, "y2": 4.5625, "x": 133, "y": 4.5625}], - "stroke": "gray", - "strokeWidth": "0", - "type": "polygon", - "x": 131, - "y": 1.5625 }, { "fill": "rgba(133, 34, 8, 1)", "closed": true, diff --git a/examples/components/MockupDesigner.js b/examples/components/MockupDesigner.js index 28e135f..653ba53 100644 --- a/examples/components/MockupDesigner.js +++ b/examples/components/MockupDesigner.js @@ -95,7 +95,7 @@ export class _Input extends Vector { }; return ( - {object.text} + onUpdate={this.handleUpdate.bind(this)}/>

Export SVG

diff --git a/examples/components/TshirtDesigner.js b/examples/components/TshirtDesigner.js index 5d38f80..082508b 100644 --- a/examples/components/TshirtDesigner.js +++ b/examples/components/TshirtDesigner.js @@ -1,5 +1,6 @@ import React, {Component} from 'react'; -import Designer, {styles as designerStyles} from '../../src/Designer'; +import Designer from '../../src/Designer'; +import {styles as canvasStyles} from '../../src/SVGRenderer'; import {Text, Rect, Circle} from '../../src/objects/index'; const priceMap = { @@ -8,10 +9,8 @@ const priceMap = { 'circle': ({width, height}) => width * (height || width) * 0.001 }; -const calculatePrice = ( - objects, - initialCost = 5 -) => ( +const calculatePrice = (objects, + initialCost = 5) => ( objects.map( ({type, ...rest}) => priceMap[type](rest) @@ -24,7 +23,7 @@ const calculatePrice = ( const Background = ({style}) => ( + Z" style={style}/> ); @@ -49,7 +48,43 @@ export default class extends Component { state = { objects: [ - {"text":"COME TO THE","rotate":0,"fontWeight":"bold","fontStyle":"normal","textDecoration":"none","fill":"rgba(11, 10, 10, 1)","fontSize":"20","fontFamily":"AmericanTypewriter, Georgia, serif","type":"text","x":175,"y":153},{"text":"REACT","rotate":0,"fontWeight":"bold","fontStyle":"normal","textDecoration":"none","fill":"rgba(0, 0, 0, 1)","fontSize":"47","fontFamily":"AmericanTypewriter, Georgia, serif","type":"text","x":176,"y":183},{"text":"SIDE","rotate":0,"fontWeight":"bold","fontStyle":"normal","textDecoration":"none","fill":"rgba(0, 0, 0, 1)","fontSize":"25","fontFamily":"AmericanTypewriter, Georgia, serif","type":"text","x":171,"y":216} + { + "text": "COME TO THE", + "rotate": 0, + "fontWeight": "bold", + "fontStyle": "normal", + "textDecoration": "none", + "fill": "rgba(11, 10, 10, 1)", + "fontSize": "20", + "fontFamily": "AmericanTypewriter, Georgia, serif", + "type": "text", + "x": 175, + "y": 153 + }, { + "text": "FRONT", + "rotate": 0, + "fontWeight": "bold", + "fontStyle": "normal", + "textDecoration": "none", + "fill": "rgba(0, 0, 0, 1)", + "fontSize": "47", + "fontFamily": "AmericanTypewriter, Georgia, serif", + "type": "text", + "x": 176, + "y": 183 + }, { + "text": "END", + "rotate": 0, + "fontWeight": "bold", + "fontStyle": "normal", + "textDecoration": "none", + "fill": "rgba(0, 0, 0, 1)", + "fontSize": "25", + "fontFamily": "AmericanTypewriter, Georgia, serif", + "type": "text", + "x": 171, + "y": 216 + } ] }; @@ -64,7 +99,7 @@ export default class extends Component { fill: "#fff989", stroke: "#808080", strokeWidth: 2 - }} /> + }}/> - Price: {calculatePrice(this.state.objects).toFixed(2)}$ + Tshirt Price: {calculatePrice(this.state.objects).toFixed(2)}$
); diff --git a/package.json b/package.json index 51be75a..c976692 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "react-designer", - "version": "1.0.0", - "description": "React designer tool", + "version": "1.0.3", + "description": "Easy to configure, lightweight, editable vector graphics in your react components.", "main": "lib/Select.js", "scripts": { "start": "node server.js", diff --git a/server.js b/server.js index f77cd81..c0f1d17 100644 --- a/server.js +++ b/server.js @@ -5,7 +5,7 @@ var config = require('./webpack.config'); new WebpackDevServer(webpack(config), { publicPath: config.output.publicPath, hot: true -}).listen(3000, 'localhost', function (err) { +}).listen(3000, '127.0.0.1', function (err) { if (err) { console.log(err); } diff --git a/src/Designer.js b/src/Designer.js index a78c7f7..b2c22dd 100644 --- a/src/Designer.js +++ b/src/Designer.js @@ -134,7 +134,7 @@ class Designer extends Component { currentObjectIndex: objects.length, selectedObjectIndex: objects.length, startPoint: this.getStartPointBundle(event, object), - mode: meta.mode || modes.SCALE, + mode: meta.editor ? modes.EDIT_OBJECT : modes.SCALE, selectedTool: null }); diff --git a/src/Handler.js b/src/Handler.js index 2fc3711..5d10134 100644 --- a/src/Handler.js +++ b/src/Handler.js @@ -37,6 +37,8 @@ RotateAnchor = Radium(RotateAnchor); class Handler extends Component { onMouseDown(event) { + // event.preventDefault(); + if (event.target.classList.contains('handler')) { this.props.onDrag(event); } diff --git a/src/SVGRenderer.js b/src/SVGRenderer.js index fcc2f3c..bbfab1e 100644 --- a/src/SVGRenderer.js +++ b/src/SVGRenderer.js @@ -50,7 +50,7 @@ class SVGRenderer extends Component { } } -const styles = { +export const styles = { canvas: { backgroundSize: 400 }, diff --git a/src/objects/Rect.js b/src/objects/Rect.js index e8f6f2f..66bd605 100644 --- a/src/objects/Rect.js +++ b/src/objects/Rect.js @@ -13,8 +13,9 @@ export default class Rect extends Vector { height: 5, strokeWidth: 0, fill: "blue", - radius: 5, - blendMode: "normal" + radius: 0, + blendMode: "normal", + rotate: 0 } }; diff --git a/src/objects/Text.js b/src/objects/Text.js index 7d07a91..1ba06f3 100644 --- a/src/objects/Text.js +++ b/src/objects/Text.js @@ -14,8 +14,8 @@ export default class Text extends Vector { fontWeight: "normal", fontStyle: "normal", textDecoration: "none", - fill: "red", - fontSize: 12, + fill: "black", + fontSize: 50, fontFamily: "Helvetica" } };