최근에 작성자의 요구 사항은 다음과 같습니다. 사용자는 링 주위에 텍스트를 추가할 수 있습니다. 링 위에 마우스를 올리면 삼각형이 방사되어 텍스트가 표시됩니다. 먼저 애니메이션 효과를 살펴보겠습니다.
위 그림과 같이 해당 작은 파란색 점에 마우스를 놓으면 삼각형 모양의 광선이 방출되어야 하며 해당 텍스트가 삼각형 외부에 표시되고 작은 파란색 점이 작은 흰색 점이 됩니다.
사용자가 위에 콘텐츠를 입력하면 아래 링 주위에 콘텐츠가 추가됩니다. 위의 그림과 같습니다.
작성자의 원래 아이디어는 아래 그림의 동적 보조 메뉴처럼 CSS를 사용하여 구현하는 것이었습니다.
그러나 링 가장자리에 있는 내용이 가변적이고 링 주위에 배치되어야 한다는 점을 고려하면 CSS를 구현하기 어려울 수 있습니다. 그래서 와, 저자는 그것을 달성하기 위해 캔버스를 사용하기로 결정했습니다. (저자는 캔버스를 최근에야 배웠습니다. 잘못된 부분이 있으면 수정을 받아들입니다.)
구현 프로세스:첫 번째:
코드의 html 부분은 다음과 같습니다.
<canvas style=margin-left: 50px;padding-top: 20px; display:block; 현재 버전의 브라우저는 캔버스를 지원하지 않습니다.</canvas>
구체적인 구현 단계는 다음과 같습니다.
1. 큰 원을 그립니다.
캔버스 메소드를 사용하십시오: context.arc(x, y, radius, startAngle, endAngle [, 시계 반대 방향]);
x, y: 원 중심 좌표, radius: 원 중심 반경, startAngle: 시작 라디안 그리기, endAngle: 끝 라디안 그리기, [, 반시계 방향]: 옵션 매개변수, 호를 시계 방향으로 그릴지 반시계 방향으로 그릴지 여부.
작가는 그리기의 편의를 위해 캔버스의 원점을 이전 왼쪽 상단에서 캔버스 중앙으로 이동시켰습니다.
저자가 계산한 링의 반경은 r-80입니다.
canvas.width = 500canvas.height = 500//캔버스 중심의 반경을 계산합니다 let r = 500 / 2//인터페이스가 초기화되면 캔버스 원점을 캔버스 중심으로 이동합니다. ctx.translate(r ,r) //브러시를 둥글게 이동합니다.
구체적인 코드는 다음과 같습니다.
//캔버스 초기화 let canvas = document.getElementById('canvas')let ctx= canvas.getContext('2d')let ratio = getPixelRato(ctx)canvas.width = 500canvas.height = 500//중심 반경 계산 of the canvas let r = 500 / 2// 인터페이스가 초기화되면 캔버스의 원점을 캔버스 중앙으로 이동합니다 ctx.translate(r,r) //브러시를 원으로 이동 ctx.lineWidth = 3; //브러시 선 너비 설정 ctx.beginPath() //브러쉬 시작//원 가장자리의 그라데이션 가장자리 색상 그리기 var arcColor = ctx.createLinearGradient(-170, -170, 0, 170)arcColor.addColorStop(0, '#8ec1ff')arcColor.addColorStop(0.2, '#83beff')arcColor.addColorStop(0.5, '#75b1ff')arcColor.addColorStop(0.7,'#5998ff')arcColor.addColorStop(1, '#2065ff')ctx .스트로크스타일= arcColor;//브러시 색상 설정 ctx.arc(0,0,r - 80,0,2*Math.PI,false) //원 그리기, 좌표 0,0, 반경 250-80, 완전한 원 (0 -360도), false는 시계 방향을 의미합니다. ctx.closePath()ctx.Stroke() //그리기추첨 결과는 다음과 같습니다
2. 링 중앙에 배경 이미지를 그린다. (현재 캔버스의 원점은 캔버스의 중심이다)
drawImage(이미지, dx, dy, dWidth, dHeight)
image: <img> 이미지, SVG 이미지, 캔버스 요소 자체 등과 같은 캔버스 이미지 리소스입니다.
dx, dy: 캔버스 캔버스에 그림을 배치할 영역을 계획합니다. dx는 이 영역의 왼쪽 상단 모서리에 대한 가로 및 세로 좌표입니다.
dWidth, dHeight: 캔버스 캔버스에 그림을 배치할 영역과 이 영역의 너비 및 높이를 계획합니다.
다음 좌표는 작성자가 계산한 것입니다.
let image = new Image()image.src = 'image/quan.png'image.onload = () => { // 원점을 중앙으로 이동 ctx.drawImage(image,-140,-140,280,280)}도면 결과는 다음과 같습니다.
3. 링에 텍스트와 작은 점을 그립니다. (현재 캔버스의 원점은 캔버스의 중심입니다.)
텍스트 및 작은 점의 그리기 대상:
3.1 큰 링에 작은 점이 고르게 표시됩니다.
3.2 작은 점들 밖으로 텍스트가 약간 흩어지는 현상
해결책:1. 저자는 배열을 사용하여 현재 단어를 저장합니다.
let textArr = ['넓은 바다와 하늘', '기술력', '튼튼한 자금', '유지 관리', '평안하고 만족스럽게 살고 일하다', '꽃 감상', '마무리 마무리',' 찌끼를 없애라', '바람에 맞서라', '경력개발']
2. 작은 점의 개수와 단어의 개수가 동일하기 때문에 둘 다의 개수는 위의 textArr 배열의 길이가 됩니다.
3. 완전한 원의 라디안은 2π입니다. 작은 점들이 고리를 균등하게 나누도록 하기 위해 저자는 먼저 각 작은 점이 위치한 지점의 라디안을 계산합니다.
for(let i = 0;i<lengths;i++){ // 라디안 계산 let rad = 2*Math.PI/lengths*i}4. 삼각함수에 따라 현재 캔버스 위의 작은 점의 좌표(x, y)를 계산할 수 있습니다. (현재 캔버스의 원점은 캔버스의 중심입니다.)
그 중 라디안, 작은 점, 고리, 고리 반경, 캔버스 원점 간의 관계를 작가는 그림으로 그려 설명했다.
텍스트 좌표를 계산합니다.
// 작은 원의 중심 좌표를 계산합니다. let x = (r - 40)*Math.cos(rad)let y = (r - 40)*Math.sin(rad)
작은 점의 좌표 계산: 작은 점의 중심이 링 위에 있어야 하므로 계산된 가로 및 세로 좌표는 다음과 같습니다.
// 텍스트의 좌표를 계산합니다. let x = (r - 80)*Math.cos(rad) let y = (r - 80)*Math.sin(rad)
구체적인 코드는 다음과 같습니다.
// 텍스트 그리기 ctx.font = '13px Arial'ctx.textAlign = 'center'ctx.textBaseline = 'middle'ctx.fillStyle=#000000let lengths = textArr.lengthtextArr.forEach(function(text,i){ //라디안 let rad = 2*Math.PI/lengths*i // 작은 원의 중심 좌표를 계산합니다. let x = (r - 40)*Math.cos(rad) let y = (r - 40)*Math.sin(rad) ctx.fillText(text,x+0.5,y+0.5)});// 작은 점을 그립니다. for(let i = 0;i<lengths;i++){ // // let rad = 2*Math.PI/lengths*i let x = (r - 80)*Math.cos(rad) let y = (r - 80)*Math.sin(rad)// // 가장자리에 작은 회색 반투명 점을 그립니다. ctx.beginPath() ctx.fillStyle = 'rgba(226,235,250, 0.8)' ctx.arc(x,y,8,0,2*Math.PI,false) ctx.closePath() ctx.fill() // 작은 파란색 점 그리기 ctx.beginPath() ctx.fillStyle = '#208fe5' ctx.arc(x,y,4,0,2*Math.PI,false) ctx.closePath( ) ctx .채우다() }도면 결과는 다음과 같습니다.
4. 각 작은 점 바깥쪽에 삼각형을 그립니다. (현재 캔버스의 원점은 캔버스의 중심입니다)
4.1 삼각형 모양을 그리려고 하기 때문에 삼각형을 그리는 아이디어는 현재 작은 점의 중심을 시작점으로 양쪽에 선을 그린 후 ctx.fill()을 사용하여 모양을 닫고 그라데이션 컬러로 내부를 채워주세요.
삼각형을 그립니다. 좌표는 스스로 계산됩니다. 저자는 가로축에 35, 세로축에 70을 더하고 뺍니다. (원하는대로 하하하)
//브러시 시작 ctx.beginPath() ctx.moveTo(x,y) ctx.lineTo(x-35,y+70) ctx.lineTo(x+35,y+70) ctx.closePath()
삼각형 아래에 텍스트를 그립니다. (이전 텍스트와 구별하기 위해 여기에서는 텍스트에 빨간색을 사용했습니다.)
ctx.fillStyle= '#e3211c' ctx.fillText(textArr[i],x,y+75)
구체적인 코드는 다음과 같습니다.
for(let i = 0;i<lengths;i++){ // // let rad = 2*Math.PI/lengths*i let x = (r - 80)*Math.cos(rad) let y = (r - 80)*Math.sin(rad) // // s 삼각형 그리기 // // ctx.rotate( -Math.PI / 4) ctx.beginPath() //브러시 시작 ctx.moveTo(x,y) ctx.lineTo(x-35,y+70) ctx.lineTo(x+35,y+70) ctx.closePath() // // 색상 그라데이션 설정- - ->중앙에서 양쪽으로 색상 추가 var sColor = ctx.createLinearGradient (x,y,x+18,y+50) sColor.addColorStop(0,'rgba(106,128,243,0.5)') sColor.addColorStop(0.6,'rgba(83,183,243,0.5)') sColor.addColorStop(0.7,'rgba(129,200,224,0.5)') sColor.addColorStop(0.8,'rgba(130,219,251,0.5)') sColor.addColorStop(1,'rgba(195,228,223,0.5)') ctx.fillStyle= sColor ctx.fill() ctx.fillStyle= '#e3211c' ctx.fillText(textArr[i],x,y+75)}도면 결과는 다음과 같습니다.
4.2 요구사항은 각 삼각형의 방향이 바깥쪽으로 퍼지는 것인데, 이제 삼각형의 방향이 아래로 향하게 되므로 이제 캔버스 회전 방법을 사용해야 합니다.
ctx.save() ctx.translate(x,y) // 회전 각도는 각 작은 점을 중심으로 합니다. ctx.rotate( rad - Math.PI/2 ) // 작은 점 ctx.translate(- x, - y) . 삼각형 및 텍스트를 그리는 코드를 생략합니다.
작은 점의 중심을 회전 시작점으로 삼으면 삼각형의 회전 호는 현재 작은 점의 호에서 π/2를 뺀 값이 되어야 한다는 계산을 통해 알 수 있습니다. 왜냐하면 회전의 시작 위치는 항상 x 좌표축의 양의 방향에서 시작합니다. 즉, 0 라디안에서 시작하지만 이제 삼각형은 모두 π/2 라디안이므로 다음과 같습니다.
회전의 라디안 = 작은 점의 라디안 - π/2
회전할 때 Canvas 상태 저장 메서드 save()를 사용하는 것을 잊지 마세요.
Restore()는 저장된 Canvas 상태를 스택 상단에서 차례로 팝합니다. 저장된 Canvas 상태가 없으면 이 메서드를 실행해도 아무런 변화가 없습니다.
마지막에 반드시 Restore() 메소드를 사용하는 것을 잊지 마세요. 이 시점에서 저자는 후회의 눈물을 흘렸습니다. . .
특정 코드:
for(let i = 0;i<lengths;i++){ // // let rad = 2*Math.PI/lengths*i let x = (r - 80)*Math.cos(rad) let y = (r - 80)*Math.sin(rad) // s 삼각형을 그립니다. ctx.save() // 작은 점이 시작 부분에 있으므로 회전 각도는 각 작은 점의 중심에 있습니다. ctx.translate(x,y) ctx.rotate( rad - Math.PI/2 ) ctx.translate(-x, -y) // 브러시 시작 ctx.beginPath() ctx.moveTo(x,y) ctx.lineTo(x-35,y+ 70 ) ctx.lineTo(x+35,y+70) ctx.closePath() //색상 그라데이션 설정--->중앙에서 양쪽으로 색상 변수 추가 sColor = ctx.createLinearGradient (x,y,x+18,y+50) sColor.addColorStop(0,'rgba(106,128,243,0.5)') sColor.addColorStop(0.6,'rgba(83,183,243,0.5)') sColor.addColorStop(0.7,'rgba(129,200,224,0.5)') sColor.addColorStop(0.8,'rgba(130,219,251,0.5)') sColor.addColorStop(1,'rgba(195,228,223,0.5)') ctx.fillStyle= sColor ctx.fill() ctx.fillStyle= '#e3211c' ctx.fillText(textArr[i],x,y+75) ctx.restore()}결과를 플롯합니다.
자세히 살펴보세요. 무엇? ? ? 회전 문제로 인해 일부 텍스트가 거꾸로 되어 있는 것을 관찰한 결과, 라디안이 π보다 크면 텍스트가 거꾸로 되는 것으로 나타났습니다.
이제 if 판단의 물결을 쓸 시간입니다. . . .
텍스트를 회전하는 방법:
functionrotateContext(ctx, x, y, Degree) { // 텍스트 회전 ctx.translate(x, y) // ctx.rotate(degree * Math.PI / 180) ctx.rotate(degree) ctx.translate(-x , -y) }라디안이 π보다 큰 작은 점을 결정합니다.
if (rad > Math.PI) { // 텍스트는 삼각형의 가장자리에 표시되어야 하므로 텍스트는 회전 후에도 항상 삼각형의 가장자리에 유지될 수 있도록 // 삼각형과 함께 회전해야 합니다. , 라디안이 π보다 클 때 텍스트가 나타납니다. 문제를 반대로 하여 텍스트를 회전합니다. ctx.save() ctx.beginPath() // 텍스트를 회전합니다.rotateContext(ctx, x, y+75, Math.PI) ctx.font = '13px Arial' ctx.textAlign = 'center' ctx.fillStyle = #ff2238 ctx.fillText(textArr[i], x, y+ 75) ctx.restore()} else { ctx.fillStyle = '#ff2238' ctx.fillText(textArr[i ], x, y + 75)}도면 결과는 다음과 같습니다.
승리를 기대하며 우리는 거의 성공했습니다. 적어도 우리는 혁명이 아직 성공하지 못했고 동지들은 여전히 열심히 노력해야 합니다! !
5. 다음은 작은 점 위에 마우스를 올리면 가장자리에 삼각형과 삼각형 가장자리에 텍스트가 표시되지만 원 가장자리에 텍스트가 표시되지 않는 구현입니다.
아이디어:1. 마우스 입력 이벤트를 캔버스에 바인딩
2. 캔버스에서 현재 마우스 위치의 좌표가 작은 점 근처의 좌표와 같은지 확인합니다. 그렇다면 작은 점에 해당하는 삼각형을 표시합니다.
5.1 mousemove 이벤트를 캔버스에 바인딩합니다. 마우스가 이벤트 위에 있습니다.
canvas.addEventListener('mousemove',clickEvent)5.2 캔버스에서 마우스의 현재 좌표 계산
계산 방법은 DOM에서 현재 마우스 좌표를 사용하여 캔버스의 왼쪽 또는 상단으로부터의 거리를 빼서 캔버스의 거리를 계산하는 것입니다.
아래 그림의 drawOne 방식은 드로잉 방식으로, 이에 대해서는 본 글의 뒷부분에서 다루도록 하겠습니다.
function clickEvent() { // 마우스 위치의 좌표 let x = event.clientX - canvas.getBoundingClientRect().left let y = event.clientY - canvas.getBoundingClientRect().top drawOne(x,y)}5.3, 위에서 계산한 캔버스 위의 마우스 좌표는 캔버스의 왼쪽 상단을 원점으로 계산하는데, 현재 캔버스의 원점은 이미 캔버스의 중앙(250,250)으로 이동했기 때문에 사용하면 클릭이 작은 점인지 확인하기 위해 현재 캔버스의 작은 점 좌표와 비교하려면 가로 좌표와 세로 좌표 모두에서 250을 빼야합니다. 판단을 할 때 y 방향의 차이가 왜 발생하는지 알 수 없습니다. 저자의 값은 250이 아닌 260입니다. 따라서 저자는 y 방향으로 260을 뺍니다.
코드는 다음과 같습니다:
그 중 Cx, Cy는 캔버스 위의 마우스 좌표(캔버스의 왼쪽 상단이 원점), x, y는 현재 작은 점의 좌표,
저자가 작은 점 중심 부근 15px의 위치를 직접 계산했더니 삼각형이 모두 표시되고 작은 점이 하얗게 변했다.
가장 중요한 것은 다시 그릴 때마다 이전 캔버스를 지워야 한다는 것입니다. 캔버스를 지우려면clearRect 메서드를 사용하는 것을 기억하세요.
let XX = Cx - 250let YY = Cy- 260let leftX = x - 15 let rightX = x + 15let topY = y - 15let BottomY = y + 15if (XX >= leftX && XX <= rightX && YY <= BottomY && YY > = topY ) {//클릭됩니다. . . . . . //가운데 그리기 코드를 작성합니다.}코드 뒤에는 링크가 옵니다:
6. 인터페이스에서 입력을 정의하고 변경 이벤트를 입력에 바인딩합니다.
구현: 입력 값이 변경될 때마다 인터페이스가 다시 그려집니다.
HTML 코드:
<input type=text id=inpt style=margin-left: 100px;margin-top: 50px placeholder=입력해 주세요...>
JS 코드:
let inpt = document.getElementById('inpt') inpt.addEventListener('change', function () { if (inpt.value !== '') { textArr.push(inpt.value) drawAll(2) //This 방법은 그리기 방법이며 소스 코드는 나중에 기사에서 제공됩니다}})7. 인터페이스를 클릭하고 인터페이스를 다시 그릴 때마다 깜박이는 상황이 발생합니다.
아래와 같이:
슬라이드할 때마다 마우스 좌표가 바뀌기 때문에 링 주위의 내용을 지우고 다시 그려야 합니다. 따라서 동적 효과를 얻으려면 캔버스를 지워야 합니다.
ClearRect()는 캔버스 애니메이션 그리기에 매우 일반적으로 사용됩니다. 캔버스 내용을 지속적으로 지운 다음 그려서 애니메이션 효과를 만듭니다.
clearRect()는 Canvas 요소의 캔버스에서 직사각형 영역을 투명하게 만들 수 있습니다.
context.clearRect(x, y, 너비, 높이);
x, y: 직사각형의 왼쪽 상단 모서리의 x, y 좌표입니다.
width, height: 지워진 직사각형 영역의 너비와 높이입니다.
clearRect()는 캔버스의 직사각형 영역만 지울 수 있기 때문에 지울 때마다 가운데 배경 이미지도 같이 지웁니다.
따라서 배경 이미지는 매번 다시 불러와야 하고, 이미지를 불러오는 데 일정 시간이 걸리기 때문에 나타날 때마다 깜박이게 됩니다.
해결책:drawImage(이미지, dx, dy, dWidth, dHeight)
매개변수 이미지: <img> 이미지, SVG 이미지, 캔버스 요소 자체 등과 같은 캔버스 이미지 리소스입니다.
그런 다음 다른 캔버스를 사용하여 이미지를 캐시할 수 있습니다.
추가 캔버스를 사용하여 배경 이미지를 그리지만 인터페이스에 표시되지 않는 캔버스의 경우: display:none을 사용하여 캔버스를 지우고 캐시된 캔버스 객체를 캔버스 중앙에 직접 렌더링하여 표시합니다. 즉, 이미지를 한 번 로드하는 데 시간이 많이 걸립니다.
HTML 코드:
<canvas width=280 height=280 style=margin-left: 50px;padding-top: 20px; id=canvas2> </canvas>
JS 코드:
//캐싱을 사용하여 다시 그린 이미지의 깜박임 문제 해결 var tempCanvas = document.getElementById('canvas2')const tempCtx = tempCanvas.getContext('2d')tempCanvas.width = 280let image = new Image( )image.src = 'image/quan.png'image.onload = () => { // 원점이 중앙으로 이동합니다. tempCtx.drawImage(image,0,0,280,280)}캔버스를 비운 후 그림을 다시 그릴 때 캐시된 canvas:tempCanvas를 직접 그립니다.
// 캐시된 캔버스를 인터페이스에 직접 그립니다. (중간 타이어 인터페이스는 캐시됩니다.) ctx.drawImage(tempCanvas,-140,-140)
좋아요, 성공했습니다. 결과 사진은 다음과 같습니다.
소스코드 주소는 다음과 같습니다.
https://github.com/Linefate/Dynamic- effect-of-canvas-ring.git
요약위 내용은 html5 캔버스를 사용하여 링 애니메이션을 그리는 방법에 대한 편집자의 소개입니다. 질문이 있는 경우 메시지를 남겨주시면 편집자가 제 시간에 답변해 드리겠습니다. 또한 VeVb 무술 웹사이트를 지원해 주신 모든 분들께 감사드립니다!