javascript - 基于下拉列表在 Canvas 上进行缓动的动画圆圈

标签 javascript jquery html canvas html5-canvas

所以我制作了这个 fiddle ,目的是通过在下拉列表中选择相应的区域来指出人体的区域。

这是我目前所做的:

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>

关于javascript - 基于下拉列表在 Canvas 上进行缓动的动画圆圈,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50513567/

相关文章:

javascript - 将鼠标悬停在其父 div 上时,如何更改链接为对象的 SVG 的属性?

html - 如何仅使用 CSS 样式表替换图像

c# - 使用 C# 从 HTML 表格中抓取文本

javascript - 如何将一个div加载到另一个div中

jquery - 更改连续动画

javascript - CreateJS - 更新子级与父级的坐标

javascript - 带有 Socket.IO 1.0 的 NodeJS - 堆外的内存泄漏

javascript - Chrome RGBA 问题

jquery - 如何禁用 .removeClass()

javascript - 如何计算 JQuery 或 Javascript 中一对标签内的字符数(不包括空格)?