将代码从画布转换为 svg

Convert code from canvas to svg

本文关键字:转换 svg 代码 布转换      更新时间:2023-09-26

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

1.Is 可能吗?

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

3.我应该使用库来帮助我编写 svg 吗,对特定的 svg 库有什么建议吗?

我的代码基于以下帖子:如何在画布中创建杜瓦尔三角形

$(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);
    }
  }
})
body {
  background-color: ivory;
  padding: 10px;
}
#canvas {
  border: 1px solid red;
  margin: 0 auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="canvas" width=1024 height=1020></canvas>

  1. 是的,这是可能的。

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

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

尝试将画布转换为 svg。小提琴

.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());
});

小提琴

另请参阅此示例小提琴