Brk
Brk

Reputation: 1297

Convert code from canvas to svg

I have a code in canvas which help me in making gas triangles(duval triangles). I need to convert the code from canvas to svg. One of the reason why I moving from canvas to svg, is because I can't add event handlers in canvas(which act like bitmap) but in svg I can do it.

1.Is it possible?

2.Can I do the same things in canvas also in svg?

3.Should I use libraries to help me in writing svg, any recommendations for specific svg library?

My code is based on the following post: 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);
    }
  }
})
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>

Upvotes: 0

Views: 13134

Answers (2)

Charlie
Charlie

Reputation: 23768

  1. Yes it is possible.

  2. You can do more things on svg than on canvas.

  3. You can try SVG.JS library. It is lightweight and easy to use.

Upvotes: 1

Nofi
Nofi

Reputation: 2175

Try fabric JS to convert canvas to 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

Upvotes: 1

Related Questions