javascript - 如何在 Canvas 中创建杜瓦尔五 Angular 大楼

标签 javascript css canvas html5-canvas

嘿,我已经根据在 Canvas 中创建杜瓦尔三 Angular 形的帖子创建了一个杜瓦尔五 Angular 大楼:how to create Duval Triangle in canvas。 我的最终结果应该是: enter image description here

我目前的情况是,我可以在五 Angular 大楼内创建所有线段,但我没有想出一种方法来在我的杜瓦尔五 Angular 大楼的每个 Angular (点)周围放置气体标签,任何建议或帮助是欢迎。

duval pentagon的创建过程是这样的:

1.创建外五边形。

2.在循环中创建所有片段。

3.创造五 Angular 大楼的传奇。

更新: 我试图根据@markE 指导线重新构建 moleculeLabel。到目前为止还没有很好的尝试,我肯定做错了什么。 :(

function moleculeLabel(V,P,text){
    var dx=V.x-P.x;
    var dy=V.y-P.y;
    var rAngle=Math.atan2(dy,dx);
    var padding=15; // == how far outside the pentagon you want to go
    var outsideX=P.x+(P.radius+padding)*Math.cos(rAngle);
    var outsideY=P.y+(P.radius+padding)*Math.sin(rAngle);
    ctx.textAlign='center';
    ctx.textBaseline='middle';
    ctx.fillStyle='black';
    ctx.fillText(text,outsideX,outsideY);
}`

$(function() {

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

  var points = [{
    x: 397,
    y: 149
  }, {
    x: 318,
    y: 346
  }, {
    x: 112,
    y: 347
  }, {
    x: 44,
    y: 147
  }, {
    x: 221,
    y: 27
  }, {
    x: 397,
    y: 149
  }];
  var cx = 0;
  var cy = 0;

  for (var i = 0; i < points.lenght; i++) {
    cx = cx + points[i].x;
    cy = cy + points[i].y;
  }
  cx = cx / points.lenght;
  cy = cy / points.lenght;
  var centerPoint = {
    x: cy,
    y: cy
  };
  // Define all your segments here
  var segments = [{
    points: [{
      x: 61,
      y: 191
    }, {
      x: 112,
      y: 347
    }, {
      x: 190,
      y: 223
    }, {
      x: 214,
      y: 211
    }, {
      x: 217,
      y: 198
    }, {
      x: 61,
      y: 192
    }],
    fill: 'rgb(172,236,222)',
    label: {
      text: 'T1',
      cx: 130,
      cy: 250,
      withLine: false,
      endX: null,
      endY: null
    },
  }, {
    points: [{
      x: 61,
      y: 191
    }, {
      x: 217,
      y: 198
    }, {
      x: 220,
      y: 26
    }, {
      x: 44,
      y: 149
    }],
    fill: 'deepskyblue',
    label: {
      text: 'S',
      cx: 140,
      cy: 150,
      withLine: false,
      endX: null,
      endY: null
    },
  }, {
    points: [{
      x: 220,
      y: 26
    }, {
      x: 217,
      y: 198
    }, {
      x: 239,
      y: 135
    }, {
      x: 365,
      y: 230
    }, {
      x: 397,
      y: 149
    }, {
      x: 221,
      y: 27
    }],
    fill: 'lightCyan',
    label: {
      text: 'D1',
      cx: 270,
      cy: 110,
      withLine: false,
      endX: null,
      endY: null
    },
  }, {
    points: [{
      x: 214,
      y: 211
    }, {
      x: 239,
      y: 135
    }, {
      x: 365,
      y: 231
    }, {
      x: 320,
      y: 336
    }, ],
    fill: 'navajoWhite',
    label: {
      text: 'D2',
      cx: 270,
      cy: 210,
      withLine: false,
      endX: null,
      endY: null
    },
  }, {
    points: [{
      x: 190,
      y: 223
    }, {
      x: 214,
      y: 211
    }, {
      x: 320,
      y: 336
    }, {
      x: 318,
      y: 346
    }, {
      x: 223,
      y: 346
    }],
    fill: 'tan',
    label: {
      text: 'T3',
      cx: 250,
      cy: 310,
      withLine: false,
      endX: null,
      endY: null
    },
  }, {
    points: [{
      x: 112,
      y: 347
    }, {
      x: 190,
      y: 223
    }, {
      x: 223,
      y: 346
    }],
    fill: 'peru',
    label: {
      text: 'T2',
      cx: 175,
      cy: 300,
      withLine: false,
      endX: null,
      endY: null
    },
  }, {
    points: [{
      x: 210,
      y: 105
    }, {
      x: 219,
      y: 105
    }, {
      x: 219,
      y: 68
    }, {
      x: 210,
      y: 67
    }],
    fill: 'red',
    label: {
      text: 'PD',
      cx: 170,
      cy: 87,
      withLine: true,
      endX: 215,
      endY: 88
    },
  }];

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

  var legendTexts = ['PD = Partial Discharge', 'T1 = Thermal fault < 300 celcius', '...'];


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


  // draw pentagon
  drawPentagon(points);

  // draw colored segments inside pentagon
  for (var i = 0; i < segments.length; i++) {
    drawSegment(segments[i]);
  }
  moleculeLabel(points[0], centerPoint, 'CH4');
  moleculeLabel(points[1], centerPoint, 'CH2');
  moleculeLabel(points[2], centerPoint, 'H2');
  // draw legend
  drawLegend(legendTexts, 10, 10, 12.86);

  // end drawing
  /////////////////////

  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 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 moleculeLabel(V, P, text) {
    var dx = V.x - P.x;
    var dy = V.y - P.y;
    var rAngle = Math.atan2(dy, dx);
    var padding = 15; // == how far outside the pentagon you want to go
    var outsideX = P.x + (P.radius + padding) * Math.cos(rAngle);
    var outsideY = P.y + (P.radius + padding) * Math.sin(rAngle);
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillStyle = 'black';
    ctx.fillText(text, outsideX, outsideY);
  }


  /**
   * draw basic pentagon.
   **/
  function drawPentagon(points) {
    ctx.beginPath();
    for (var i = 0; i < points.length; i++) {
      ctx.lineTo(points[i].x, points[i].y);
    }

    ctx.strokeStyle = 'black';
    ctx.lineWidth = 1;
    ctx.stroke();
    ctx.closePath();

  }

  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=650 height=500></canvas>

最佳答案

对于每个所需的分子标签:

给定一个形状如下的五边形:{x:,y:,radius:} 和一个分子顶点 {x:,y:}

使用Math.atan2 求出多边形中心点与分子顶点之间的夹 Angular 。

var dx=V.x-P.x;
var cy=V.y-P.y;
var rAngle=Math.atan2(dy,dx);

使用基本三 Angular 学沿中心点和顶点之间的线计算多边形外部的点。

var padding=15; // == how far outside the pentagon you want to go
var outsideX=P.x+(P.radius+padding)*Math.cos(rAngle);
var outsideY=P.y+(P.radius+padding)*Math.sin(rAngle);

使用fillText[outsideX,outsideY]绘制所需的标签

context.textAlign='center';
context.textBaseline='middle';
context.fillStyle='black';
context.fillText('CH4',outsideX,outsideY);

这是示例代码和演示:

enter image description here

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
        
var points = [{x:397,y:149},{x:318,y:346},{x:112,y:347},{x:44,y:147},{x: 221,y:27},{x:397,y:149}];

// calc the polygon center mass
var cx,cy;
var totx=0;
var toty=0;
for(var i=0;i<points.length-1;i++){ // don't include the "closing" point in points[]
    totx+=points[i].x;
    toty+=points[i].y;
}
cx=totx/(points.length-1);
cy=toty/(points.length-1);

draw();

function draw(){
    // draw the polygon
    ctx.beginPath();
    ctx.moveTo(points[0].x,points[0].y);
    for(var i=1;i<points.length;i++){
        ctx.lineTo(points[i].x,points[i].y);
    }
    ctx.stroke();
    
    // draw the labels at their radial extension points
    ctx.textAlign='center';
    ctx.textBaseline='middle';
    var padding=20;
    for(var i=0;i<points.length-1;i++){
        var p=points[i];
        var dx=p.x-cx;
        var dy=p.y-cy;
        var dist=Math.sqrt(dx*dx+dy*dy);
        var rAngle=Math.atan2(dy,dx);
        var labelX=cx+(dist+padding)*Math.cos(rAngle);
        var labelY=cy+(dist+padding)*Math.sin(rAngle);
        ctx.fillText('label#'+i,labelX,labelY)
        
        // demo only, for points[0] draw the 
        //centerpoint and the radial extension point
        if(i==0){
            ctx.beginPath();
            ctx.moveTo(cx,cy);
            ctx.lineTo(labelX,labelY);
            ctx.moveTo(cx,cy);
            ctx.arc(cx,cy,5,0,Math.PI*2);
            ctx.moveTo(labelX,labelY);
            ctx.arc(labelX,labelY,3,0,Math.PI*2);
            ctx.strokeStyle='red';
            ctx.stroke();
            ctx.fillStyle='red';
            ctx.fill();
            ctx.strokeStyle='black';
            ctx.fillStyle='black';
        }
    }   
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=500 height=500></canvas>

关于javascript - 如何在 Canvas 中创建杜瓦尔五 Angular 大楼,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36531290/

相关文章:

javascript - 我如何以编程方式 "highlight"对象,而不实际 "selecting"对象

android - 在Android中绘制带曲线底部的矩形 View

javascript - 外部路径不相互链接?

javascript - CSS:不同分辨率的缩放问题

css - 找不到模块 : Error: Can't resolve './style.css' in Directory?

css - Wordpress body_class() 在博客页面上加载单个帖子 css

javascript - 从坐标fabric js绘制路径

javascript - 是否有类似可选链的东西在 javascript 中进行赋值

javascript - jquery保存$(this),然后重新运行(重写)它,它效果不好。

css - 如何使 ul 在其内容框中包含 li?