WeChat 애플릿에서 날씨 선 차트를 그리는 방법은 무엇입니까? 다음 기사에서는 WeChat 애플릿에서 캔버스를 사용하여 날씨 선 차트를 그리는 방법과 3차 베지어 곡선을 사용하여 온도 지점을 맞춰 매끄럽게 만들고 곡선 하단에 배경색을 지정하는 방법을 소개합니다. . 모두에게 도움이 되기를 바랍니다!
Rendering:
Custom 컴포넌트 line-chart
<canvas type="2d" id="line" class="line-class" style="width:{{width}}px;height:{{height}}px" />
Component({ externalClasses: ['line-class'], properties: { width: String, height: String, data: Array, }, observers: { width() { // 这里监听 width 变化重绘 canvas // 动态传入 width 好像只能这样了.. const query = this.createSelectorQuery(); query .select('#line') .fields({ node: true, size: true }) .exec(res => { const canvas = res[0].node; const ctx = canvas.getContext('2d'); const width = res[0].width; // 画布宽度 const height = res[0].height; // 画布高度 console.log(`宽度: ${width}, 高度: ${height}`); const dpr = wx.getSystemInfoSync().pixelRatio; canvas.width = width * dpr; canvas.height = height * dpr; ctx.scale(dpr, dpr); // 开始绘图 this.drawLine(ctx, width, height, this.data.data); }); }, }, methods: { drawLine(ctx, width, height, data) { const Max = Math.max(...data); const Min = Math.min(...data); // 把 canvas 的宽度, 高度按一定规则平分 const startX = width / (data.length * 2), // 起始点的横坐标 X baseY = height * 0.9, // 基线纵坐标 Y diffX = width / data.length, diffY = (height * 0.7) / (Max - Min); // 高度预留 0.2 写温度 ctx.beginPath(); ctx.textAlign = 'center'; ctx.font = '13px Microsoft YaHei'; ctx.lineWidth = 2; ctx.strokeStyle = '#ABDCFF'; // 画折线图的线 data.forEach((item, index) => { const x = startX + diffX * index, y = baseY - (item - Min) * diffY; ctx.fillText(`${item}°`, x, y - 10); ctx.lineTo(x, y); }); ctx.stroke(); // 画折线图背景 ctx.lineTo(startX + (data.length - 1) * diffX, baseY); // 基线终点 ctx.lineTo(startX, baseY); // 基线起点 const lingrad = ctx.createLinearGradient(0, 0, 0, height * 0.7); lingrad.addColorStop(0, 'rgba(255,255,255,0.9)'); lingrad.addColorStop(1, 'rgba(171,220,255,0)'); ctx.fillStyle = lingrad; ctx.fill(); // 画折线图上的小圆点 ctx.beginPath(); data.forEach((item, index) => { const x = startX + diffX * index, y = baseY - (item - Min) * diffY; ctx.moveTo(x, y); ctx.arc(x, y, 3, 0, 2 * Math.PI); }); ctx.fillStyle = '#0396FF'; ctx.fill(); }, }, });
data는 [1, 2, ...]
과 같은 온도 배열입니다.아니기 때문에 우리는 온도 값이 몇 개인지 알고 있으므로 여기의 너비는 동적으로 전달됩니다.
작은 문제가 있습니다. 즉, 너비가 너무 크면 실제 기계에서 표시되지 않습니다...
// 获取 scroll-view 的总宽度 wx.createSelectorQuery() .select('.hourly') .boundingClientRect(rect => { this.setData({ scrollWidth: rect.right - rect.left, }); }) .exec();
<view class="title">小时概述</view> <scroll-view scroll-x scroll-y class="scroll" show-scrollbar="{{false}}" enhanced="{{true}}"> <view class="hourly"> <view wx:for="{{time}}" wx:key="index">{{item}}</view> </view> <line-chart line-class="line" width="{{scrollWidth}}" height="100" data="{{temp}}" /> </scroll-view>
여기에는 스크롤-x, 스크롤-y를 적고, 그렇지 않으면 절대 위치 오프셋 문제가 있는데 왜인지 모르겠습니다
.scroll { position: relative; height: 150px; width: 100%; } .hourly { display: flex; height: 150px; position: absolute; top: 0; } .hourly > view { min-width: 3.5em; text-align: center; } .line { // 折线图绝对定位到底部 position: absolute; bottom: 0; }
여기서 사용한 절대 위치 지정은 사실 모지와 같은 꺾은선형 차트의 효과를 시뮬레이션하기 위한 것입니다. 날씨와 요일이 블록 단위이므로 시간별로 스크롤 뷰 등을 결합해야 합니다. 높으면 캔버스 위치를 지정해야 합니다
주로 Moji Weather를 얻는 방법을 모르기 때문에 일시적으로만 할 수 있습니다. ㅋㅋㅋ 먼저 포인트 수업을 작성해보세요
class Point { constructor(x, y) { this.x = x; this.y = y; } }
캔버스 베지어 곡선 그리기 도구(karlew.com)
즉, bezierCurveTo를 사용하면 마지막 점이 다음 점이고 처음 두 점이 제어점입니다
제어점 계산 참고: 베지어 곡선 제어점 결정 방법 - Baidu Library
https //wenku.baidu.com/view/c790f8d46bec0975f565e211.html
간략히 말하면여기서 a와 b는 임의의 양수일 수 있습니다그러므로 a의 제어점 A와 B를 계산하는 방법을 정의하세요. 특정 포인트
/** * 计算当前点的贝塞尔曲线控制点 * @param {Point} previousPoint: 前一个点 * @param {Point} currentPoint: 当前点 * @param {Point} nextPoint1: 下一个点 * @param {Point} nextPoint2: 下下个点 * @param {Number} scale: 系数 */ calcBezierControlPoints( previousPoint, currentPoint, nextPoint1, nextPoint2, scale = 0.25 ) { let x = currentPoint.x + scale * (nextPoint1.x - previousPoint.x); let y = currentPoint.y + scale * (nextPoint1.y - previousPoint.y); const controlPointA = new Point(x, y); // 控制点 A x = nextPoint1.x - scale * (nextPoint2.x - currentPoint.x); y = nextPoint1.y - scale * (nextPoint2.y - currentPoint.y); const controlPointB = new Point(x, y); // 控制点 B return { controlPointA, controlPointB }; }
여기 스케일은 a와 b인데 그 값을 동일하게 만드세요
하지만 첫 번째 포인트에는 이전 포인트가 없고 두 번째에서 마지막 포인트에는 nextPoint2가 없습니다
그래서 포인트가 첫 번째일 때 다음을 사용하세요. PreviousPoint 대신 currentPoint두 번째 점인 경우 nextPoint2 대신 nextPoint1을 사용하세요마지막 점은 bezierCurveTo의 세 번째 매개변수가 다음 점이므로 아무 것도 할 필요가 없습니다. 연결하기 위해 좌표만 제공하면 됩니다. 제어점을 계산할 필요가 없습니다. 따라서 3차 베지어 곡선을 그리는 방법:
/** * 绘制贝塞尔曲线 * ctx.bezierCurveTo(控制点1, 控制点2, 当前点); */ drawBezierLine(ctx, data, options) { const { startX, diffX, baseY, diffY, Min } = options; ctx.beginPath(); // 先移动到第一个点 ctx.moveTo(startX, baseY - (data[0] - Min) * diffY); data.forEach((e, i) => { let curPoint, prePoint, nextPoint1, nextPoint2, x, y; // 当前点 x = startX + diffX * i; y = baseY - (e - Min) * diffY; curPoint = new Point(x, y); // 前一个点 x = startX + diffX * (i - 1); y = baseY - (data[i - 1] - Min) * diffY; prePoint = new Point(x, y); // 下一个点 x = startX + diffX * (i + 1); y = baseY - (data[i + 1] - Min) * diffY; nextPoint1 = new Point(x, y); // 下下个点 x = startX + diffX * (i + 2); y = baseY - (data[i + 2] - Min) * diffY; nextPoint2 = new Point(x, y); if (i === 0) { // 如果是第一个点, 则前一个点用当前点代替 prePoint = curPoint; } else if (i === data.length - 2) { // 如果是倒数第二个点, 则下下个点用下一个点代替 nextPoint2 = nextPoint1; } else if (i === data.length - 1) { // 最后一个点直接退出 return; } const { controlPointA, controlPointB } = this.calcBezierControlPoints( prePoint, curPoint, nextPoint1, nextPoint2 ); ctx.bezierCurveTo( controlPointA.x, controlPointA.y, controlPointB.x, controlPointB.y, nextPoint1.x, nextPoint1.y ); }); ctx.stroke(); },
[관련 학습 권장 사항:
미니 프로그램 개발 튜토리얼]
위 내용은 WeChat 애플릿에서 캔버스를 사용하여 날씨 선 차트를 그리는 방법을 단계별로 가르칩니다(코드 포함).의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!