javascript - 在任何位置(X,Y)使用 JavaScript 绘制心形

标签 javascript html css animation canvas

在codepen.io看过一个不错的动画Link Here .真的很神奇。但我想把它改成心形(爱情符号)而不是红色箭头。所以我开始调试代码,我找到了 function drawArrow,他们在其中绘制箭头。在那里我尝试实现心画(得到代码 from here )。

        var ctx = _pexcanvas.getContext("2d");
        var d = 20; //The Size of the hearting
        var k =150; // The Position of the heart
        ctx.moveTo(k, k + d / 4);
        ctx.quadraticCurveTo(k, k, k + d / 4, k);
        ctx.quadraticCurveTo(k + d / 2, k, k + d / 2, k + d / 4);
        ctx.quadraticCurveTo(k + d / 2, k, k + d * 3/4, k);
        ctx.quadraticCurveTo(k + d, k, k + d, k + d / 4);
        ctx.quadraticCurveTo(k + d, k + d / 2, k + d * 3/4, k + d * 3/4);
        ctx.lineTo(k + d / 2, k + d);
        ctx.lineTo(k + d / 4, k + d * 3/4);
        ctx.quadraticCurveTo(k, k + d / 2, k, k + d / 4);

但是在使用上面的代码时我不能改变心脏的起始位置,这意味着如果我增加 K 值它会将心脏置于线性位置(像心脏只会出现在(-x,y) 到 (x,-y)) 的线性范围,

但是我喜欢把心放在屏幕的任何地方,但是我做不到。给我正确的方向来修复它。

注意:我不是 JavaScript 开发人员,我有 java 的基础知识。

提前致谢。

最佳答案

你只需要添加新的功能来绘制心而不是箭头,你提到的解决方案将绘制一个稳定的心。

宽度和高度可以根据您的要求使用。

添加如下函数:

function drawHeart(fromx, fromy, tox, toy,lw,hlen,color) {

  var x = fromx;
  var y = fromy;
  var width = lw ;
  var height = hlen;

  ctx.save();
  ctx.beginPath();
  var topCurveHeight = height * 0.3;
  ctx.moveTo(x, y + topCurveHeight);
  // top left curve
  ctx.bezierCurveTo(
    x, y, 
    x - width / 2, y, 
    x - width / 2, y + topCurveHeight
  );

  // bottom left curve
  ctx.bezierCurveTo(
    x - width / 2, y + (height + topCurveHeight) / 2, 
    x, y + (height + topCurveHeight) / 2, 
    x, y + height
  );

  // bottom right curve
  ctx.bezierCurveTo(
    x, y + (height + topCurveHeight) / 2, 
    x + width / 2, y + (height + topCurveHeight) / 2, 
    x + width / 2, y + topCurveHeight
  );

  // top right curve
  ctx.bezierCurveTo(
    x + width / 2, y, 
    x, y, 
    x, y + topCurveHeight
  );

  ctx.closePath();
  ctx.fillStyle = color;
  ctx.fill();
  ctx.restore();

}

下面是相同的工作解决方案。

"use strict"
var stage = {
  w:1280,
  h:720
}

var _pexcanvas = document.getElementById("canvas");
_pexcanvas.width = stage.w;
_pexcanvas.height = stage.h;
var ctx = _pexcanvas.getContext("2d");




var pointer = {
  x:0,
  y:0
}

var scale = 1;
var portrait = true;
var loffset = 0;
var toffset = 0;
var mxpos = 0;
var mypos = 0;


// ------------------------------------------------------------------------------- Gamy
function drawArrow(fromx, fromy, tox, toy,lw,hlen,color) {
  var dx = tox - fromx;
  var dy = toy - fromy;
  var angle = Math.atan2(dy, dx);
  ctx.fillStyle=color;
  ctx.strokeStyle=color;
  ctx.lineCap = "round";
  ctx.lineWidth = lw;
  ctx.beginPath();
  ctx.moveTo(fromx, fromy);
  ctx.lineTo(tox, toy);
  ctx.stroke();
  ctx.beginPath();
  ctx.moveTo(tox, toy);
  ctx.lineTo(tox - hlen * Math.cos(angle - Math.PI / 6), toy - hlen * Math.sin(angle - Math.PI / 6));
  ctx.lineTo(tox - hlen * Math.cos(angle)/2, toy - hlen * Math.sin(angle)/2);
  ctx.lineTo(tox - hlen * Math.cos(angle + Math.PI / 6), toy - hlen * Math.sin(angle + Math.PI / 6));
  ctx.closePath();
  ctx.stroke();
  ctx.fill();
}


function drawHeart(fromx, fromy, tox, toy,lw,hlen,color) {

  var x = fromx;
  var y = fromy;
  var width = lw ;
  var height = hlen;

  ctx.save();
  ctx.beginPath();
  var topCurveHeight = height * 0.3;
  ctx.moveTo(x, y + topCurveHeight);
  // top left curve
  ctx.bezierCurveTo(
    x, y, 
    x - width / 2, y, 
    x - width / 2, y + topCurveHeight
  );

  // bottom left curve
  ctx.bezierCurveTo(
    x - width / 2, y + (height + topCurveHeight) / 2, 
    x, y + (height + topCurveHeight) / 2, 
    x, y + height
  );

  // bottom right curve
  ctx.bezierCurveTo(
    x, y + (height + topCurveHeight) / 2, 
    x + width / 2, y + (height + topCurveHeight) / 2, 
    x + width / 2, y + topCurveHeight
  );

  // top right curve
  ctx.bezierCurveTo(
    x + width / 2, y, 
    x, y, 
    x, y + topCurveHeight
  );

  ctx.closePath();
  ctx.fillStyle = color;
  ctx.fill();
  ctx.restore();

}



var colors = ['#1abc9c','#1abc9c','#3498db','#9b59b6','#34495e','#16a085','#27ae60','#2980b9','#8e44ad','#2c3e50','#f1c40f','#e67e22','#e74c3c','#95a5a6','#f39c12','#d35400','#c0392b','#bdc3c7','#7f8c8d'];


ctx.clearRect(0,0,stage.w,stage.h);
for (var i =0;i<200;i++) {
var angle = Math.random()*Math.PI*2;
var length = Math.random()*250+50;
var myx=360+Math.sin(angle)*length;
var myy=360-Math.cos(angle)*length;
drawArrow(myx,myy,myx+length/6*Math.sin(angle),myy-length/6*Math.cos(angle),length/30,length/30,'#c0392b');
}
var explode = new Image();
explode.src = canvas.toDataURL("image/png");

ctx.clearRect(0,0,stage.w,stage.h);
for (var i =0;i<200;i++) {
var angle = Math.random()*Math.PI-Math.PI/2;
var length = Math.random()*480+50;
var myx=stage.w/2+Math.sin(angle)*length;
var myy=stage.h-Math.cos(angle)*length;
drawArrow(myx,myy,myx+length/6*Math.sin(angle),myy-length/6*Math.cos(angle),length/30,length/30,'#2c3e50');
}
var explodeb = new Image();
explodeb.src = canvas.toDataURL("image/png");


ctx.clearRect(0,0,stage.w,stage.h);
ctx.fillStyle = "rgba(236,240,241,1)";
ctx.fillRect(0,0,stage.w,stage.h);
for (var i =0;i<200;i++) {
var angle = Math.random()*Math.PI/Math.PI*180;
var length = Math.random()*250+50;
var myx=Math.random()*stage.w;
var myy=Math.random()*stage.h;
drawArrow(myx,myy,myx+length/6*Math.sin(angle),myy-length/6*Math.cos(angle),length/30,length/30,colors[Math.floor(Math.random()*colors.length)]);
}

ctx.fillStyle = "rgba(236,240,241,0.9)";
ctx.fillRect(0,0,stage.w,stage.h);
var back = new Image();
back.src = canvas.toDataURL("image/png");

var angle=0;
var ai = true;
var ait = 0;
var btm=0;
var bullets = [];

function Bullet() {
this.x=stage.w/2-Math.sin(angle)*150;
this.y=stage.h-Math.cos(angle)*150;
this.r=angle;
}

var enemies = [];
function Enemy() {
this.r = Math.random()*Math.PI/(2.5/2)-Math.PI/2.5;
this.dis = Math.random()*1280+720;
this.x=stage.w/2-Math.sin(this.r)*this.dis;
this.y=stage.h-Math.cos(this.r)*this.dis;
}
for(var i=0;i<10;i++) {
enemies.push(new Enemy());

enemies[i].x += Math.sin(enemies[i].r)*300;
enemies[i].y += Math.cos(enemies[i].r)*300;
}



var explosions = [];
function Explosion(x,y,ty) {
this.x=x;
this.y=y;
this.t=30;
this.ty=ty;
}

var eturn = 0;
var cold = [];
function enginestep() {

ctx.drawImage(back,0,0);
if (!ai&&ait<Date.now()-3000) {
ai = true;
}
btm++;
if(btm>8){
btm=0;
bullets.push(new Bullet());
}

for (var i=0;i<bullets.length;i++) {
  bullets[i].x -= Math.sin(bullets[i].r)*20;
  bullets[i].y -= Math.cos(bullets[i].r)*20;
  drawArrow(bullets[i].x+Math.sin(bullets[i].r)*50,bullets[i].y+Math.cos(bullets[i].r)*50,bullets[i].x,bullets[i].y,8,8,'#2980b9');
  if(bullets[i].x<-100||bullets[i].x>stage.w+100){
    bullets.splice(i,1);
  }
  if(bullets[i].y<-100||bullets[i].y>stage.h+100){
    bullets.splice(i,1);
  }

}


for(var i=0;i<enemies.length;i++) {
  enemies[i].x += Math.sin(enemies[i].r)*3;
  enemies[i].y += Math.cos(enemies[i].r)*3;
  drawHeart(enemies[i].x-Math.sin(enemies[i].r)*100,enemies[i].y-Math.cos(enemies[i].r)*100,enemies[i].x,enemies[i].y,15,15,"#c0392b");
  if (enemies[i].y>stage.h) {
    enemies[i] = new Enemy();
    explosions.push(new Explosion(stage.w/2,stage.h,2));
      shake = true;
      shaket=0;
  }
  for (var b=0;b<bullets.length;b++) {
    var dx = enemies[i].x-bullets[b].x;
    var dy = enemies[i].y-bullets[b].y;
    var dis = dx*dx+dy*dy;
    if (dis<20*20) {
      explosions.push(new Explosion(enemies[i].x,enemies[i].y,1));
      enemies[i] = new Enemy();
      bullets.splice(b,1);
    }
  }
}

if (ai) {
for(var l=0;l<enemies.length;l++) {
  var dx = enemies[l].x-stage.w/2;
  var dy = enemies[l].y-stage.h;
  var dis = Math.floor(Math.sqrt(dx*dx+dy*dy));
  var val1 = 100000+dis;
  var val2 = 1000+l;
  cold[l]=val1+'x'+val2;
}



cold.sort();
eturn = parseInt(cold[0].slice(8,11));
if (parseInt(cold[0].slice(1,6))<800) {
  angle += (enemies[eturn].r-angle)/8;
}
} else {

var dx = pointer.x-stage.w/2;
var dy = pointer.y-stage.h;
angle = Math.atan(dx/dy);
}

drawArrow(stage.w/2,stage.h,stage.w/2-Math.sin(angle)*150,stage.h-Math.cos(angle)*150,30,20,'#2c3e50');



for(var e=0;e<explosions.length;e++) {

if (explosions[e].ty==1) {
  var myimg = explode;
  ctx.globalAlpha=1-(explosions[e].t/stage.h);
  ctx.drawImage(myimg,explosions[e].x-explosions[e].t/2,explosions[e].y-explosions[e].t/2,explosions[e].t*stage.w/stage.h,explosions[e].t);
  ctx.globalAlpha=1;
} else {
  var myimg = explodeb;
  ctx.globalAlpha=1-(explosions[e].t/stage.h);
  ctx.drawImage(myimg,explosions[e].x-explosions[e].t*stage.w/stage.h/2,stage.h-explosions[e].t,explosions[e].t*stage.w/stage.h,explosions[e].t);
  ctx.globalAlpha=1;
}

}


for(var e=0;e<explosions.length;e++) {
explosions[e].t += 20;
if (explosions[e].t>stage.h) {
  explosions.splice(e,1);
}
}
}


// ------------------------------------------------------------------------------- events
// ------------------------------------------------------------------------------- events
// ------------------------------------------------------------------------------- events
// ------------------------------------------------------------------------------- events

function toggleFullScreen() {
var doc = window.document;
var docEl = doc.documentElement;

var requestFullScreen = docEl.requestFullscreen || docEl.mozRequestFullScreen || docEl.webkitRequestFullScreen || docEl.msRequestFullscreen;
var cancelFullScreen = doc.exitFullscreen || doc.mozCancelFullScreen || doc.webkitExitFullscreen || doc.msExitFullscreen;

if(!doc.fullscreenElement && !doc.mozFullScreenElement && !doc.webkitFullscreenElement && !doc.msFullscreenElement) {
requestFullScreen.call(docEl);

}
else {
cancelFullScreen.call(doc);

}
}


function motchstart(e) {
mxpos = (e.pageX-loffset)*scale;
mypos = (e.pageY-toffset)*scale;




}

function motchmove(e) {
mxpos = (e.pageX-loffset)*scale;
mypos = (e.pageY-toffset)*scale;
pointer.x = mxpos;
pointer.y = mypos;
ai = false;
ait = Date.now();
}

function motchend(e) {

}






window.addEventListener('mousedown', function(e) {
motchstart(e);
}, false);
window.addEventListener('mousemove', function(e) {
motchmove(e);
}, false);
window.addEventListener('mouseup', function(e) {
motchend(e);
}, false);
window.addEventListener('touchstart', function(e) {
e.preventDefault();
motchstart(e.touches[0]);
}, false);
window.addEventListener('touchmove', function(e) {
e.preventDefault();
motchmove(e.touches[0]);
}, false);
window.addEventListener('touchend', function(e) {
e.preventDefault();
motchend(e.touches[0]);
}, false);



// ------------------------------------------------------------------------ stager
// ------------------------------------------------------------------------ stager
// ------------------------------------------------------------------------ stager
// ------------------------------------------------------------------------ stager
function _pexresize() {
var cw = window.innerWidth;
var ch = window.innerHeight;
if (cw<=ch*stage.w/stage.h) {
portrait = true;
scale = stage.w/cw;
loffset = 0;
toffset = Math.floor(ch-(cw*stage.h/stage.w))/2;
_pexcanvas.style.width = cw + "px";
_pexcanvas.style.height = Math.floor(cw*stage.h/stage.w) + "px";
_pexcanvas.style.marginLeft = loffset +"px";
_pexcanvas.style.marginTop = toffset +"px";
} else {
scale = stage.h/ch;
portrait = false;
loffset = Math.floor(cw-(ch*stage.w/stage.h))/2;
toffset = 0;
_pexcanvas.style.height = ch + "px";
_pexcanvas.style.width = Math.floor(ch*stage.w/stage.h) + "px";
_pexcanvas.style.marginLeft = loffset +"px";
_pexcanvas.style.marginTop = toffset +"px";
}
}


window.requestAnimFrame = (function(){
return  window.requestAnimationFrame       ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame    ||
window.oRequestAnimationFrame      ||
window.msRequestAnimationFrame     ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};})();



function sfps(iny) {
return(Math.floor(smoothfps)/60*iny);
}



var timebomb=0;
var lastCalledTime;
var fpcount = 0;
var fpall = 0;
var smoothfps = 60;
var thisfps = 60;
function fpscounter() {
timebomb ++;
if (!lastCalledTime) {
  lastCalledTime = Date.now();
  return;
}
var delta = (Date.now()-lastCalledTime)/1000;
lastCalledTime = Date.now();
var fps = 1/delta;
fpcount ++;
fpall += fps;
if (timebomb>30) {
  thisfps = parseInt(fpall/fpcount*10)/10;
  fpcount = 0;
  fpall = 0;
  timebomb = 0;
}
}

var shake = false;
var shaket = 0;
function animated() {
requestAnimFrame(animated);
if (shake) {
  var trax = Math.random()*60-30;
  var tray = Math.random()*60-30;
  ctx.translate(trax,tray);
}
// fpscounter();
//ctx.clearRect(0,0,_pexcanvas.width,_pexcanvas.height);
enginestep()
// ctx.fillStyle='#8e44ad';
// ctx.font = "24px arial";

// ctx.textAlign = "left"; 
// ctx.fillText(thisfps,20,50);
// smoothfps += (thisfps-smoothfps)/100;
// ctx.fillText(cold[0].slice(1,6),20,80);
//  ctx.beginPath();
//  ctx.arc(pointer.x, pointer.y, 50, 0, Math.PI*2,false);
// ctx.closePath();
// ctx.fill();
if (shake) {
 ctx.translate(-trax,-tray);
 shaket ++;
 if (shaket>20) {
   shaket=0;
   shake=false;
 }
}
}

_pexresize();
animated();
   body {background:#000000;margin:0;padding:0}

canvas {background:#ecf0f1;}
         <html>
<head>
	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<meta name="description" content="Pex.Js Engine">
	<meta name="author" content="Ahmad Faisal Jawed">
	<title>Arrows</title>
</head>
<body onresize='_pexresize()'>

	<canvas id='canvas' width=1280 height=720></canvas>

</body>
</html>

关于javascript - 在任何位置(X,Y)使用 JavaScript 绘制心形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58333678/

相关文章:

javaScript 正在获取浏览器日期?我怎样才能改变它?

javascript - 设置 Jekyll 站点

html - 在 HTML 中创建帮助文件

jquery - 如何将显示从无切换到表格单元格?

html在全局中隐藏滚动条,我如何在div标签中显示它

html - 输入文本框宽度与父级相同

javascript - 动态计数器随逗号上升

javascript - 防止 useEffect 在初始渲染时触发

javascript - 文件加载不正确

css - 修改Rails的custom.scss.css导致报错