console
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>bezierCurveTo</title>
<style>
.canvas{
display: inline-block;
float: left;
width: 300px;
margin: 10px;
}
canvas {
border:1px solid #d3d3d3;
}
</style>
</head>
<body>
<div class="canvas">
<div>------------线条样式------------</div>
<canvas id="myCanvas1" width="300" height="300"></canvas>
</div>
<div class="canvas">
<div>------------线条样式------------</div>
<canvas id="myCanvas2" width="300" height="300"></canvas>
</div>
<div class="canvas">
<div>-------手动调整贝塞尔曲线--------</div>
<canvas id="myCanvas3" width="300" height="300"></canvas>
</div>
<div class="canvas">
<div>------------粒子特效-----------</div>
<canvas id="myCanvas4" width="300" height="300"></canvas>
<input type="text" id='textNode' placeholder="请输入要粒子化的文字" />
<button id='submiteBtn'>提交</button>
</div>
<script>
var myCanvas1 = document.getElementById('myCanvas1');
var ctx1 = myCanvas1.getContext('2d');
var myCanvas2 = document.getElementById('myCanvas2');
var ctx2 = myCanvas2.getContext('2d');
let x = 0, y = 300, h = 0;
function drawBezierCurveTo(ctx, x, y, h){
ctx.beginPath();
ctx.fillStyle = 'black';
ctx.moveTo(90, 0);
ctx.lineTo(150, 300);
ctx.lineTo(30, 300);
ctx.closePath();
ctx.strokeStyle = 'blue';
ctx.fill();
ctx.stroke();
ctx.globalCompositeOperation = 'source-atop';
ctx.beginPath();
ctx.moveTo(x, y);
ctx.strokeStyle="red";
ctx.quadraticCurveTo(x + 15, y + 15, x + 30, y);
ctx.quadraticCurveTo(x + 45, y - 15, x + 60, y);
ctx.quadraticCurveTo(x + 75, y + 15, x + 90, y);
ctx.quadraticCurveTo(x + 105, y - 15, x + 120, y);
ctx.quadraticCurveTo(x + 135, y + 15, x + 150, y);
ctx.quadraticCurveTo(x + 165, y - 15, x + 180, y);
ctx.quadraticCurveTo(x + 195, y + 15, x + 210, y);
ctx.lineTo(x + 210, y + h);
ctx.lineTo(x, y + h);
ctx.closePath();
ctx.fillStyle = 'pink';
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.font = "20px Georgia";
ctx.textAlign = 'center';
ctx.fillStyle = 'white';
ctx.fillText((h / 300).toFixed(2) * 100 + '%', 90, 150);
}
function totalAnimate(){
let timer = setInterval(()=>{
drawBezierCurveTo(ctx1, x, y, h);
x -= 1;
y -= 1;
h += 1;
if (y < 20){
clearInterval(timer);
timer = null;
}
if(x === -60){
x = 0
}
},20);
}
totalAnimate();
// drawBezierCurveTo(x, y);
// drawText('hello world') ;
function drawText(text) {
ctx1.beginPath();
ctx1.font = '30px Arial';
ctx1.textAlign="center";
ctx1.fillStyle = 'red';
ctx1.globalCompositeOperation = 'source-over';
ctx1.fillText(text, 150, 150);
}
// -----------------------------------canvas属性划分-------------------------------\
function drawLine(ctx, sx,sy, ex, ey, color, lineWidth){
ctx.beginPath();
ctx.moveTo(sx, sy);
ctx.lineTo(ex, ey);
ctx.lineWidth = lineWidth;
ctx.strokeStyle = color;
ctx.stroke();
}
drawLine(ctx2, 20, 20, 275, 20, 'red', 5);
drawLine(ctx2, 20, 40, 275, 40, 'pink', 5);
function drawRect (){
ctx2.clearRect(-30, -30, 60, 60);
ctx2.beginPath();
ctx2.lineWidth = 1;
ctx2.strokeStyle = 'red';
ctx2.moveTo(-20, -20);
ctx2.lineTo(20, -20);
ctx2.lineTo(0, 0);
ctx2.closePath();
ctx2.fillStyle = 'red';
ctx2.fill();
ctx2.stroke();
ctx2.beginPath();
ctx2.lineWidth = 1;
ctx2.strokeStyle = 'yellow';
ctx2.moveTo(20, -20);
ctx2.lineTo(20, 20);
ctx2.lineTo(0, 0);
ctx2.closePath();
ctx2.fillStyle = 'yellow';
ctx2.fill();
ctx2.stroke();
ctx2.beginPath();
ctx2.lineWidth = 1;
ctx2.strokeStyle = 'pink';
ctx2.moveTo(20, 20);
ctx2.lineTo(-20, 20);
ctx2.lineTo(0, 0);
ctx2.closePath();
ctx2.fillStyle = 'pink';
ctx2.fill();
ctx2.stroke();
ctx2.beginPath();
ctx2.lineWidth = 1;
ctx2.strokeStyle = 'white';
ctx2.moveTo(-20, 20);
ctx2.lineTo(-20, -20);
ctx2.lineTo(0, 0);
ctx2.fillStyle = 'white';
ctx2.fill();
ctx2.closePath();
ctx2.stroke();
ctx2.beginPath();
ctx2.strokeStyle = 'black';
ctx2.arc(0,0,20,0,2*Math.PI);
ctx2.stroke();
}
// ctx2.translate(40,80);
let angle = 0;
// drawRect();
ctx2.translate(40,60);
let timer2 = setInterval(()=>{
drawRect();
ctx2.rotate(4 * Math.PI / 180);
angle += 5;
if (angle > 720) {
clearInterval(timer2);
timer2 = null;
}
},30);
// 手动调整贝塞尔曲线
class Canvas03 {
constructor(id){
let idNode = document.getElementById(id);
this.id = idNode;
this.width = idNode.width;
this.height = idNode.height;
this.ctx = idNode.getContext('2d');
this.top = idNode.getBoundingClientRect().top;
this.left = idNode.getBoundingClientRect().left;
this.startX = 60;
this.startY = 100;
this.startText = '';
this.endX = 240;
this.endY = 100;
this.endText = '';
this.controlX = 150;
this.controlY = 150;
this.controlText = '';
this.pointName = '';
this.mousemovefn = this.mousemovefn.bind(this);
this.mousedownfn = this.mousedownfn.bind(this);
this.mouseupfn = this.mouseupfn.bind(this);
this.getMousePos = this.getMousePos.bind(this);
this.sampleMousemovefn = this.sampleMousemovefn.bind(this);
}
init() {
this.ctx.clearRect(0,0,this.width,this.height);
this.drawLine();
this.drawthreeArc();
this.dragFn();
}
// 绘制贝塞尔曲线 以及控制点到贝塞尔曲线两端的直线
drawLine() {
let {startX, startY, endX, endY, controlX, controlY} = this;
this.ctx.beginPath();
this.ctx.moveTo(startX, startY);
this.ctx.quadraticCurveTo(controlX, controlY, endX, endY);
this.ctx.stroke();
this.ctx.beginPath();
this.ctx.moveTo(startX, startY);
this.ctx.lineTo(controlX, controlY);
this.ctx.strokeStyle = 'pink';
this.ctx.stroke();
this.ctx.beginPath();
this.ctx.moveTo(endX, endY);
this.ctx.lineTo(controlX, controlY);
this.ctx.strokeStyle = 'pink';
this.ctx.stroke();
}
// 控制点增加圆环样式
drawArc(x, y, r, lineWidth) {
this.ctx.beginPath();
this.ctx.strokeStyle = "#999";
this.ctx.arc(x,y,r,0,2*Math.PI);
if (lineWidth) this.ctx.lineWidth = lineWidth;
this.ctx.fillText("("+ x +","+ y +")", x + 10, y);
this.ctx.stroke();
}
// 绘制三个控制点 直线的开始点 结束点 贝塞尔曲线的控制点
drawthreeArc(){
let {startX, startY, endX, endY, controlX, controlY} = this;
this.drawArc(startX, startY, 6);
this.drawArc(endX, endY, 6);
this.drawArc(controlX, controlY, 6);
}
//获取鼠标在画布中的绝对位置
getMousePos(evt){
let rect = this.id.getBoundingClientRect();
return {
x: evt.clientX - rect.left * (this.width / rect.width),
y: evt.clientY - rect.top * (this.height / rect.height)
}
}
// 点被选中后的鼠标移动事件
mousemovefn(evt){
let {x, y} = this.getMousePos(evt);
let {top, left} = this;
let {startX, startY, endX, endY, controlX, controlY} = this;
if (x > controlX - 10 && y > controlY - 10 && x < controlX + 10 && y < controlY + 10){
this.pointName = 'control';
this.id.style.cssText = "cursor: pointer;";
this.drawArc(controlX, controlY, 8, 1);
this.controlX = evt.clientX - left;
this.controlY = evt.clientY - top;
this.avoidStartAndEndPointOverlay();
this.init();
}else {
this.pointName = '';
this.id.style.cssText = "cuosor: default;";
this.init();
}
if (x > startX - 10 && y > startY - 10 && x < startX + 10 && y < startY + 10){
this.pointName = 'start';
this.id.style.cssText = "cursor: pointer;";
this.drawArc(startX, startY, 8, 1);
this.startX = evt.clientX - left;
this.startY = evt.clientY - top;
this.avoidStartAndEndPointOverlay();
this.init();
}else {
this.pointName = '';
this.id.style.cssText = "cuosor: default;";
this.init();
}
if (x > endX - 10 && y > endY - 10 && x < endX + 10 && y < endY + 10){
this.pointName = 'end';
this.id.style.cssText = "cursor: pointer;";
this.drawArc(endX, endY, 8, 1);
this.endX = evt.clientX - left;
this.endY = evt.clientY - top;
this.avoidStartAndEndPointOverlay();
this.init();
}else {
this.pointName = '';
this.id.style.cssText = "cuosor: default;";
this.init();
}
}
// 避免三个控制点位置重叠
avoidStartAndEndPointOverlay(){
let {startX, startY, endX, endY, controlX, controlY} = this;
if (Math.abs(startX - endX) < 5 || Math.abs(startY - endY) < 5) {
if (this.pointName === 'start') {
this.startX += 5;
this.startY += 5;
}
if (this.pointName === 'end') {
this.endX += 5;
this.endY += 5;
}
}
if (Math.abs(startX - controlX) < 5 || Math.abs(startY - controlY) < 5) {
if (this.pointName === 'start') {
this.startX += 5;
this.startY += 5;
}
if (this.pointName === 'control') {
this.controlX += 5;
this.controlY += 5;
}
}
if (Math.abs(endX - controlX) < 5 || Math.abs(endY - controlY) < 5) {
if (this.pointName === 'end') {
this.endX += 5;
this.endY += 5;
}
if (this.pointName === 'control') {
this.controlX += 5;
this.controlY += 5;
}
}
}
// 鼠标移动事件。当鼠标移动到控制点时控制点增加样式
sampleMousemovefn(evt){
let {x, y} = this.getMousePos(evt);
let {top, left} = this;
let {startX, startY, endX, endY, controlX, controlY} = this;
if (x > controlX - 10 && y > controlY - 10 && x < controlX + 10 && y < controlY + 10){
this.id.style.cssText = "cursor: pointer;";
this.drawArc(controlX, controlY, 6, 1);
}else {
this.id.style.cssText = "cuosor: default;";
}
if (x > startX - 10 && y > startY - 10 && x < startX + 10 && y < startY + 10){
this.id.style.cssText = "cursor: pointer;";
this.drawArc(startX, startY, 6, 1);
}else {
this.id.style.cssText = "cuosor: default;";
}
if (x > endX - 10 && y > endY - 10 && x < endX + 10 && y < endY + 10){
this.id.style.cssText = "cursor: pointer;";
this.drawArc(endX, endY, 6, 1);
}else {
this.id.style.cssText = "cuosor: default;";
}
}
mousedownfn(){
this.id.addEventListener("mousemove", this.mousemovefn, false);
}
mouseupfn(){
this.id.removeEventListener("mousemove",this.mousemovefn, false);
this.init();
}
// 圆点拖拽功能
dragFn(){
this.id.removeEventListener('mousemove', this.sampleMousemovefn, false);
this.id.removeEventListener('mousedown', this.mousedownfn, false);
this.id.removeEventListener('mouseup', this.mouseupfn, false);
this.id.addEventListener("mousemove", this.sampleMousemovefn, false);
this.id.addEventListener("mousedown", this.mousedownfn, false);
this.id.addEventListener("mouseup", this.mouseupfn, false);
}
}
const myCanvas3 = new Canvas03('myCanvas3');
myCanvas3.init();
// 粒子特效
class ParticleEffects {
constructor (){
let myCanvas4 = document.getElementById('myCanvas4');
let textNode = document.getElementById('textNode');
let submiteBtn = document.getElementById('submiteBtn');
this.myCanvas4 = myCanvas4;
this.textNode = textNode;
this.submiteBtn = submiteBtn;
this.width = myCanvas4.width;
this.height = myCanvas4.height;
this.ctx = myCanvas4.getContext('2d');
this.top = myCanvas4.getBoundingClientRect().top;
this.left = myCanvas4.getBoundingClientRect().left;
this.textValue = '❤️canvas';
this.textBindEvent();
this.submitBtnBindEvent();
}
init(){
this.drawText();
}
// 在canvas上绘制文本
drawText(){
this.ctx.clearRect(0, 0, this.width, this.height);
this.ctx.beginPath();
this.ctx.textAlign = "center";
this.ctx.font = '66px Arial';
this.ctx.fillStyle = 'pink';
this.ctx.fillText(this.textValue, 150, 150);
this.ctx.stroke();
this.canvsaToImage();
}
// 将canvas转成图片 然后再绘制图片
canvsaToImage(){
let img = new Image();
img.src = this.myCanvas4.toDataURL('image/jepg');
img.onload = ()=>{
this.ctx.drawImage(img, 0, 0);
let imageData = this.ctx.getImageData(0, 0, this.width, this.height);
let particleData = [];
// 反转颜色
let startX = 125, startY = 125;
for (var i=0, j = 1;i<imageData.data.length;i+=4){
let colorStr = imageData.data[i] + '' + imageData.data[i+1]+ imageData.data[i+2]+ imageData.data[i+3];
if (colorStr !== '0000') {
particleData.push({
x: j % this.width,
y: parseInt(j / this.width) + 1,
moveX: 0,
moveY: 0,
flutteMoveX: 0,
flutteMoveY: 0,
xStep: (j % this.width -( startX % 100 + 100)) / 10,
yStep: (parseInt(j / this.width) + 1 - (Math.floor(startX / 100) + 100)) / 10,
startX: startX % 100 + 100,
startY: Math.floor(startX / 100) + 100
});
startX++;
}
j++;
}
this.drawParticle(particleData);
}
}
// 绘制粒子描绘出来的粒子
drawParticle(particleDataArr){
if (Object.prototype.toString.call(particleDataArr) === '[object Array]'){
// 增加飘动效果
this.ctx.clearRect(0, 0, this.width, this.height);
particleDataArr.map((item, index)=>{
let {startX, startY} = item;
this.ctx.beginPath();
this.ctx.arc(startX, startY, 2, 0, 2*Math.PI);
this.ctx.strokeStyle = 'pink';
this.ctx.stroke();
})
// 1s内粒子从矩形转成文字
this.timeout1 = setTimeout(()=>{
this.timer = setInterval(()=>{
this.ctx.clearRect(0, 0, this.width, this.height);
particleDataArr.map((item, index)=>{
if (index % 10 === 0) {
let {x, y, moveX, moveY, xStep, yStep, startX, startY} = item;
this.ctx.beginPath();
this.ctx.arc(startX + moveX, startY + moveY, 2, 0, 2*Math.PI);
this.ctx.strokeStyle = 'pink';
this.ctx.stroke();
item.moveX = moveX + xStep;
item.moveY = moveY + yStep;
}
});
}, 100);
this.timeout1 = setTimeout(()=>{
clearInterval(this.timer);
clearTimeout(this.timeout1);
this.timer = null;
this.timeout1 = null;
}, 1000);
},100)
this.timeout2 = setTimeout(()=>{
this.timer = setInterval(()=>{
this.ctx.clearRect(0, 0, this.width, this.height);
particleDataArr.map((item, index)=>{
if (index % 10 === 0) {
let {x, y, flutteMoveX, flutteMoveY, xStep, yStep} = item;
if(flutteMoveX === 0 && flutteMoveY === 0) flutteMoveX = Math.floor(Math.random() * 11 - 5), flutteMoveY = Math.floor(Math.random() * 11 - 5);
if(flutteMoveX >= -1 && flutteMoveX <= 1){
}else {
if(flutteMoveX >= 1) xStep = -1;
if(flutteMoveX <= -1) xStep = 1;
}
if(flutteMoveY >= -1 && flutteMoveY <= 1){
}else {
if(flutteMoveY >= 1) yStep = -1;
if(flutteMoveY <= -1) yStep = 1;
}
this.ctx.beginPath();
this.ctx.arc(x + flutteMoveX, y + flutteMoveY, 2, 0, 2*Math.PI);
this.ctx.strokeStyle = 'pink';
this.ctx.stroke();
item.flutteMoveX = flutteMoveX + xStep;
item.flutteMoveY = flutteMoveY + yStep;
item.xStep = xStep;
item.yStep = yStep;
}
});
}, 100);
}, 1350);
}
}
// 绘制飘动的粒子
drawParticleFlutter(x, y){
let moveX = 0, moveY = 0;
setInterval
}
// 文本框绑定键盘事件
textEvent (evt) {
if(evt.keyCode === 13){
clearInterval(this.timer);
this.timer = null;
this.init();
}else{
this.textValue = evt.target.value;
}
}
textBindEvent (){
this.textNode.addEventListener('keyup', this.textEvent.bind(this), false);
}
// 提交按钮绑定鼠标事件
submiteBtnEvent(evt){
this.textNode.removeEventListener('keydown', this.textEvent.bind(this), false);
this.submiteBtn.removeEventListener('click', this.submiteBtnEvent.bind(this), false);
this.init();
}
submitBtnBindEvent (){
this.submiteBtn.addEventListener('click', (evt)=>{
clearInterval(this.timer);
clearTimeout(this.timeout1);
clearTimeout(this.timeout2);
this.timeout1 = null;
this.timeout2 = null;
this.timer = null;
this.init();
}, false);
}
}
let particleEffects = new ParticleEffects();
particleEffects.init();
</script>
</body>
</html>