将代码从canvas转换为svg

时间:2016-04-28 07:42:53

标签: javascript html5 canvas svg

我在画布上有一个代码可以帮助我制作气体三角形(duval三角形)。 我需要将代码从canvas转换为svg。 我从canvas转到svg的原因之一是因为我无法在canvas中添加事件处理程序(这类似于位图),但在svg中我可以做到。

1.可能吗?

2.我可以在svg中用画布做同样的事情吗?

3.我应该使用库来帮助我编写svg,有关特定svg库的任何建议吗?

我的代码基于以下帖子: how to create Duval Triangle in canvas



$(function() {


  var canvas = document.getElementById("canvas");
  var ctx = canvas.getContext("2d");

  // https://www.researchgate.net/publication/4345236_A_Software_Implementation_of_the_Duval_Triangle_Method

  var v0 = {
    x: 58,
    y: 845
  };
  var v1 = {
    x: 984,
    y: 845
  };
  var v2 = {
    x: 521,
    y: 41
  };
  var triangle = [v0, v1, v2];

  // Define all your segments here
  var segments = [{
    points: [{
      x: 58,
      y: 845
    }, {
      x: 272,
      y: 845
    }, {
      x: 567,
      y: 333
    }, {
      x: 461,
      y: 150
    }],
    fill: 'rgb(172,236,222)',
    label: {
      text: 'D1',
      cx: 300,
      cy: 645,
      withLine: false,
      endX: null,
      endY: null
    },
  }, {
    points: [{
      x: 272,
      y: 845
    }, {
      x: 567,
      y: 333
    }, {
      x: 646,
      y: 468
    }, {
      x: 572,
      y: 597
    }, {
      x: 716,
      y: 845
    }],
    fill: 'deepskyblue',
    label: {
      text: 'D2',
      cx: 490,
      cy: 645,
      withLine: false,
      endX: null,
      endY: null
    },
  }, {
    points: [{
      x: 716,
      y: 845
    }, {
      x: 845,
      y: 845
    }, {
      x: 683,
      y: 565
    }, {
      x: 734,
      y: 476
    }, {
      x: 503,
      y: 76
    }, {
      x: 461,
      y: 150
    }, {
      x: 646,
      y: 468
    }, {
      x: 572,
      y: 595
    }],
    fill: 'lightCyan',
    label: {
      text: 'DT',
      cx: 656,
      cy: 645,
      withLine: false,
      endX: 366,
      endY: 120
    },
  }, { //here - I am in hell.-s5
    points: [{
      x: 530,
      y: 59
    }, {
      x: 512,
      y: 59
    }, {
      x: 521,
      y: 41
    }],
    fill: 'black',
    label: {
      text: 'PD',
      cx: 600,
      cy: 52,
      withLine: true,
      endX: 520,
      endY: 70
    },
  }, {
    points: [{
      x: 595,
      y: 235
    }, {
      x: 614,
      y: 203
    }, {
      x: 530,
      y: 59
    }, {
      x: 512,
      y: 59
    }, {
      x: 503,
      y: 76
    }],
    fill: 'navajoWhite',
    label: {
      text: 'T1',
      cx: 670,
      cy: 140,
      withLine: true,
      endX: 574,
      endY: 105
    },
  }, {
    points: [{
      x: 753,
      y: 446
    }, {
      x: 735,
      y: 476
    }, {
      x: 595,
      y: 235
    }, {
      x: 614,
      y: 203
    }],
    fill: 'tan',
    label: {
      text: 'T2',
      cx: 800,
      cy: 290,
      withLine: true,
      endX: 662,
      endY: 120
    },
  }, {
    points: [{
      x: 845,
      y: 845
    }, {
      x: 683,
      y: 565
    }, {
      x: 753,
      y: 446
    }, {
      x: 984,
      y: 845
    }],
    fill: 'peru',
    label: {
      text: 'T3',
      cx: 800,
      cy: 645,
      withLine: false,
      endX: null,
      endY: null
    },
  }, ];

  // label styles
  var labelfontsize = 12;
  var labelfontface = 'verdana';
  var labelpadding = 3;

  // pre-create a canvas-image of the arrowhead
  var arrowheadLength = 10;
  var arrowheadWidth = 8;
  var arrowhead = document.createElement('canvas');
  premakeArrowhead();

  var legendTexts = ['PD = Partial Discharge',
    'DT =  Discharges and Thermal',
    'T1 =  Thermal fault T < 300 ℃',
    'T2 =  Thermal fault 300 ℃ < T < 700 ℃',
    'T3 =  Thermal fault  T > 700 ℃',
    'D1 =  Discharges of low energy',
    'D2 =  Discharges of high energy'
  ];


  // start drawing
  /////////////////////


  // draw colored segments inside triangle
  for (var i = 0; i < segments.length; i++) {
    drawSegment(segments[i]);
  }
  // draw ticklines
  ticklines(v0, v1, 9, Math.PI * 1.2, 20);
  ticklines(v1, v2, 9, Math.PI * 3 / 4, 20);
  ticklines(v2, v0, 9, Math.PI * 2, 20);
  // molecules
  moleculeLabel(v0, v1, 100, Math.PI / 2, '% CH4');
  moleculeLabel(v1, v2, 100, 0, '% C2H4');
  moleculeLabel(v2, v0, 100, Math.PI, '% C2H2');
  // draw outer triangle
  drawTriangle(triangle);
  // draw legend
  drawLegend(legendTexts, 10, 10, 12.86);
  drawCircle(canvas.width / 3, canvas.height / 2, 2.5, 'red');
  // end drawing
  /////////////////////

  function drawCircle(point1, point2, radius, color) {
    ctx.beginPath();
    ctx.arc(point1, point2, radius, 0, 2 * Math.PI, false);
    ctx.fillStyle = color;
    ctx.fill();
  }

  function drawSegment(s) {
    // draw and fill the segment path
    ctx.beginPath();
    ctx.moveTo(s.points[0].x, s.points[0].y);
    for (var i = 1; i < s.points.length; i++) {
      ctx.lineTo(s.points[i].x, s.points[i].y);
    }
    ctx.closePath();
    ctx.fillStyle = s.fill;
    ctx.fill();
    ctx.lineWidth = 2;
    ctx.strokeStyle = 'black';
    ctx.stroke();
    // draw segment's box label
    if (s.label.withLine) {
      lineBoxedLabel(s, labelfontsize, labelfontface, labelpadding);
    } else {
      boxedLabel(s, labelfontsize, labelfontface, labelpadding);
    }
  }


  function moleculeLabel(start, end, offsetLength, angle, text) {
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle'
    ctx.font = '14px verdana';
    var dx = end.x - start.x;
    var dy = end.y - start.y;
    var x0 = parseInt(start.x + dx * 0.50);
    var y0 = parseInt(start.y + dy * 0.50);
    var x1 = parseInt(x0 + offsetLength * Math.cos(angle));
    var y1 = parseInt(y0 + offsetLength * Math.sin(angle));
    ctx.fillStyle = 'black';
    ctx.fillText(text, x1, y1);
    // arrow
    var x0 = parseInt(start.x + dx * 0.35);
    var y0 = parseInt(start.y + dy * 0.35);
    var x1 = parseInt(x0 + 50 * Math.cos(angle));
    var y1 = parseInt(y0 + 50 * Math.sin(angle));
    var x2 = parseInt(start.x + dx * 0.65);
    var y2 = parseInt(start.y + dy * 0.65);
    var x3 = parseInt(x2 + 50 * Math.cos(angle));
    var y3 = parseInt(y2 + 50 * Math.sin(angle));
    ctx.beginPath();
    ctx.moveTo(x1, y1);
    ctx.lineTo(x3, y3);
    ctx.strokeStyle = 'black';
    ctx.lineWidth = 1;
    ctx.stroke();
    var angle = Math.atan2(dy, dx);
    ctx.save(); // save
    ctx.translate(x3, y3);
    ctx.rotate(angle);
    ctx.drawImage(arrowhead, -arrowheadLength, -arrowheadWidth / 2);
    ctx.restore()
  }


  function boxedLabel(s, fontsize, fontface, padding) {
    var centerX = s.label.cx;
    var centerY = s.label.cy;
    var text = s.label.text;
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle'
    ctx.font = fontsize + 'px ' + fontface
    var textwidth = ctx.measureText(text).width;
    var textheight = fontsize * 1.286;
    var leftX = centerX - textwidth / 2 - padding;
    var topY = centerY - textheight / 2 - padding;
    ctx.fillStyle = 'white';
    ctx.fillRect(leftX, topY, textwidth + padding * 2, textheight + padding * 2);
    ctx.lineWidth = 1;
    ctx.strokeRect(leftX, topY, textwidth + padding * 2, textheight + padding * 2);
    ctx.fillStyle = 'black';
    ctx.fillText(text, centerX, centerY);
  }


  function lineBoxedLabel(s, fontsize, fontface, padding) {
    var centerX = s.label.cx;
    var centerY = s.label.cy;
    var text = s.label.text;
    var lineToX = s.label.endX;
    var lineToY = s.label.endY;
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle'
    ctx.font = fontsize + 'px ' + fontface
    var textwidth = ctx.measureText(text).width;
    var textheight = fontsize * 1.286;
    var leftX = centerX - textwidth / 2 - padding;
    var topY = centerY - textheight / 2 - padding;
    // the line
    ctx.beginPath();
    ctx.moveTo(leftX, topY + textheight / 2);
    ctx.lineTo(lineToX, topY + textheight / 2);
    ctx.strokeStyle = 'black';
    ctx.lineWidth = 1;
    ctx.stroke();
    // the boxed text
    ctx.fillStyle = 'white';
    ctx.fillRect(leftX, topY, textwidth + padding * 2, textheight + padding * 2);
    ctx.strokeRect(leftX, topY, textwidth + padding * 2, textheight + padding * 2);
    ctx.fillStyle = 'black';
    ctx.fillText(text, centerX, centerY);
  }


  function ticklines(start, end, count, angle, length) {
    var dx = end.x - start.x;
    var dy = end.y - start.y;
    ctx.lineWidth = 1;
    for (var i = 1; i < count; i++) {
      var x0 = parseInt(start.x + dx * i / count);
      var y0 = parseInt(start.y + dy * i / count);
      var x1 = parseInt(x0 + length * Math.cos(angle));
      var y1 = parseInt(y0 + length * Math.sin(angle));
      ctx.beginPath();
      ctx.moveTo(x0, y0);
      ctx.lineTo(x1, y1);
      ctx.stroke();
      if (i == 2 || i == 4 || i == 6 || i == 8) {
        var labelOffset = length * 3 / 4;
        var x1 = parseInt(x0 - labelOffset * Math.cos(angle));
        var y1 = parseInt(y0 - labelOffset * Math.sin(angle));
        ctx.fillStyle = 'black';
        ctx.fillText(parseInt(i * 10), x1, y1);
      }
    }
  }


  function premakeArrowhead() {
    var actx = arrowhead.getContext('2d');
    arrowhead.width = arrowheadLength;
    arrowhead.height = arrowheadWidth;
    actx.beginPath();
    actx.moveTo(0, 0);
    actx.lineTo(arrowheadLength, arrowheadWidth / 2);
    actx.lineTo(0, arrowheadWidth);
    actx.closePath();
    actx.fillStyle = 'black';
    actx.fill();
  }


  function drawTriangle(t) {
    ctx.beginPath();
    ctx.moveTo(t[0].x, t[0].y);
    ctx.lineTo(t[1].x, t[1].y);
    ctx.lineTo(t[2].x, t[2].y);
    ctx.closePath();
    ctx.strokeStyle = 'black';
    ctx.lineWidth = 2;
    ctx.stroke();
  }


  function drawLegend(texts, x, y, lineheight) {
    ctx.textAlign = 'left';
    ctx.textBaseline = 'top';
    ctx.fillStyle = 'black';
    ctx.font = '12px arial';
    for (var i = 0; i < texts.length; i++) {
      ctx.fillText(texts[i], x, y + i * lineheight);
    }
  }
})
&#13;
body {
  background-color: ivory;
  padding: 10px;
}
#canvas {
  border: 1px solid red;
  margin: 0 auto;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="canvas" width=1024 height=1020></canvas>
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:1)

尝试使用fabric JS将canvas转换为svg。 JsFiddle

<强> HTML

<canvas id="canvas" width=1024 height=1020></canvas>
<button id="canvas2svg">Canvas 2 SVG</button>

<强> JS

var canvas = new fabric.Canvas('canvas', { isDrawingMode: true });
  //var canvas = document.getElementById("canvas");
  var ctx = canvas.getContext("2d");
$("#canvas2svg").click(function(){
    canvas.isDrawingMode = false;
    alert(canvas.toSVG());
});

JsFiddle

Also refer this example fiddle

答案 1 :(得分:0)

  1. 是的,这是可能的。

  2. 你可以在svg上做比在画布上做更多的事情。

  3. 您可以尝试使用SVG.JS库。它重量轻,易于使用。