0

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>
Community
  • 1
  • 1
Brk
  • 1,247
  • 2
  • 23
  • 55

2 Answers2

1

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

Nofi
  • 2,107
  • 1
  • 15
  • 23
  • The problem is that it is an image of svg, I can't add event listeners to this svg component. I can't split this svg into a small components and it acts just like an image. – Brk Apr 28 '16 at 10:16
  • Can I add event handlers using fabricjs? if so you solved my problem, can I ? – Brk Apr 28 '16 at 10:24
  • Yes better use fabricJs handlers. – Nofi Apr 28 '16 at 10:29
1
  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.

Community
  • 1
  • 1
Charlie
  • 22,886
  • 11
  • 59
  • 90
  • ok please show me a full 3d game made in svg. And if you want to stick with 2d context simply show me how you do pixel manipulation in svg. There are a few things you can do on svg that you can't in canvas (basically importing HTML nodes), but there are a lot of things you can do on a canvas that you can't do on an svg. – Kaiido Apr 28 '16 at 12:03