2020년 첫 글입니다. 연초에 질문을 검토하고 답변하느라 바빠서 아무것도 쓸 시간이 없었습니다. , 내 프로젝트에 우연히 캔버스 사업이 있었는데 갑자기 UI 프런트엔드에 불이 붙었고, 함정과 생각을 적었습니다.
캔버스에 그림/텍스트를 그릴 때 캔버스의 너비와 높이를 375*667로 설정합니다. 그려진 그림이 매우 흐릿하고 해상도가 낮은 그림처럼 느껴지며 텍스트도 흐릿하게 보입니다. 겹치는 그림자가 있습니다.
참고: 물리적 픽셀은 휴대폰 화면에 표시되는 가장 작은 단위를 의미하고, 장치 독립 픽셀(논리 픽셀)은 컴퓨터 장치의 한 지점을 의미합니다. 픽셀.
이유: 프런트 엔드 개발에서는 인터페이스를 렌더링할 때 장치 독립적인 픽셀을 렌더링하는 데 사용되는 물리적 픽셀 수(보통 2개)를 결정하는 devicePixelRatio(设备像素比)
라는 속성을 알고 있습니다.
예를 들어 100*100픽셀 사진의 경우 레티나 화면에서는 사진의 한 픽셀을 렌더링하는 데 2픽셀이 사용되며 이는 사진을 두 배로 늘리는 것과 동일하므로 이 역시 흐릿해집니다. 레티나 화면에서 1px가 두꺼워지는 이유.
해결책: 캔버스 너비와 캔버스 높이를 2배로 늘리고, 스타일을 통해 캔버스 표시 너비와 높이를 2배로 줄입니다. times.
예:
<canvas width="320" height="180" style="width:160px;height:90px;"></canvas>
rpx는 미니 프로그램의 고유한 크기 단위로, iPhone6/iphonex에서 1rpx는 다른 px와 같습니다. 따라서 캔버스 디스플레이가 다른 휴대폰에서 일관되지 않을 가능성이 있습니다.
포스터를 그리기 전 우리가 받는 디자인 초안은 대개 iPhone6의 2x 이미지를 기반으로 합니다. 그리고 이전 문제에 대한 해결 방법을 통해 캔버스의 크기도 2배라는 것을 알고 있으므로 그림의 2배에 대한 디자인 시안을 직접 측정하여 캔버스를 직접 그릴 수 있으며 크기는 rpxtoPx에 주의해야 합니다. .
/** * * @param {*} rpx * @param {*} int //是否变成整数 factor => 0.5 //iphone6 pixelRatio => 2 像素比 */ toPx(rpx, int) { if (int) { return parseInt(rpx * this.factor * this.pixelRatio) } return rpx * this.factor * this.pixelRatio }
미니 프로그램에서는 this.ctx.measureText(text).width
가 제공됩니다. 텍스트 길이를 계산하지만 숫자
코드>를 모두 사용하면 API가 항상 0으로 계산하는 것을 볼 수 있습니다. 따라서 마지막으로 시뮬레이션된 MeasureText 메서드를 사용하여 텍스트 길이를 계산합니다. this.ctx.measureText(text).width
去计算文本的长度,但是如果你全数字
的话,你会发现该API永远都计算成0.所以,最后采用模拟measureText方法去计算文本长度。
measureText(text, fontSize = 10) { text = String(text) text = text.split('') let width = 0 text.forEach(function(item) { if (/[a-zA-Z]/.test(item)) { width += 7 } else if (/[0-9]/.test(item)) { width += 5.5 } else if (/\./.test(item)) { width += 2.7 } else if (/-/.test(item)) { width += 3.25 } else if (/[\u4e00-\u9fa5]/.test(item)) { // 中文匹配 width += 10 } else if (/\(|\)/.test(item)) { width += 3.73 } else if (/\s/.test(item)) { width += 2.5 } else if (/%/.test(item)) { width += 8 } else { width += 10 } }) return width * fontSize / 10 }
字体的如果过长,会超出canvas画布,造成绘制难看,这个时候我们就应该让超出的部分变成...
你可以设置一个width并且循环计算计算出文本的宽度,如果超出则利用substring截取后补充...
即可。
let fillText='' let width = 350 for (let i = 0; i <= text.length - 1; i++) { // 将文字转为数组,一行文字一个元素 fillText = fillText + text[i] // 判断截断的位置 if (this.measureText(fillText, this.toPx(fontSize, true)) >= width) { if (line === lineNum) { if (i !== text.length - 1) { fillText = fillText.substring(0, fillText.length - 1) + '...' } } if (line <= lineNum) { textArr.push(fillText) } fillText = '' line++ } else { if (line <= lineNum) { if (i === text.length - 1) { textArr.push(fillText) } } } }
文字剧中展示计算公式:
居中在canvas中可以用(canvas的宽度-文字宽度)/2 + x (x为字体的x轴的推移)
let w = this.measureText(text, this.toPx(fontSize, true)) this.ctx.fillText(text, this.toPx((this.canvas.width - w) / 2 + x), this.toPx(y + (lineHeight || fontSize) * index))
关于在小程序里使用网络图片,比如cdn上的图片,是需要down到微信本地进行 LRU 管理,让后续绘制同样图片时,节省下载时间。所以首先需要你在微信小程序的后台配置downloadFile合法域名,其次你可以在canvas绘制之前,最好提前去down图片,等待图片下载好了,再开始绘制,以避免一些绘制失败的问题。
先把 base64 转成 Uint8ClampedArray
格式。然后再通过 wx.canvasPutImageData(OBJECT, this)
this.ctx.draw(false, () => { setTimeout(() => { Taro.canvasToTempFilePath({ canvasId: 'canvasid', success: async(res) => { this.props.onSavePoster(res.tempFilePath)//回调事件 // 清空画布 this.ctx.clearRect(0, 0, canvas_width, canvas_height) }, fail: (err) => { console.log(err) } }, this.$scope) }, time) })
...
로 설정해야 합니다. 너비와 루프 계산을 설정할 수 있습니다. 텍스트를 계산하려면 너비를 초과하는 경우 하위 문자열을 사용하여 ...
를 가로채서 추가하세요. 캔버스에서 센터링을 사용할 수 있습니다(캔버스 너비 - 텍스트 너비)/2 + x(x는 글꼴의 x축 이동)
rrreee질문 5: 미니 프로그램에서 네트워크 다이어그램을 처리하는 방법은 무엇입니까? CDN의 이미지 등 미니 프로그램에서 네트워크 이미지를 사용하는 경우 로컬 LRU 관리를 위해 WeChat으로 내려가야 나중에 동일한 이미지를 그릴 때 다운로드 시간을 절약할 수 있습니다. 따라서 우선 위챗 애플릿의 백그라운드에서 downloadFile의 법적 도메인 이름을 구성해야 합니다. 둘째, 캔버스에 그리기 전에 이미지를 미리 다운로드하고 시작하기 전에 이미지가 다운로드될 때까지 기다리는 것이 가장 좋습니다. 그리기 실패 문제를 피하기 위해 그릴 수 있습니다.Uint8ClampedArray
형식으로 변환하세요. 그런 다음 wx.canvasPutImageData(OBJECT, this)
를 통해 캔버스에 그린 다음 캔버스를 그림으로 내보냅니다. 🎜🎜질문 6: 둥근 모서리 그림을 그리는 방법은 무엇인가요? 🎜🎜질문 7: wx.canvasToTempFilePath에 대하여🎜🎜 Canvas를 사용하여 성공적으로 그린 후 이 메서드를 직접 호출하여 그림을 생성하면 IDE에서는 문제가 없지만 생성된 그림은 실제 컴퓨터에서는 불완전할 수 있습니다. 이 문제를 해결하기 위해. 🎜rrreee🎜질문 8: canvasContext.font 정보🎜🎜fontsize는 소수를 사용할 수 없습니다.
글꼴 설정의 글꼴 크기 부분에 소수점이 포함되어 있으면 전체 글꼴 설정이 무효화됩니다. 🎜이 문제는 Android 휴대폰에서 발생하며 iOS는 정상적으로 작동합니다. 이 문제를 처음 봤을 때 왜 일부는 중간에 있고 다른 일부는 훨씬 더 앞서 있는지 알 수 없었습니다. 나중에 확인해보니 Android에서 this.ctx.setTextAlign(textAlign)
의 기본값이 center
로 되어 있어 혼동을 주었는데 왼쪽으로 변경하니 정상이 되었습니다. this.ctx.setTextAlign(textAlign)
默认是为center
,所以导致了错乱,改成left后就正常了。
利用canvas绘制一个简单的折线图,只需要利用lineTo
和moveTo
俩个API
将点连接即可。利用createLinearGradient
캔버스를 사용하여 간단한 선 차트를 그리려면 lineToAPI
/code>와 moveTo
의 점을 연결하세요. 그림자를 그리려면 createLinearGradient
를 사용하세요. web
端使用拖拽的方式去完成设计稿的事情,自动生成json
생각 2: 백엔드 생성 포스터의 한계
프런트 엔드에서 포스터를 생성할 때 이미지를 로컬로 다운로드하고 정상적인 그리기를 보장하기 위해 Android에 특별한 setTimeout을 요구하는 등 시간이 더 오래 걸린다는 것을 알았습니다. 다양한 호환성 문제, 휴대폰, 안드로이드, iOS의 DPR 등 논스톱 부활절 달걀이 대머리가 되겠네요~ 하하하하~
캔버스를 개발하는 과정에서 항상 생각나게 하는 미니 프로그램에는 희미한 빛이 있었습니다. 최신 canvas2d API도 사용해봤는데 실제로 웹측과 동기화가 되었고 작성 방법도 개발자 도구에서는 모든 것이 정상으로 보이지만 휴대폰에서 실행하면 절반만 실행됩니다. 다양한 모델에서 테스트할 때도 마찬가지입니다. 나중에 원본 캔버스로 바꾸시면 괜찮을 것 같아요. . . 구체적인 이유는 WeChat 커뮤니티에서 아직 발견되지 않았습니다. 후속 반복 및 업그레이드를 통해 연구하겠습니다. 🎜🎜🎜추천 튜토리얼: "🎜JS Tutorial🎜"🎜위 내용은 캔버스를 사용하여 작은 프로그램에서 포스터를 그리는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!