dimanche 24 janvier 2016

Grouping functionality in JavaScript using an Object

I am creating a drawing-app. I want to have a toolbar populated with tools. Each tool is defined in a separate js file. Right now i have defined each tool as an object that contains functions and variables that dictate it's behavior, for example i have 'setDragBehaviour()' and setDrawBehaviour()'.

All these functions interact with variables in the global scope such as the Canvas and an Array containing all objects on the Canvas. This is very messy, as i have to reference 'this' in some of the functions to call other class functions\variables, but at the same time i bind these object functions to the canvas with events and such. It feels like a big Spaghetti.

Do you have any tips or general direction for a better more maintainable design, maybe a suggested pattern ? Here is my code :

var tool_rectangle = {
  name : 'Rectangle',
  setDragBehavior : function(element) {
    var start = function() {
            this.ox = this.attr("x");
            this.oy = this.attr("y");
            this.dx = 0
            this.dy = 0
            in_drag = true;
        },
        move = function(dx, dy) {

          mx = (parseInt(dx) - parseInt(this.dx)),
          my = (parseInt(dy) - parseInt(this.dy))
            var att = {
                x: mx,
                y: my
            }
            this.attr(att);
        },
        stop = function(){
          in_drag = false;
        };
        element.drag(move,start,stop)
  },
  creation : function(e,tags){
    //NEW ELEMENT CREATED
    if(tags==null)
    {
      x = e.offsetX
      y = e.offsetY
      size = 100
      initial_element = s.rect(x-size/2,y-size/2,size,size).attr({fill:"#000",
       "fill-opacity": 0.25, stroke:"#ff0000", strokeWidth:2});
    }else{// LOAD EXISTING ELEMENT
      initial_element = s.rect(tags);
    }
    return initial_element;
  },
  initial : function (e,tags){
    initial_element = this.creation(e,tags);
    initial_element.click(this.mount.bind(initial_element,this));
    initial_element.drag(move.bind(initial_element), start.bind(initial_element));
    elements.add(initial_element);
  },
  mount : function(tool){
    React.unmountComponentAtNode(document.getElementById('options_mount_point'));
    React.render(<tool.component svg={this}/>,
      document.getElementById("options_mount_point"));
  },
// RECTANGLE TAG TOOL > PROPERTIES PANEL
  component : React.createClass({
  mixins: [React.addons.LinkedStateMixin],
  getInitialState: function(){
      snap = this.props.svg
      stroke = snap.attr('stroke')
      fill = snap.attr('fill')
      fill_opacity = snap.attr('fill-opacity')
      strokeWidth = snap.attr('strokeWidth')
      x = snap.attr('x')
      y = snap.attr('y')
      return {'x':x, 'y':y, 'stroke': stroke, 'fill':fill, 'fill-opacity':fill_opacity, 'strokeWidth':strokeWidth, 'svg':snap}
  },
  componentDidUpdate: function(prevProps, prevState){
    //After changing the values in the properties we must update the SVG object itself.
    //Updates Snap.svg component with new attrs
    this.state.svg.attr(this.state);
  },
  render : function(){
    return (
      <div>
      <b>Rectangle Properties</b><br/>
      <label for="stroke_color">Stroke Color:</label>
      <input type="text" id="stroke_color" valueLink={this.linkState("stroke")} placeholder="Stroke color"></input><br/>
      <label for="fill_color">Fill Color:</label>
      <input type="text" id="fill_color" valueLink={this.linkState("fill")} placeholder="Fill color"></input><br/>
      <label for="fill_opacity">Fill Opacity:</label>
      <input type="float" id="fill_opacity" valueLink={this.linkState("fill-opacity")} placeholder="Fill opacity"></input><br/>
      <label for="stroke_width">Stroke width:</label>
      <input type="text" id="stroke_width" valueLink={this.linkState("strokeWidth")} placeholder="Stroke width"></input><br/>
      <label for="fill_opacity">X:</label><br/>
      <input type="float" id="x" valueLink={this.linkState("x")} placeholder="X"></input><br/>
      <label for="stroke_width">Y:</label><br/>
      <input type="text" id="y" valueLink={this.linkState("y")} placeholder="Y"></input><br/>
      </div>
    );
  },

})


}// END OF TOOL

Aucun commentaire:

Enregistrer un commentaire