嘿,我创造了一种非常复杂的三角形,其中包含7个片段和标签以供指导。 我正在尝试为当前形状添加放大/缩小功能。 我已经使用缩放方法编写了放大方法,问题是当我放大或缩小三角形时,每个东西都会分崩离析,我无法正确缩放。 我对这个问题的建议是: 1.将所有元素组合成一个元素,然后放大或缩小统一元素。我在画布上做了吗? 2.缩小到特定的中间绝对点,我该怎么办? 任何帮助都将得到祝福,提前谢谢: - )。
放大/缩小方法:
$('#zoomIn').click(function() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.scale(1/0.9, 1/0.9);
drawDuvalShape();
});
$('#zoomOut').click(function() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.scale(0.90, 0.90);
drawDuvalShape();
});
$(function(){
//offset : 150+ : x & 50+ : y.
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:154,y:344};
var v1={x:302,y:69};
var v2={x:450,y:344};
var triangle=[v0,v1,v2];
// Define all your segments here
var segments=[
{
points:[{x:154,y:344},{x:184,y:344},{x:236,y:246},{x:222,y:219}],
fill:'rgb(172,236,222)',
label:{text:'O',cx:200,cy:290,withLine:false,endX:null,endY:null}
},
{
points:[{x:236,y:246},{x:222,y:219},{x:280,y:111},{x:295,y:136}],
fill:'deepskyblue',
label:{text:'S',cx:258,cy:180,withLine:false,endX:null,endY:null}
},
{
points:[{x:280,y:111},{x:295,y:136},{x:317,y:96},{x:302,y:69}],
fill:'rgb(172,236,222)',
label:{text:'O',cx:300,cy:110,withLine:false,endX:305,endY:120}
},
{
points:[{x:184,y:344},{x:258,y:344},{x:310,y:248},{x:273,y:179},],
fill:'navajoWhite',
label:{text:'ND',cx:260,cy:280,withLine:false,endX:null,endY:null}
},
{
points:[{x:258,y:344},{x:310,y:248},{x:360,y:344}],
fill:'#8CAAD2',
label:{text:'T3',cx:310,cy:310,withLine:false,endX:null,endY:null}
},
{
points:[{x:360,y:344},{x:273,y:179},{x:300,y:130},{x:355,y:232},{x:353,y:236},{x:386,y:300}],
fill:'peru',
label:{text:'C',cx:320,cy:220,withLine:false,endX:null,endY:null}
},
{
points:[{x:360,y:344},{x:450,y:344},{x:353,y:167},{x:337,y:198},{x:355,y:232},{x:353,y:236},{x:386,y:300}],
fill:'#8CAAD2',
label:{text:'T3',cx:400,cy:310,withLine:false,endX:null,endY:null}
},
{
points:[{x:337,y:198},{x:353,y:167},{x:317,y:96},{x:300,y:128}],
fill:'#918CD2',
label:{text:'T2',cx:328,cy:150,withLine:false,endX:null,endY:null}
},
{
points:[{x:280,y:111},{x:283,y:113},{x:291,y:96},{x:288,y:96}],
fill:'#d2b48c',
label:{text:'PD',cx:250,cy:86,withLine:true,endX:295,endY:96}
},
{
points:[{x:291,y:96},{x:288,y:96},{x:299,y:75},{x:302,y:78}],
fill:'#d2b48c',
label:{text:'PD',cx:250,cy:86,withLine:true,endX:295,endY:96}
}
];
// 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',
'T2 = Thermal fault 300 ℃ < T < 700 ℃',
'T3 = Thermal fault T > 700 ℃',
'O = Overheating < 250ºC',
'S = Stray Gassing of Oil',
'ND = Not Determined',
'C = Carbonization'];
drawDuvalShape();
function drawDuvalShape(){
// start drawing
/////////////////////
// draw colored segments inside triangle
for(var i=0;i<segments.length;i++){
drawSegment(segments[i]);
}
// draw ticklines
ticklines(v0,v1,9,0,20);
ticklines(v1,v2,9,Math.PI*3/4,20);
ticklines(v2,v0,9,Math.PI*5/4,20);
// molecules
moleculeLabel(v0,v1,100,Math.PI,'% CH4');
moleculeLabel(v1,v2,100,0,'% C2H4');
moleculeLabel(v2,v0,75,Math.PI/2,'% C2H6');
// draw outer triangle
drawTriangle(triangle);
// 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 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.translate(x3,y3);
ctx.rotate(angle);
ctx.drawImage(arrowhead,-arrowheadLength,-arrowheadWidth/2);
ctx.setTransform(1,0,0,1,0,0);
}
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);
}
}
$('#zoomIn').click(function() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.scale(1/0.9, 1/0.9);
drawDuvalShape();
});
$('#zoomOut').click(function() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.scale(0.90, 0.90);
drawDuvalShape();
});
})
&#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=650 height=500></canvas>
<button id="zoomIn">+</button>
<button id="zoomOut">-</button>
&#13;
答案 0 :(得分:1)
渲染代码在绘图期间重置变换:
ctx.setTransform(1,0,0,1,0,0);
这意味着在绘图过程中将覆盖缩放变换。
在moleculeLabel()
方法的末尾找到此代码段:
...
var angle=Math.atan2(dy,dx);
ctx.translate(x3,y3);
ctx.rotate(angle);
ctx.drawImage(arrowhead,-arrowheadLength,-arrowheadWidth/2);
ctx.setTransform(1,0,0,1,0,0);
}
并改为:
var angle=Math.atan2(dy,dx);
ctx.save(); // save
ctx.translate(x3,y3);
ctx.rotate(angle);
ctx.drawImage(arrowhead,-arrowheadLength,-arrowheadWidth/2);
ctx.restore(); // restore
}
这将保留全球变换。可能会有更多实例,如果是,请重复。
关于缩放中心(从original answer here添加回来):
缩放将始终发生在原点(其中(0,0)最初位于上下文的左上角),因此为了能够在特定点进行缩放,您需要做的就是首先转换为所需的缩放中心,应用缩放,翻译(在这种情况下)和绘制。
简化此操作的一种方法是在形状的预定义中心点(0,0)周围定义三角形和形状,以便形状中的所有点都相对于此。
答案 1 :(得分:0)
使用ctx.scale。 ctx.scale缩放ypu在画布上绘制的所有内容。唯一的缺点是,它只能从左上角扩展。
这可以通过首先对画布进行描绘来解决,因此图像的中间位于左上角,缩放,然后向后变换,并绘制三角形。