Bagaimana untuk melukis carta garis cuaca dalam applet WeChat? Artikel berikut akan memperkenalkan kepada anda cara menggunakan kanvas untuk melukis carta garis cuaca dalam applet WeChat, dan menggunakan lengkung Bezier tertib ketiga agar sesuai dengan titik suhu untuk menjadikannya licin dan mempunyai warna latar belakang di bahagian bawah lengkung Saya harap Bermanfaat untuk semua orang!
Rendering:
Carta garis komponen tersuai
<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 ialah tatasusunan suhu, seperti [1, 2, ...]
Kerana saya tidak 'Tidak tahu Berapa banyak nilai suhu yang ada, jadi lebar di sini dihantar secara dinamik
Ada masalah kecil, iaitu, jika lebar terlalu besar, mesin sebenar tidak akan memaparkannya. ..
// 获取 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>
Di sini Tulis tatal-x dan tatal-y, tidak akan ada masalah mengimbangi kedudukan mutlak, dan saya tidak tahu mengapa
.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; }
Kedudukan mutlak yang digunakan di sini sebenarnya adalah untuk mensimulasikan Kesan carta garisan seperti Cuaca Moji dan setiap hari dalam blok, jadi ketinggian setiap jam hendaklah sama dengan paparan skrol, dan kanvas perlu diletakkan
Terutamanya kerana saya tidak tahu cara melaksanakan Cuaca Moji, jadi saya hanya boleh melakukan ini buat sementara waktu
Rendering
emmm, nampak tak lancar sangat
Kira titik kawalan
Mula-mula tulis kelas mata
class Point { constructor(x, y) { this.x = x; this.y = y; } }
Alat lukisan lengkung Kanvas Bezier (karlew.com)
http: //wx.karlew.com/canvas/bezier/
Anda boleh mengetahui susunan ketiga melalui laman web di atas Maksud setiap parameter keluk Bezier
Iaitu, apabila menggunakan bezierCurveTo, titik terakhir ialah titik seterusnya, dan dua yang pertama ialah titik kawalan
Rujukan pengiraan titik kawalan: Kaedah menentukan titik kawalan lengkung Bezier - Perpustakaan Baidu
https://wenku.baidu.com/view/c790f8d46bec0975f565e211.html
Untuk meringkaskannya, ia adalah
di mana a dan b boleh menjadi sebarang nombor positif
Jadi tentukan kaedah untuk mengira titik kawalan A dan B bagi titik tertentu
/** * 计算当前点的贝塞尔曲线控制点 * @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 }; }
Di sini skala ialah a dan b, tetapi nilainya adalah sama
Tetapi titik pertama tidak mempunyai Titik sebelumnya, dan titik kedua terakhir tidak mempunyai NextPoint2
Jadi apabila titik itu adalah yang pertama, gunakan CurrentPoint dan bukannya previousPoint
Apabila ia adalah titik kedua terakhir, gunakan nextPoint1 dan bukannya nextPoint2
Bagi titik terakhir, anda tidak perlu melakukan apa-apa, kerana parameter ketiga bezierCurveTo ialah titik seterusnya Anda hanya perlu menyediakan koordinat untuk menyambung, dan tidak perlu mengira titik kawalan
Oleh itu, kaedah melukis lengkung Bezier tertib ketiga:
/** * 绘制贝塞尔曲线 * 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(); },
[Cadangan pembelajaran berkaitan: Tutorial Pembangunan Program Mini]
Atas ialah kandungan terperinci Ajar anda langkah demi langkah cara menggunakan kanvas untuk melukis carta garis cuaca dalam applet WeChat (dengan kod). Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!