Drawing SVG with Mouse

后端 未结 1 1402
南旧
南旧 2021-02-06 16:30

I having be exploring several options for building an open-source HTML5 based application like Sketch, which will basically be vector based app for creating UI screens etc.

1条回答
  •  长情又很酷
    2021-02-06 17:09

    I think you already solved this problem, but here is how to do. I'm using SVG.js and plugin svg.draw.js. It is lightweight and well documented.

    It's a lot of code here, but once you run it is exactly what you want.

    /*! svg.draw.js - v2.0.3 - 2017-06-19
    * https://github.com/svgdotjs/svg.draw.js
    * Copyright (c) 2017 Ulrich-Matthias Schäfer; Licensed MIT */
    /* Include min code here since there is no CDN for svg.draw.js */
    (function(){function a(a,b,c){this.el=a,a.remember("_paintHandler",this);var d=this,e=this.getPlugin();this.parent=a.parent(SVG.Nested)||a.parent(SVG.Doc),this.p=this.parent.node.createSVGPoint(),this.m=null,this.startPoint=null,this.lastUpdateCall=null,this.options={};for(var f in this.el.draw.defaults)this.options[f]=this.el.draw.defaults[f],"undefined"!=typeof c[f]&&(this.options[f]=c[f]);e.point&&(e.pointPlugin=e.point,delete e.point);for(var f in e)this[f]=e[f];b||this.parent.on("click.draw",function(a){d.start(a)})}a.prototype.transformPoint=function(a,b){return this.p.x=a-(this.offset.x-window.pageXOffset),this.p.y=b-(this.offset.y-window.pageYOffset),this.p.matrixTransform(this.m)},a.prototype.start=function(a){var b=this;this.m=this.el.node.getScreenCTM().inverse(),this.offset={x:window.pageXOffset,y:window.pageYOffset},this.options.snapToGrid*=Math.sqrt(this.m.a*this.m.a+this.m.b*this.m.b),this.startPoint=this.snapToGrid(this.transformPoint(a.clientX,a.clientY)),this.init&&this.init(a),this.el.fire("drawstart",{event:a,p:this.p,m:this.m}),SVG.on(window,"mousemove.draw",function(a){b.update(a)}),this.start=this.point},a.prototype.point=function(a){return this.point!=this.start?this.start(a):this.pointPlugin?this.pointPlugin(a):void this.stop(a)},a.prototype.stop=function(a){a&&this.update(a),this.clean&&this.clean(),SVG.off(window,"mousemove.draw"),this.parent.off("click.draw"),this.el.forget("_paintHandler"),this.el.draw=function(){},this.el.fire("drawstop")},a.prototype.update=function(a){!a&&this.lastUpdateCall&&(a=this.lastUpdateCall),this.lastUpdateCall=a,this.calc(a),this.el.fire("drawupdate",{event:a,p:this.p,m:this.m})},a.prototype.done=function(){this.calc(),this.stop(),this.el.fire("drawdone")},a.prototype.cancel=function(){this.stop(),this.el.remove(),this.el.fire("drawcancel")},a.prototype.snapToGrid=function(a){var b=null;if(a.length)return b=[a[0]%this.options.snapToGrid,a[1]%this.options.snapToGrid],a[0]-=b[0]b?this.options.snapToGrid:0);return a},a.prototype.param=function(a,b){this.options[a]=null===b?this.el.draw.defaults[a]:b,this.update()},a.prototype.getPlugin=function(){return this.el.draw.plugins[this.el.type]},SVG.extend(SVG.Element,{draw:function(b,c,d){b instanceof Event||"string"==typeof b||(c=b,b=null);var e=this.remember("_paintHandler")||new a(this,b,c||{});return b instanceof Event&&e.start(b),e[b]&&e[b](c,d),this}}),SVG.Element.prototype.draw.defaults={snapToGrid:1},SVG.Element.prototype.draw.extend=function(a,b){var c={};"string"==typeof a?c[a]=b:c=a;for(var d in c){var e=d.trim().split(/\s+/);for(var f in e)SVG.Element.prototype.draw.plugins[e[f]]=c[d]}},SVG.Element.prototype.draw.plugins={},SVG.Element.prototype.draw.extend("rect image",{init:function(a){var b=this.startPoint;this.el.attr({x:b.x,y:b.y,height:0,width:0})},calc:function(a){var b={x:this.startPoint.x,y:this.startPoint.y},c=this.transformPoint(a.clientX,a.clientY);b.width=c.x-b.x,b.height=c.y-b.y,this.snapToGrid(b),b.width<0&&(b.x=b.x+b.width,b.width=-b.width),b.height<0&&(b.y=b.y+b.height,b.height=-b.height),this.el.attr(b)}}),SVG.Element.prototype.draw.extend("line polyline polygon",{init:function(a){this.set=new SVG.Set;var b=this.startPoint,c=[[b.x,b.y],[b.x,b.y]];this.el.plot(c),this.drawCircles()},calc:function(a){var b=this.el.array().valueOf();if(b.pop(),a){var c=this.transformPoint(a.clientX,a.clientY);b.push(this.snapToGrid([c.x,c.y]))}this.el.plot(b)},point:function(a){if(this.el.type.indexOf("poly")>-1){var b=this.transformPoint(a.clientX,a.clientY),c=this.el.array().valueOf();return c.push(this.snapToGrid([b.x,b.y])),this.el.plot(c),this.drawCircles(),void this.el.fire("drawpoint",{event:a,p:{x:b.x,y:b.y},m:this.m})}this.stop(a)},clean:function(){this.set.each(function(){this.remove()}),this.set.clear(),delete this.set},drawCircles:function(){var a=this.el.array().valueOf();this.set.each(function(){this.remove()}),this.set.clear();for(var b=0;b {
      shape = document.getElementById('shape').value;
      const color = document.getElementById('color').value;
      const option = {
        stroke: color,
        'stroke-width': 2,
        'fill-opacity': 0,
      };
    
      switch (shape) {
        case 'mouse paint':
          return draw.polyline().attr(option);
        case 'ellipse':
          return draw.ellipse().attr(option);
        case 'rect':
          return draw.rect().attr(option);
      }
      return null;
    }
    
    
    draw.on('mousedown', event => {
      const shape = getDrawObject();
      shapes[index] = shape;
      shape.draw(event);
    });
    draw.on('mousemove', event => {
      if (shape === 'mouse paint' && shapes[index]) {
        shapes[index].draw('point', event);
      }
    })
    draw.on('mouseup', event => {
      if (shape === 'mouse paint') {
        shapes[index].draw('stop', event);
      } else {
        shapes[index].draw(event);
      }
      index++;
    })
    
    // This is custom extension of line, polyline, polygon which doesn't draw the circle on the line. 
    SVG.Element.prototype.draw.extend('line polyline polygon', {
    
      init:function(e){
        // When we draw a polygon, we immediately need 2 points.
        // One start-point and one point at the mouse-position
    
        this.set = new SVG.Set();
    
        var p = this.startPoint,
            arr = [
              [p.x, p.y],
              [p.x, p.y]
            ];
    
        this.el.plot(arr);
      },
    
      // The calc-function sets the position of the last point to the mouse-position (with offset ofc)
      calc:function (e) {
        var arr = this.el.array().valueOf();
        arr.pop();
    
        if (e) {
          var p = this.transformPoint(e.clientX, e.clientY);
          arr.push(this.snapToGrid([p.x, p.y]));
        }
    
        this.el.plot(arr);
    
      },
    
      point:function(e){
    
        if (this.el.type.indexOf('poly') > -1) {
          // Add the new Point to the point-array
          var p = this.transformPoint(e.clientX, e.clientY),
              arr = this.el.array().valueOf();
    
          arr.push(this.snapToGrid([p.x, p.y]));
    
          this.el.plot(arr);
    
          // Fire the `drawpoint`-event, which holds the coords of the new Point
          this.el.fire('drawpoint', {event:e, p:{x:p.x, y:p.y}, m:this.m});
    
          return;
        }
    
        // We are done, if the element is no polyline or polygon
        this.stop(e);
    
      },
    
      clean:function(){
    
        // Remove all circles
        this.set.each(function () {
          this.remove();
        });
    
        this.set.clear();
    
        delete this.set;
    
      },
    });
    #drawing {
      border: 1px solid #ccc;
    }
    
    
    Shape: Color:

    0 讨论(0)
提交回复
热议问题