Your IP : 3.147.47.202


Current Path : /usr/local/mgr5/skins/orion/src/
Upload File :
Current File : //usr/local/mgr5/skins/orion/src/svg.js

(function(exports) {
  'use strict';
  var ns = {},
      doc = document,
      hash = window.hash;
  ns.svg = 'http://www.w3.org/2000/svg';
  ns.xmlns = 'http://www.w3.org/2000/xmlns/';
  ns.xlink = 'http://www.w3.org/1999/xlink';


  var Svg = function(id, width, height, scale) {
    this.id = id;
    this.cont = document.getElementById(id);
    this.wrapper = doc.createElement('div');
    this.svg = doc.createElementNS(ns.svg, 'svg');
    this.width = width;
    this.height = height;
    this.svg.setAttribute('viewBox',
        '0 0 ' + this.width * scale + ' ' + this.height * scale);
    this.svg.setAttribute('width', this.width);
    this.svg.setAttribute('height', this.height);
    this.svg.setAttributeNS(ns.xmlns,
        'xmlns:xlink', 'http://www.w3.org/1999/xlink');
    this.wrapper.className = 'svg-wrapper';
    this.wrapper.appendChild(this.svg);
    this.layers = {};
    this.zoomRate = 1.1;
    this.curZoom = scale ?
        (- Math.round(Math.log(scale) / Math.log(this.zoomRate))) : 0;
    this.zoomDelta = scale ? (1 / scale) : 1;
    this.scale = scale || 1;
    this.elems = {};
  };

  Svg.fn = Svg.prototype;

  Svg.fn.setWidth = function(width) {
    var curWidth = this.svg.getAttribute('width'),
        viewBoxValues = this.svg.getAttribute('viewBox').split(' '),
        rateZoom = viewBoxValues[2] / curWidth;
    this.svg.setAttribute('width', width);
    viewBoxValues[2] = rateZoom * width;
    this.svg.setAttribute('viewBox', viewBoxValues.join(' '));
  };

  Svg.fn.setHeight = function(height) {
    var curHeight = this.svg.getAttribute('height'),
        viewBoxValues = this.svg.getAttribute('viewBox').split(' '),
        rateZoom = viewBoxValues[3] / curHeight;
    this.svg.setAttribute('height', height);
    viewBoxValues[3] = rateZoom * height;
    this.svg.setAttribute('viewBox', viewBoxValues.join(' '));
  };

  Svg.fn.append = function() {
    this.cont.appendChild(this.wrapper);
    this.viewBoxMoveInit();
    this.setBorder();
    this.viewBoxZoomInit();
  };

  Svg.fn.setBorder = function() {
    var border = this.square('def-border', {
      x: 0, y: 0, width: this.width,
      height: this.height, 'class': 'default-border' });
    this.svg.appendChild(border.elem);
  };
  //@todo do it like options
  Svg.fn.viewBoxMoveInit = function() {
    this.svg.addEventListener('mousedown', this.viewBoxDrag.bind(this), true);
  };

  Svg.fn.viewBoxZoomInit = function() {
    //this.svg.addEventListener('mousewheel',
    // this.viewBoxZoom.bind(this), true);
    this.svg.addEventListener('mousewheel',
        this.viewBoxScrollMove.bind(this), false);
    this.svg.addEventListener('DOMMouseScroll',
        this.viewBoxScrollMove.bind(this), false);
    //this.zoomText = this.text('zoomInfo',
    // '100%', { id: 'zoomInfo', x: 25, y: 25 });
    //this.appendChild(this.zoomText);
  };

  Svg.fn.viewBoxZoom = function(e) {
    var wheelDelta, self = this;
    if (e.wheelDelta) {
      wheelDelta = -e.wheelDelta / 2.5;
    } else if (e.detail) { //for FF
      wheelDelta = e.detail * 16;
    } else if (e.direction) {
      wheelDelta = e.direction;
    }
    var viewBoxValues = this.svg.getAttribute('viewBox').split(' ');
    viewBoxValues[2] -= 0;
    viewBoxValues[3] -= 0;

    if (wheelDelta > 0) {
      viewBoxValues[2] /= this.zoomRate;
      viewBoxValues[3] /= this.zoomRate;
      this.curZoom += 1;
    } else {
      viewBoxValues[2] *= this.zoomRate;
      viewBoxValues[3] *= this.zoomRate;
      this.curZoom -= 1;
    }

    this.svg.setAttribute('viewBox', viewBoxValues.join(' '));

    var zoom = Math.pow(this.zoomRate, this.curZoom),
        zoomText = '100%';
    this.zoomDelta = zoom;
    if (zoom === 0) {
      zoomText = '100%';
      this.zoomDelta = 1;
    } else if (zoom > 0) {
      zoomText = (zoom * 100).toFixed(0);
    } else {
      zoomText = (zoom * 100).toFixed(0);
    }
    //this.zoomText.setContent(zoomText + '%');
    e.preventDefault();
    this.scale = 1 / this.zoomDelta;
    if (typeof this.zoomCallback === 'function') {
      clearTimeout(this.zoomCallbackTimeOut);
      this.zoomCallbackTimeOut = setTimeout(function() {
        self.zoomCallback.apply(self.master, []);
      }, 200);
    }
  };

  Svg.fn.viewBoxScrollMove = function(e) {
    this.wrapperWidth = this.width -
        ((this.svg.offsetWidth || this.svg.parentNode.offsetWidth) *
            this.scale);
    this.wrapperHeight = this.height -
        ((this.svg.offsetHeight || this.svg.parentNode.offsetHeight) *
            this.scale);
    var wheelDeltaX, wheelDeltaY;
    if (e.wheelDelta) {
      wheelDeltaX = -e.wheelDeltaX / 2.5;
      wheelDeltaY = -e.wheelDeltaY / 2.5;
    } else if (e.detail) { //for FF
      //wheelDeltaY = e.detail * 16;
      wheelDeltaX = e.axis === e.HORIZONTAL_AXIS ? e.detail * 16 : 0;
      wheelDeltaY = e.axis === e.VERTICAL_AXIS ? e.detail * 16 : 0;

    }
    var x = wheelDeltaX / this.zoomDelta,
        y = wheelDeltaY / this.zoomDelta,
        viewBox = this.svg.getAttribute('viewBox'),
        viewBoxValues = viewBox.split(' ');
    viewBoxValues[0] = viewBoxValues[0] - 0 + x;
    viewBoxValues[1] = viewBoxValues[1] - 0 + y;

    //check for borders
    if (viewBoxValues[0] < 0) {
      viewBoxValues[0] = 0;
    } else if (this.wrapperWidth < viewBoxValues[0]) {
      viewBoxValues[0] = this.wrapperWidth;
    }
    if (viewBoxValues[1] < 0) {
      viewBoxValues[1] = 0;
    } else if (this.wrapperHeight < viewBoxValues[1]) {
      viewBoxValues[1] = this.wrapperHeight;
    }
    this.svg.setAttribute('viewBox', viewBoxValues.join(' '));
    e.preventDefault();

  };

  Svg.fn.viewBoxDrag = function(e) {
    document.onmousemove = this.viewBoxMove.bind(this);
    document.onmouseup = this.viewBoxDrop.bind(this);
    this.shiftX = e.clientX;
    this.shiftY = e.clientY;
    var viewBoxValues = this.svg.getAttribute('viewBox').split(' ');
    this.defX = viewBoxValues[0] - 0;
    this.defY = viewBoxValues[1] - 0;
    this.svg.style.cursor = 'move';
    this.wrapperWidth = this.width - (this.svg.offsetWidth * this.scale);
    this.wrapperHeight = this.height - (this.svg.offsetHeight * this.scale);
    e.preventDefault();
  };

  Svg.fn.viewBoxMove = function(e) {
    var x = (this.shiftX - e.clientX) / this.zoomDelta,
        y = (this.shiftY - e.clientY) / this.zoomDelta,
        viewBox = this.svg.getAttribute('viewBox'),
        viewBoxValues = viewBox.split(' ');
    viewBoxValues[0] = this.defX + x;
    viewBoxValues[1] = this.defY + y;

    //check for borders
    if (viewBoxValues[0] < 0) {
      viewBoxValues[0] = 0;
    } else if (this.wrapperWidth < viewBoxValues[0]) {
      viewBoxValues[0] = this.wrapperWidth;
    }
    if (viewBoxValues[1] < 0) {
      viewBoxValues[1] = 0;
    } else if (this.wrapperHeight < viewBoxValues[1]) {
      viewBoxValues[1] = this.wrapperHeight;
    }
    this.svg.setAttribute('viewBox', viewBoxValues.join(' '));
    e.preventDefault();
  };

  Svg.fn.viewBoxDrop = function(e) {
    document.onmousemove = null;
    document.onmouseup = null;
    this.svg.style.cursor = null;
    e.preventDefault();
  };


  Svg.fn.appendChild = function(child) {
    if (child.elem) {
      child = child.elem;
    }
    this.svg.appendChild(child);
    return this;
  };

  Svg.fn.createLayer = function(id) {
    var g = doc.createElementNS(ns.svg, 'g');
    g.setAttributeNS(null, 'id', this.id + '-' + id);
    this.svg.appendChild(g);
    this.layers[id] = g;
  };

  Svg.fn.circle = function(name, attr, props) {
    var circle = doc.createElementNS(ns.svg, 'circle'),
        svgElement = new SvgElem(circle, name, this);
    attr = attr || {};
    props = props || {};
    svgElement.props(props);
    svgElement.attrs(attr);
    return svgElement;
  };

  Svg.fn.group = function(name, attr, props) {
    var g = doc.createElementNS(ns.svg, 'g'),
        svgElement = new SvgElem(g, name, this);
    attr = attr || {};
    props = props || {};
    svgElement.props(props);
    svgElement.attrs(attr);
    return svgElement;
  };

  Svg.fn.square = function(name, attr, props) {
    var rect = doc.createElementNS(ns.svg, 'rect'),
        svgElement = new SvgElem(rect, name, this);
    attr = attr || {};
    props = props || {};
    svgElement.props(props);
    svgElement.attrs(attr);
    return svgElement;
  };

  Svg.fn.rect = function(name, attr, props) {
    var rect = doc.createElementNS(ns.svg, 'rect'),
        svgElement = new SvgElem(rect, name, this);
    attr = attr || {};
    props = props || {};
    props.shapeType = 'rect';
    svgElement.props(props);
    svgElement.attrs(attr);
    return svgElement;
  };

  Svg.fn.text = function(name, content, attr, props) {
    var text = doc.createElementNS(ns.svg, 'text'),
        svgElement = new SvgElem(text, name, this);
    svgElement.setContent(content);
    attr = attr || {};
    props = props || {};
    props.shapeType = 'text';
    svgElement.props(props);
    svgElement.attrs(attr);
    return svgElement;
  };

  Svg.fn.image = function(name, attr, props) {
    var image = doc.createElementNS(ns.svg, 'image'),
        svgElement = new SvgElem(image, name, this);
    attr = attr || {};
    props = props || {};
    props.shapeType = 'image';
    svgElement.props(props);
    svgElement.attrs(attr);
    return svgElement;
  };

  Svg.fn.line = function(name, attr, props) {
    var line = doc.createElementNS(ns.svg, 'line'),
        svgElement = new SvgElem(line, name, this);
    attr = attr || {};
    props = props || {};
    props.shapeType = 'line';
    svgElement.props(props);
    svgElement.attrs(attr);
    return svgElement;
  };

  Svg.fn.renderRacks = function(racks) {
    var g = doc.createElementNS(svgNs, 'g'),
        rl = racks.length,
        newRack, text, coord;
    g.setAttributeNS(null, 'id', 'racks');

    while (rl--) {
      coord = {
        'x1': racks[rl].left, 'x2': racks[rl].left + racks[rl].width,
        'y1': racks[rl].top, 'y2': racks[rl].top + racks[rl].height,
        'text': racks[rl].name
      };
      newRack = this.rect(coord, {
        'fill': '#3b6fcc', 'fill-opacity': 1, 'style': 'color: #fff;' });

      text = this.text(coord, { 'stroke': '#fff' });
      newRack.appendChild(text);
      g.appendChild(newRack);
    }
    this.svg.appendChild(g);
  };

  Svg.fn.renderSetka = function() {
    var step = 30,
        inside = 4,
        hLines = Math.ceil(this.height / step / 2),
        hLinesS = hLines - 1,
        vLines = Math.ceil(this.width / step / 2),
        vLinesS = vLines - 1,
        width = this.width,
        height = this.height,
        fragElem = doc.createDocumentFragment(),
        g = doc.createElementNS(svgNs, 'g'),
        gInside = doc.createElementNS(svgNs, 'g'),
        newElem, y1, y2, x1, x2, ind, sy1, sy2, sx1, sx2, sStep;
    g.setAttributeNS(null, 'id', 'setka');
    while (hLines--) {
      if (hLines === hLinesS) {
        y1 = height - (height % step);
        y2 = y1 + step;
        height = y1 + step;
      } else {
        y1 = height - step;
        y2 = height;
      }
      newElem = this.rect({ 'x1': 0, 'x2': width, 'y1': y1, 'y2': y2 });
      gInside.appendChild(newElem);
      height -= 2 * step;
      ind = inside;
      sy1 = y1;
      sStep = (y2 - y1) / 5;
      while (ind--) {
        sy1 += sStep;
        sy2 = sy1 + sStep;
        newElem = this.rect({ 'x1': 0, 'x2': width, 'y1': sy1, 'y2': sy2 },
            { 'stroke-width': '0.5', 'stroke': 'rgb(255, 255, 255)' });
        fragElem.appendChild(newElem);
        sy1 += sStep;
        if (ind === 2) { sy1 += sStep; }
      }
    }
    height = this.height;
    while (vLines--) {
      if (vLines === vLinesS) {
        x1 = width - (width % step);
        x2 = x1 + step;
        width = x1 + step;
      } else {
        x1 = width - step;
        x2 = width;
      }
      newElem = this.rect({ 'x1': x1, 'x2': x2, 'y1': 0, 'y2': height });
      gInside.appendChild(newElem);
      width -= 2 * step;
      ind = inside;
      sx1 = x1;
      sStep = (x2 - x1) / 5;
      while (ind--) {
        sx1 += sStep;
        sx2 = sx1 + sStep;
        newElem = this.rect({ 'x1': sx1, 'x2': sx2, 'y1': 0, 'y2': height },
            { 'stroke-width': '0.5', 'stroke': 'rgb(255, 255, 255)' });
        fragElem.appendChild(newElem);
        sx1 += sStep;
        if (ind === 2) { sx1 += sStep; }
      }
    }
    fragElem.appendChild(gInside);
    g.appendChild(fragElem);
    this.svg.appendChild(g);
  };

  var SvgElem = function(elem, name, papper) {
    this.elem = elem;
    this.name = name;
    this.children = [];
    this.selected = false;
    this.papper = papper;
  };

  SvgElem.fn = SvgElem.prototype;

  SvgElem.fn.rm = function() {
    this.elem.parentNode.removeChild(this.elem);
  };

  SvgElem.fn.attr = function(name, value) {
    var namespace = null;
    if (typeof value === 'object') {
      namespace = ns[value.ns];
      name = value.ns + ':' + name;
      value = value.v;
    }
    if (value === undefined && name) {
      return this.elem.getAttribute(name);
    }
    this.elem.setAttributeNS(namespace, name, value);
    return this;
  };

  SvgElem.fn.props = function(props) {
    props = props || {};
    for (var key in props) {
      if (props.hasOwnProperty(key)) {
        this[key] = props[key];
      }
    }
  };

  SvgElem.fn.attrs = function(attr) {
    for (var keyVar in attr) {
      if (keyVar !== 'elid') {
        this.attr(keyVar, attr[keyVar]);
      } else {
        this.elid = attr[keyVar];
      }
    }
    if (this.elid && this.name) {
      this.id = hash(this.elid + this.name);
    }
    return this;
  };

  SvgElem.fn.addClass = function(className) {
    if (typeof className !== 'string') { return this; }
    var curClass = this.elem.getAttribute('class');
    if (!curClass.match(className)) {
      curClass += ' ' + className;
      this.elem.setAttribute('class', curClass);
    }
    return this;
  };

  SvgElem.fn.removeClass = function(className) {
    if (typeof className !== 'string') { return this; }
    var curClass = this.elem.getAttribute('class');
    var regex = new RegExp(className, 'g');
    curClass = curClass.replace(regex, '');
    this.elem.setAttribute('class', curClass);
    return this;
  };

  SvgElem.fn.appendChild = function(child) {
    if (child.elem) {
      child = child.elem;
    }
    this.elem.appendChild(child);
    return this;
  };

  SvgElem.fn.setContent = function(content) {
    this.elem.textContent = content;
    return this;
  };
  /**
   * Bind Drag event
   * @param {object} self HTML node
   * @param {function} dragCallback
   * @param {function} moveCallback
   * @param {function} dropCallback
   * @return {self} return this
   */
  SvgElem.fn.onDrag = function(self, dragCallback, moveCallback, dropCallback) {
    this.elem.addEventListener('mousedown', this.drag.bind(this), true);
    this.dragCallback = dragCallback;
    this.moveCallback = moveCallback;
    this.dropCallback = dropCallback;
    this.moveSelf = self;
    var l = this.children.length,
        child;
    while (l--) {
      child = this.children[l];
      child.elem.addEventListener('mousedown', this.drag.bind(this), true);
    }
    return this;
  };

  SvgElem.fn.onSelect = function(self, callback) {
    this.onSelectEvent = true;
    this.selectedCallback = callback;
    this.selectedSelf = self;
    return this;
  };

  SvgElem.fn.onSelectOnly = function(overlay) {
    this.elem.addEventListener('mousedown', this.select.bind(this), true);
    if (overlay) {
      overlay.elem.addEventListener('mousedown', this.select.bind(this), true);
    }
  };

  SvgElem.fn.onDblclick = function(self, callback) {
    if (typeof callback === 'function') {
      this.elem.addEventListener('dblclick', callback.bind(this), true);
    }
    return this;
  };

  SvgElem.fn.onRotate = function(self,
                                 dragCallback, moveCallback, dropCallback) {
    this.elem.addEventListener('mousedown', this.dragRotate.bind(this), true);
    this.elem.addEventListener('keydown', this.forceRotate.bind(this), true);
    this.dragRotateCallback = dragCallback;
    this.moveRotateCallback = moveCallback;
    this.dropRotateCallback = dropCallback;
    this.moveSelf = self;
  };

  SvgElem.fn.drag = function(e, groupmove) {
    if (!groupmove) {
      document.onmousemove = this.move.bind(this);
      document.onmouseup = this.drop.bind(this);
    }
    this.dragStartTime = (new Date()).getTime();
    this.prevClientX = e.clientX;
    this.prevClientY = e.clientY;
    this.defX = this.attr('x') - 0;
    this.defY = this.attr('y') - 0;
    this.direction = this.direction || 0;
    this.curDirect = this.direction;
    this.elem.style.cursor = 'move';
    var l = this.children.length,
        child;
    while (l--) {
      child = this.children[l];
      child.defX = child.attr('x') - 0;
      child.defY = child.attr('y') - 0;
    }
    if (!this.selected && !e.ctrlKey) {
      this.select.apply(this, [e]);
      this.forceSelect = true;
    } else {
      if (!this.selected && e.ctrlKey) {
        this.select.apply(this, [e]);
        this.forceSelect = true;
      }
      if (typeof this.dragCallback === 'function' && !groupmove) {
        this.dragCallback.apply(this.moveSelf, [this, e]);
      }
    }
    if (!groupmove) {
      this.createRulesLines();
    }
    e.stopPropagation();
    e.preventDefault();
  };

  //    function calcNewPoints(x, y, cx, cy, a) {
  //      var coord = [x - cx, -y + cy],
  //        matrix = [
  //          [getCos(a), -getSin(a)],
  //          [getSin(a), getCos(a)]
  //        ], newX, newY;
  //
  //      newX = coord[0] * matrix[0][0] + coord[1] * matrix[1][0];
  //      newY = coord[0] * matrix[0][1] + coord[1] * matrix[1][1];
  //      return {
  //        x: newX + cx,
  //        y: - newY + cy
  //      };
  //    }
  //
  //    var sin = {}, cos = {}, n =  (180 / Math.PI) * -1;
  //
  //    function getSin(a) {
  //      if (!sin[a]) {
  //        sin[a] = Math.sin(a * n).toFixed(1);
  //      }
  //      return sin[a];
  //    }
  //
  //    function getCos(a) {
  //      if (!cos[a]) {
  //        cos[a] = Math.cos(a * n).toFixed(1);
  //      }
  //      return cos[a];
  //    }

  SvgElem.fn.createRulesLines = function() {
    this.width = this.attr('width');
    this.height = this.attr('height');

    if (this.direction < 90) {
      this.dy = this.height / 2;
      this.dx = this.width / 2;
    } else if (this.direction < 180) {
      this.dy = this.width / 2;
      this.dx = this.height / 2;
    } else if (this.direction < 270) {
      this.dy = this.height / 2;
      this.dx = this.width / 2;
    } else {
      this.dy = this.width / 2;
      this.dx = this.height / 2;
    }

    this.rotateX = (this.defX + (this.width / 2));
    this.rotateY = (this.defY + (this.height / 2));

    var x = this.rotateX - this.dx,
        y = this.rotateY - this.dy;

    //    var xy = calcNewPoints(this.defX, this.defY,
    // this.rotateX, this.rotateY, this.direction);
    //    x = xy.x;
    //    y = xy.y;
    if (this.group) {
      this.group.rm();
    }
    this.group = this.papper.group('scale-ruler-group', {});
    this.lineX = this.papper.line('scale-ruler-line-x', {
      x1: x,
      x2: x,
      y1: 0,
      y2: y,
      stroke: '#000',
      'stroke-width': this.papper.scale });
    this.group.appendChild(this.lineX);
    this.lineY = this.papper.line('scale-ruler-line-y', {
      x1: 0,
      x2: x,
      y1: y,
      y2: y,
      stroke: '#000',
      'stroke-width': this.papper.scale });
    this.group.appendChild(this.lineY);
    this.textX = this.papper.text('scale-ruler-text-x', y, {
      x: x / 2,
      y: y + (20 * this.papper.scale),
      stroke: '#000',
      'font-size': 11 * this.papper.scale + 'px' });
    this.group.appendChild(this.textX);
    this.textY = this.papper.text('scale-ruler-text-y', x, {
      x: x + (10 * this.papper.scale),
      y: y / 2,
      stroke: '#000',
      'font-size': 11 * this.papper.scale + 'px' });
    this.group.appendChild(this.textY);
    this.papper.appendChild(this.group);
  };

  SvgElem.fn.moveRulesLines = function() {
    this.rotateX = (this.curX + (this.width / 2));
    this.rotateY = (this.curY + (this.height / 2));
    var x = this.rotateX - this.dx,
        y = this.rotateY - this.dy;
    this.lineX.attr('x1', x);
    this.lineX.attr('x2', x);
    this.lineX.attr('y2', y);

    this.lineY.attr('y1', y);
    this.lineY.attr('y2', y);
    this.lineY.attr('x2', x);

    this.textX.setContent(y.toFixed(0));
    this.textX.attr('x', x / 2);
    this.textX.attr('y', y + (20 * this.papper.scale));

    this.textY.setContent(x.toFixed(0));
    this.textY.attr('x', x + (10 * this.papper.scale));
    this.textY.attr('y', y / 2);
  };

  SvgElem.fn.removeRulesLines = function() {
    this.group.rm();
    this.group = null;
    this.lineX = null;
    this.lineY = null;
    this.textY = null;
    this.textX = null;
  };

  SvgElem.fn.move = function(e, groupmove) {
    var shiftX = (e.clientX - this.prevClientX) / this.papper.zoomDelta,
        shiftY = (e.clientY - this.prevClientY) / this.papper.zoomDelta;

    this.prevClientX = e.clientX;
    this.prevClientY = e.clientY;

    this.moveSetAttr(shiftX, shiftY);

    if (typeof this.moveCallback === 'function' && !groupmove) {
      this.moveCallback.apply(this.moveSelf, [this, e]);
    }
    e.preventDefault();
  };

  SvgElem.fn.moveSetAttr = function(shiftX, shiftY, round) {
    var w, h, transform,
        x = shiftX + (this.attr('x') - 0),
        y = shiftY + (this.attr('y') - 0);
    if (x < 0) {
      shiftX = shiftX - x;
      x = 0;
    }
    if (y < 0) {
      shiftY = shiftY - y;
      y = 0;
    }
    if (round) {
      x -= x % round;
      y -= y % round;
    }
    this.attr('x', x);
    this.attr('y', y);
    this.curX = x;
    this.curY = y;

    if (this.direction) {
      w = this.attr('width') - 0;
      h = this.attr('height') - 0;
      transform = 'rotate(' + this.direction + ', ' +
          (this.curX - 0 + w / 2) + ', ' + (this.curY - 0 + h / 2) + ')';
      this.attr('transform', transform);
    }

    var l = this.children.length,
        child;
    while (l--) {
      child = this.children[l];
      x = shiftX + (child.attr('x') - 0);
      y = shiftY + (child.attr('y') - 0);
      child.attr('x', x);
      child.attr('y', y);
      if (child.direction) {
        if (child.shapeType !== 'text') {
          child.attr('transform', transform);
        } else if (this.direction > 125 && this.direction < 225) {
          child.attr('transform', 'rotate(' + 0 + ', ' +
              (this.curX - 0 + w / 2) + ', ' + (this.curY - 0 + h / 2) + ')');
        } else {
          child.attr('transform', transform);
        }
      }
    }
    if (this.group) {
      this.moveRulesLines();
    }
  };

  SvgElem.fn.drop = function(e, groupmove) {
    document.onmousemove = null;
    document.onmouseup = null;
    this.elem.style.cursor = null;
    var clickTime = (new Date()).getTime() - this.dragStartTime;
    //call drop callback
    if (typeof this.dropCallback === 'function' &&
        !groupmove && (clickTime > 200)) {
      this.dropCallback.apply(this.moveSelf, [this, e]);
    }
    //check for click event
    if (this.onSelectEvent && (clickTime < 200) && !this.forceSelect) {
      this.select.apply(this, [e]);
    }
    this.forceSelect = false;
    if (this.group) {
      this.removeRulesLines();
    }
    e.preventDefault();
  };

  SvgElem.fn.forceMove = function(direction) {
    this.defX = this.attr('x') - 0;
    this.defY = this.attr('y') - 0;
    var shiftX = 0, shiftY = 0, self = this,
        shift = 1 / this.papper.zoomDelta;
    switch (direction) {
      case 'left':
        shiftX = -1;
        break;
      case 'right':
        shiftX = 1;
        break;
      case 'up':
        shiftY = -1;
        break;
      case 'down':
        shiftY = 1;
        break;
    }
    if (shift === 1) {
      shift = 1;
    } else if (shift <= 5) {
      shift = 5;
    } else if (shift <= 10) {
      shift = 10;
    } else if (shift <= 50) {
      shift = 50;
    } else if (shift <= 100) {
      shift = 100;
    }

    if (shiftX !== 0) {
      shiftX = shift * shiftX;
    } else if (shiftY !== 0) {
      shiftY = shift * shiftY;
    }

    if (!this.group) {
      this.createRulesLines();
    }

    this.moveSetAttr(shiftX, shiftY, shift);
    clearTimeout(this.timeid);
    this.timeid = setTimeout(function() {
      if (typeof self.dropCallback === 'function') {
        self.dropCallback.apply(self.moveSelf, [self, {}]);
        if (self.group) {
          self.removeRulesLines();
        }
      }
    }, 1000);
  };

  SvgElem.fn.dragRotate = function(e) {
    var parent = this.parent,
        o = $(this.parent.papper.wrapper).offset(),
        radians, degree;
    document.onmousemove = this.moveRotate.bind(parent);
    document.onmouseup = this.dropRotate.bind(this);
    parent.defX = parent.attr('x') - 0;
    parent.defY = parent.attr('y') - 0;
    parent.curY = parent.defY;
    parent.curX = parent.defX;
    parent.rotateX = (parent.defX - 0 + (parent.attr('width') / 2));
    parent.rotateY = (parent.defY - 0 + (parent.attr('height') / 2));
    parent.direction = parent.direction || 0;
    parent.curDirect = parent.direction;
    parent.offsetLeft = o.left;
    parent.offsetTop = o.top;
    var a1 = e.pageX - o.left - (parent.rotateX) / this.papper.scale,
        a2 = e.pageY - o.top - (parent.rotateY) / this.papper.scale;
    radians = Math.atan2(a1, a2);
    degree = (radians * (180 / Math.PI) * -1) + 180;

    parent.defA = degree;
    if (typeof this.dragRotateCallback === 'function') {
      this.dragRotateCallback.apply(this.moveSelf, [this, e]);
    }
  };

  SvgElem.fn.moveRotate = function(e) {
    var transform,
        a1 = e.pageX - this.offsetLeft - (this.rotateX) / this.papper.scale,
        a2 = e.pageY - this.offsetTop - (this.rotateY) / this.papper.scale,
        radians = Math.atan2(a1, a2),
        degree = ((radians * (180 / Math.PI) * -1) + 180) - this.defA;

    this.curDirect = this.direction - 0 + Math.round(degree);

    transform = 'rotate(' + this.curDirect + ', ' +
        this.rotateX + ', ' + this.rotateY + ')';
    this.attr('transform', transform);

    var l = this.children.length,
        child;
    while (l--) {
      child = this.children[l];
      child.direction = true;
      if (this.children[l].shapeType !== 'text') {
        child.attr('transform', transform);
      } else if (this.curDirect > 125 && this.curDirect < 225) {
        child.attr('transform', 'rotate(' +
            0 + ', ' + this.rotateX + ', ' + this.rotateY + ')');
      } else {
        child.attr('transform', transform);
      }
    }
    if (typeof this.moveRotateCallback === 'function') {
      this.moveRotateCallback.apply(this.moveSelf, [this, e]);
    }
    e.preventDefault();
  };

  SvgElem.fn.forceRotate = function(e) {
    var curRotate = this.direction,
        diff = curRotate % 90,
        transform;
    this.defX = this.attr('x') - 0;
    this.defY = this.attr('y') - 0;
    //@TODO save width & height
    this.rotateX = (this.defX + (this.attr('width') / 2));
    this.rotateY = (this.defY + (this.attr('height') / 2));

    this.curDirect = this.direction - 0 + (90 - diff);
    this.setAngle(this.curDirect);
    transform = 'rotate(' + this.curDirect +
        ', ' + this.rotateX + ', ' + this.rotateY + ')';
    this.attr('transform', transform);

    var l = this.children.length,
        child;
    while (l--) {
      child = this.children[l];
      child.direction = true;
      if (this.children[l].shapeType !== 'text') {
        child.attr('transform', transform);
      } else if (this.curDirect > 125 && this.curDirect < 225) {
        child.attr('transform', 'rotate(' + 0 +
            ', ' + this.rotateX + ', ' + this.rotateY + ')');
      } else {
        child.attr('transform', transform);
      }
    }
    if (typeof this.dropRotateCallback === 'function') {
      this.dropRotateCallback.apply(this.moveSelf, [this, e]);
    }
  };

  SvgElem.fn.setAngle = function(angle) {
    angle = angle % 360;
    this.direction = angle;
    this.curDirect = angle;
  };

  SvgElem.fn.dropRotate = function(e) {
    document.onmousemove = null;
    document.onmouseup = null;
    this.parent.setAngle(this.parent.curDirect);
    //call drop callback
    if (typeof this.dropRotateCallback === 'function') {
      this.dropRotateCallback.apply(this.parent.moveSelf, [this.parent, e]);
    }
    e.preventDefault();
  };

  var CTRL_KEY = 17;

  SvgElem.fn.select = function(e) {
    var codeKey = e.which || e.keyCode,
        ctrl = (CTRL_KEY === codeKey || e.ctrlKey),
        timeEvent = (new Date()).getTime();
    if (ctrl) {
      if (this.selected) {
        this.selected = false;
      } else {
        this.selected = true;
      }
    } else {
      this.selected = true;
    }
    if ((timeEvent - this.lastClicked) < 300) {
      this.dblclicked = true;
    } else {
      this.dblclicked = false;
    }
    //call callback function
    if (typeof this.selectedCallback === 'function') {
      this.selectedCallback.apply(this.selectedSelf, [this, ctrl]);
    }
    this.lastClicked = timeEvent;
    e.preventDefault();
  };

  exports.Svg = Svg;

}(window));