基于下拉列表的画布上带有缓动的动画圆圈



所以我做了这个小提琴,目标是通过在下拉列表中选择它们各自的区域来指出人体的区域。

目前,这是我所做的:

let coords = {
maleFirst: {
hands: {
left: {
x: 100,
y: 360
},
right: {
x: 280,
y: 360
}
},
foot: {
left: {
x: 180,
y: 590
},
right:{
x: 210,
y: 590
}
}
},
maleSecond: {
hands: {
left: {
x: 365,
y: 360
},
right: {
x: 545,
y: 360
}
},
foot: {
left: {
x: 430,
y: 590
},
right:{
x: 480,
y: 590
}
}
}
}
let draw = (option) => {
let canvas = document.getElementById('canvas');

if (canvas.getContext) {
let ctx = canvas.getContext('2d');

ctx.clearRect(0, 0, canvas.width, canvas.height);

if (option === 'hands') {

coordsDraw(ctx, coords.maleFirst.hands.left.x, coords.maleFirst.hands.left.y);
coordsDraw(ctx, coords.maleFirst.hands.right.x, coords.maleFirst.hands.right.y);
coordsDraw(ctx, coords.maleSecond.hands.left.x, coords.maleSecond.hands.left.y);
coordsDraw(ctx, coords.maleSecond.hands.right.x, coords.maleSecond.hands.right.y);
}
if (option === 'foot') {
coordsDraw(ctx, coords.maleFirst.foot.left.x, coords.maleFirst.foot.left.y);
coordsDraw(ctx, coords.maleFirst.foot.right.x, coords.maleFirst.foot.right.y);
coordsDraw(ctx, coords.maleSecond.foot.left.x, coords.maleSecond.foot.left.y);
coordsDraw(ctx, coords.maleSecond.foot.right.x, coords.maleSecond.foot.right.y);
}

}
}

let coordsDraw = (ctx, x, y) => {

ctx.beginPath();
ctx.fillStyle = '#01567f'; // color of fill
ctx.arc(x, y, 5, 0, 2 * Math.PI);
ctx.fill();
ctx.closePath();
}
document.getElementById('options').addEventListener('change', function ()  {
draw(this.value)
});

#canvas {
background-image:url('http://www.coloringsky.com/wp-content/uploads/2015/11/How-to-Draw-Human-Body-Coloring-Pages.jpg');
background-repeat:no-repeat;
background-size:contain;
background-position:center;
width: 100%;
}
<select name="options" id="options">
<option value="#">Select option</option>
<option value="hands">hands</option>
<option value="foot">foot</option>
</select>
<br>
<br>
<canvas id="canvas" width="650" height="650"></canvas>

我的目标是有一个更"突出"的指针,在这些行中:

// canvas related variables
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var $canvas = $("#canvas");
var canvasOffset = $canvas.offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var scrollX = $canvas.scrollLeft();
var scrollY = $canvas.scrollTop();
// set the context styles
ctx.lineWidth = 1;
ctx.strokeStyle = "gold";
ctx.fillStyle = "#888";
// variables used to draw & animate the ring
var PI2 = Math.PI * 2;
var ringX, ringY, ringRadius, ingCounter, ringCounterVelocity;
var cancelAnimationId;
// fill the canvas with a background color
ctx.fillRect(0, 0, canvas.width, canvas.height);
// tell handleMouseDown to handle all mousedown events
$("#canvas").mousedown(function (e) {
handleMouseDown(e);
});
// set the ring variables and start the animation
function ring(x, y) {
ringX = x;
ringY = y;
ringRadius = 0;
ringCounter = 0;
ringCounterVelocity = 4;
cancelAnimationId = requestAnimationFrame(animate);
}
// the animation loop
function animate() {
// return if the animation is complete
if (ringCounter > 200) {
ringCounter = 0;
}
// otherwise request another animation loop
cancelAnimationId = requestAnimationFrame(animate);
// ringCounter<100 means the ring is expanding
// ringCounter>=100 means the ring is shrinking
if (ringCounter < 100) {
// expand the ring using easeInCubic easing
ringRadius = easeInCubic(ringCounter, 0, 15, 100);
} else {
// shrink the ring using easeOutCubic easing
ringRadius = easeOutCubic(ringCounter - 100, 15, -15, 100);
}
// draw the ring at the radius set using the easing functions
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(ringX, ringY, ringRadius, 0, PI2);
ctx.closePath();
ctx.stroke();
// increment the ringCounter for the next loop
ringCounter += ringCounterVelocity;
}
//  Robert Penner's easing functions
//
//  https://github.com/danro/jquery-easing/blob/master/jquery.easing.js
//
//  now=elapsed time,
//  startValue=value at start of easing,
//  deltaValue=amount the value will change during the easing,
//  duration=total time for easing
function easeInCubic(now, startValue, deltaValue, duration) {
return deltaValue * (now /= duration) * now * now + startValue;
}
function easeOutCubic(now, startValue, deltaValue, duration) {
return deltaValue * ((now = now / duration - 1) * now * now + 1) + startValue;
}
// handle mousedown events
function handleMouseDown(e) {
// tell the browser we'll handle this event
e.preventDefault();
e.stopPropagation();
// calc the mouse position
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// animate a ring at the mouse position
cancelAnimationFrame(cancelAnimationId);
ring(mouseX, mouseY);
}
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h4>Click in the canvas to draw animated circle with easings.</h4>
<canvas id="canvas" width=300 height=300></canvas>

我在使动画适应我正在寻找的内容时遇到了麻烦,因为我最终遇到了以下错误:

let coords = {
maleFirst: {
hands: {
left: {
x: 100,
y: 360
},
right: {
x: 280,
y: 360
}
},
foot: {
left: {
x: 180,
y: 590
},
right:{
x: 210,
y: 590
}
}
},
maleSecond: {
hands: {
left: {
x: 365,
y: 360
},
right: {
x: 545,
y: 360
}
},
foot: {
left: {
x: 430,
y: 590
},
right:{
x: 480,
y: 590
}
}
}
}
let draw = (option) => {
let canvas = document.getElementById('canvas');

if (canvas.getContext) {
let ctx = canvas.getContext('2d');

ctx.clearRect(0, 0, canvas.width, canvas.height);

if (option === 'hands') {

coordsDraw(ctx, coords.maleFirst.hands.left.x, coords.maleFirst.hands.left.y);
coordsDraw(ctx, coords.maleFirst.hands.right.x, coords.maleFirst.hands.right.y);
coordsDraw(ctx, coords.maleSecond.hands.left.x, coords.maleSecond.hands.left.y);
coordsDraw(ctx, coords.maleSecond.hands.right.x, coords.maleSecond.hands.right.y);
}
if (option === 'foot') {
coordsDraw(ctx, coords.maleFirst.foot.left.x, coords.maleFirst.foot.left.y);
coordsDraw(ctx, coords.maleFirst.foot.right.x, coords.maleFirst.foot.right.y);
coordsDraw(ctx, coords.maleSecond.foot.left.x, coords.maleSecond.foot.left.y);
coordsDraw(ctx, coords.maleSecond.foot.right.x, coords.maleSecond.foot.right.y);
}

}
}
var ringRadius = 0, ringCounter = 0, ringCounterVelocity = 4;
let coordsDraw = (ctx, x, y) => {
if (ringCounter > 200) {
ringCounter = 0;
}
// otherwise request another animation loop
cancelAnimationId = requestAnimationFrame(coordsDraw(ctx, x, y));
// ringCounter<100 means the ring is expanding
// ringCounter>=100 means the ring is shrinking
if (ringCounter < 100) {
// expand the ring using easeInCubic easing
ringRadius = easeInCubic(ringCounter, 0, 15, 100);
} else {
// shrink the ring using easeOutCubic easing
ringRadius = easeOutCubic(ringCounter - 100, 15, -15, 100);
}
ctx.beginPath();
ctx.fillStyle = '#01567f'; // color of fill
ctx.arc(x, y, ringRadius, 0, 2 * Math.PI);
ctx.fill();
ctx.closePath();
ringCounter += ringCounterVelocity;
}
function easeInCubic(now, startValue, deltaValue, duration) {
return deltaValue * (now /= duration) * now * now + startValue;
}
function easeOutCubic(now, startValue, deltaValue, duration) {
return deltaValue * ((now = now / duration - 1) * now * now + 1) + startValue;
}
document.getElementById('options').addEventListener('change', function ()  {
draw(this.value)
});

#canvas {
background-image:url('http://www.coloringsky.com/wp-content/uploads/2015/11/How-to-Draw-Human-Body-Coloring-Pages.jpg');
background-repeat:no-repeat;
background-size:contain;
background-position:center;
width: 100%;
}
<select name="options" id="options">
<option value="#">Select option</option>
<option value="hands">hands</option>
<option value="foot">foot</option>
</select>
<br>
<br>
<canvas id="canvas" width="650" height="650"></canvas>

Uncaught RangeError: Maximum call stack size exceeded
at coordsDraw (select.js:299)

任何帮助将不胜感激

我会这样做(此示例没有动画环,但我显示了您将放置该代码的位置。

<!doctype html>

<style>
canvas {
background-image:url('http://www.coloringsky.com/wp-content/uploads/2015/11/How-to-Draw-Human-Body-Coloring-Pages.jpg');
background-repeat:no-repeat;
background-size:contain;
background-position:center;
width: 100%;
}
</style>

<select name="options" id="options">
<option value="#">Select option</option>
<option value="hands">hands</option>
<option value="feet">feet</option>
</select>
<br>
<br>
<canvas width="650" height="650">
<script>
var canvas = document.querySelector("canvas");
var context = canvas.getContext("2d");
var option = document.querySelector("select");

var rings = [];
var ringOffsetH = 110;
var ringOffsetF = 155;
animationLoop();

//The ring constructor
function Ring(x,y,r,v)
{
this.x = x;
this.y = y;
this.radius = r;
this.visible = v;
this.draw = function()
{
context.beginPath();
context.arc(this.x,this.y,this.radius,0,Math.PI*2,false);
context.closePath();
context.stroke();
}
this.animate= function()
{
//animation easing code goes here
}
};
function animationLoop()
{
window.requestAnimationFrame(animationLoop,canvas);

//Loop through options tracking the currently selected one
for(var o=0; o<option.length; o++)
{
var selectedOption = option.selectedIndex;
switch(selectedOption)
{
case 1:
clearRings(rings);
for(var n=0; n<2; n++)
{
var ring = new Ring(165*n+ringOffsetH,350,10,true);//Here you could replace x,y with your coord getters instead of hardcoding as I have done
rings.push(ring);
}
break;
case 2:
clearRings(rings);
for(var n=0; n<2; n++)
{
var ring = new Ring(70*n+ringOffsetF,600,10,true);
rings.push(ring);
}
break;
default:
clearRings(rings);
console.log("nothing");
break;
}
}
//Loop through rings calling the rings animation function
//if visible
for(var r=0; r<rings.length; r++)
{
var ring = rings[r];
if(ring.visible)
{
ring.animate();
}
}

render();
};
function clearRings(array)
{
this.array = array;
array.length = 0;
}
function render()
{
context.clearRect(0,0,canvas.width,canvas.height);
//Loop through rings
if(rings.length !== 0)
{
for(var r=0; r<rings.length; r++)
{
//Assign the current ring to a temporary 
//ring reference
var ring = rings[r];
//Draw the ring
ring.draw();
}
}

};

</script>

更新

现在有了动画戒指">

<!doctype html>

<style>
canvas {
background-image:url('http://www.coloringsky.com/wp-content/uploads/2015/11/How-to-Draw-Human-Body-Coloring-Pages.jpg');
background-repeat:no-repeat;
background-size:contain;
background-position:center;
width: 100%;
}
</style>

<select name="options" id="options">
<option value="#">Select option</option>
<option value="hands">hands</option>
<option value="feet">feet</option>
</select>
<br>
<br>
<canvas width="650" height="650">
<script>
var canvas = document.querySelector("canvas");
var context = canvas.getContext("2d");
var option = document.querySelector("select");
const EASING = .08;
var rings = [];
var ringOffsetH = 110;
var ringOffsetF = 178;
const RADIUS = 10;
const MIN_RADIUS = 0;
var shrinkRing = false;
var growRing = false;

animationLoop();

//The ring constructor
function Ring(n,x,y,r,v,vl)
{
this.name = n;
this.x = x;
this.y = y;
this.radius = r;
this.visible = v;
this.velocity = vl;
this.draw = function()
{
context.beginPath();
context.arc(this.x,this.y,this.radius,0,Math.PI*2,false);
context.closePath();
context.stroke();
}
this.animate= function()
{

//animation easing code goes here
if((this.radius > MIN_RADIUS && !growRing) 
|| (this.radius >= RADIUS && growRing))
{
growRing = false;
shrinkRing = true;
this.radius -= this.velocity * EASING;
}
if((this.radius < RADIUS && !shrinkRing) 
|| (this.radius < MIN_RADIUS && shrinkRing))
{
shrinkRing = false;
growRing = true;
this.radius += this.velocity * EASING;
}
}
};
function animationLoop()
{
window.requestAnimationFrame(animationLoop,canvas);

//Loop through options tracking the currently selected one
for(var o=0; o<option.length; o++)
{
var selectedOption = option.selectedIndex;
switch(selectedOption)
{
case 1:
if(rings.length !== 0)
{
for(var r=0; r<rings.length; r++)
{
var tempRing = rings[r];
if(tempRing.name !== "hands")
{
clearRings(rings);
for(var n=0; n<2; n++)
{
var ring = new Ring("hands",(165*n)+ringOffsetH,350,
RADIUS,true,5);
rings.push(ring);
}
}
}
}
else
{
for(var n=0; n<2; n++)
{
var ring = new Ring("hands",(165*n)+ringOffsetH,350,
RADIUS,true,5);
rings.push(ring);
}
}
break;
case 2:
if(rings.length !== 0)
{
for(var r=0; r<rings.length; r++)
{
var tempRing = rings[r];
if(tempRing.name !== "feet")
{
clearRings(rings);
for(var n=0; n<2; n++)
{
var ring = new Ring("feet",(30*n)+ringOffsetF,600,
RADIUS,true,5);
rings.push(ring);
}
}
}
}
else
{
for(var n=0; n<2; n++)
{
var ring = new Ring("feet",(30*n)+ringOffsetH,600,
RADIUS,true,5);
rings.push(ring);
}
}
break;
default:
clearRings(rings);
console.log("nothing");
break;
}
}
//Loop through rings calling the rings animation function
//if visible
for(var r=0; r<rings.length; r++)
{
var ring = rings[r];
if(ring.visible)
{
ring.animate();
}
}

render();
};
function clearRings(array)
{
this.array = array;
array.length = 0;
}
function render()
{
context.clearRect(0,0,canvas.width,canvas.height);
//Loop through rings
if(rings.length !== 0)
{
for(var r=0; r<rings.length; r++)
{
//Assign the current ring to a temporary 
//ring reference
var ring = rings[r];
//Draw the ring
ring.draw();
}
}

};

</script>

<!doctype html>
<html>
<head>
	<meta charset = 'utf-8'>
	<style>
	
		canvas {
		
		background-image:url('http://www.coloringsky.com/wp-content/uploads/2015/11/How-to-Draw-Human-Body-Coloring-Pages.jpg');
		background-repeat:no-repeat;
		background-size:contain;
		background-position:center;
		width: 100%;
		
		}
	
	</style>
</head>
<body>
	<select name="options" id="options">
		<option value="#">Select option</option>
		<option value="hands">hands</option>
		<option value="feet">feet</option>
	</select>
	<br>
	<br>
	
	<canvas width="650" height="650">
	<script>
		var canvas = document.querySelector("canvas");
		var context = canvas.getContext("2d");
		
		var option = document.querySelector("select");
		const EASING = .08;
		
		var rings = [];
		var ringOffsetH = 110;
		var ringOffsetF = 178;
		const RADIUS = 10;
		const MIN_RADIUS = 0;
		var shrinkRing = false;
		var growRing = false;
		
		
		animationLoop();
		
		
		//The ring constructor
		function Ring(n,x,y,r,v,vl)
		{
			this.name = n;
			this.x = x;
			this.y = y;
			this.radius = r;
			this.visible = v;
			this.velocity = vl;
			
			this.draw = function()
			{
				context.beginPath();
				context.arc(this.x,this.y,this.radius,0,Math.PI*2,false);
				context.closePath();
				context.stroke();
				
			}
			
			this.animate= function()
			{
				
				
				//animation easing code goes here
				if((this.radius > MIN_RADIUS && !growRing) || (this.radius >= RADIUS && growRing))
				{
					growRing = false;
					shrinkRing = true;
					this.radius -= this.velocity * EASING;
				}
				if((this.radius < RADIUS && !shrinkRing) || (this.radius < MIN_RADIUS && shrinkRing))
				{
		
					shrinkRing = false;
					growRing = true;
					
					this.radius += this.velocity * EASING;
				}
				
			}
		};
		
		function animationLoop()
		{
			window.requestAnimationFrame(animationLoop,canvas);
			
			
			//Loop through options tracking the currently selected one
			for(var o=0; o<option.length; o++)
			{
				var selectedOption = option.selectedIndex;
			
				switch(selectedOption)
				{
					case 1:
						if(rings.length !== 0)
						{
							for(var r=0; r<rings.length; r++)
							{
								var tempRing = rings[r];
								
								if(tempRing.name !== "hands")
								{
									clearRings(rings);
									
									for(var n=0; n<2; n++)
									{
										var ring = new Ring("hands",(165*n)+ringOffsetH,350,RADIUS,true,5);
										rings.push(ring);
									}
								}
							
							}
						}
						else
						{
							for(var n=0; n<2; n++)
							{
								var ring = new Ring("hands",(165*n)+ringOffsetH,350,RADIUS,true,5);
								rings.push(ring);
							}
						}
					break;
					
					case 2:
						if(rings.length !== 0)
						{
							for(var r=0; r<rings.length; r++)
							{
								var tempRing = rings[r];
								
								if(tempRing.name !== "feet")
								{
									clearRings(rings);
									
									for(var n=0; n<2; n++)
									{
										var ring = new Ring("feet",(30*n)+ringOffsetF,600,RADIUS,true,5);
										rings.push(ring);
									}
								}
							
							}
						}
						else
						{
							for(var n=0; n<2; n++)
							{
								var ring = new Ring("feet",(30*n)+ringOffsetF,600,RADIUS,true,5);
								rings.push(ring);
							}
						}
					break;
					
					default:
					clearRings(rings);
					//console.log("nothing");
					break;
				}
			}
			
			//Loop through rings calling the rings animation function
			//if visible
			for(var r=0; r<rings.length; r++)
			{
				var ring = rings[r];
				
				if(ring.visible)
				{
					ring.animate();
				}
			}
			
			
			render();
		};
		
		function clearRings(array)
		{
			this.array = array;
			
			array.length = 0;
		}
		
		function render()
		{
			context.clearRect(0,0,canvas.width,canvas.height);
			
			//Loop through rings
			if(rings.length !== 0)
			{
				for(var r=0; r<rings.length; r++)
				{
					//Assign the current ring to a temporary 
					//ring reference
					var ring = rings[r];
					
					//Draw the ring
					ring.draw();
				}
			}
				
			
		};
	</script>
</body>
</html>

最新更新