今回は、キャンバスに描画されたポリライン セグメントのエッジとコーナーを滑らかにする方法、つまり、各描画点にベジェ曲線を渡すことによって元のポリライン グラフを置き換える方法を共有します。
滑らかにフィットするポリライン セグメントを使用する理由まず、Echarts での折れ線グラフのレンダリング効果を見てみましょう。
最初は、このポリライン セグメントが実際にはそれを通過する曲線であることに気付かず、単純な点描画だと思っていました。そのため、最初に実装した単純な (醜い) バージョンと簡単な (醜い) バージョンは次のようなものでした。
重要な点は、実装後に Echarts の実装が非常にスムーズであることがわかり、その後の議論のきっかけにもなりました。滑らかな曲線を定期的に描くにはどうすればよいでしょうか?
レンダリング
まず、最終的な模倣の実装を見てみましょう。
Echarts が内部でどのように実装されているかわからないため (エスケープ
見た目はすでに非常に丸みを帯びており、当初のビジョンに非常に近いものになっています。曲線が描画点を通過するかどうかを確認してみましょう。
わかりました!結果は明らかです。実装を見てみましょう。
実装プロセス
シミュレートされたデータ
var data = [Math.random() * 300]; for (var i = 1; i < 50; i++) { //echarts に従ってください data.push(Math.round((Math.random() - 0.5) * 20 + data[i - 1])); } オプション = { Canvas:{ id: 'canvas' }, series: { name: 'シミュレートされたデータ', itemStyle: { color: 'rgb(255, 70, 131)' }, areaStyle: { color: 'rgb(255, 158, 68)' }, data: data } };折れ線グラフを描く
まずコンストラクターを初期化して、必要なデータを配置します。
function LinearGradient(option) { this.canvas = document.getElementById(option.canvas.id) this.ctx = this.canvas.getContext('2d') this.width = this.canvas.width this.height = this.canvas .height this.tooltip = option.tooltip this.title = option.text this.series = option.series //ストレージ シミュレーション データ}折れ線グラフを描きます。
LinearGradient.prototype.draw1 = function() { //ポリラインの基準線... //キャンバスの原点は左上隅であると考えるべきです。 //そのため、以下でいくつかの変換を行う必要があります。 //diff x、y 軸はデータです。最大値と最小値の範囲の等しい部分です。 this.series.data.forEach(function(item,index){varx=diffX*index,y=Math.floor(self.height - diffY * (item - dataMin)) self.ctx.lineTo(x, y) //個々のデータポイントをプロットする}) ...}ベジェ曲線の滑らかなフィッティングベジェ曲線の重要なポイントは、制御点の選択です。この Web サイトでは、さまざまな制御点で描かれたさまざまな曲線を動的に表示できます。そして制御点の計算用です。 。著者は数学が苦手なので、それでも Baidu を選びました:)。特定のアルゴリズムに興味がある学生は、それについてさらに詳しく学ぶことができます。次に、制御点の計算の結論について説明します。
上の式には、現在の点、前の点、次の 2 点の 4 つの座標点が含まれます。座標値が下図のとおりである場合、描かれる曲線は次のようになります。
ただし、始点と終点にはこの式が使えないという問題がありますが、その記事では境界値を処理する方法も紹介されています。
したがって、ポリラインを滑らかな曲線に変更するときは、境界値とその他の制御点を計算し、それらをベッセル関数に代入します。
//コア実装 this.series.data.forEach(function(item,index) { //前の点と次の点の間の制御点を見つけます varscale = 0.1 //ab 制御点が正の数の場合、次のことができますvar を調整します last1X = diffX * (index - 1), last1Y = Math.floor(self.height - diffY * (self.series.data[index - 1] - dataMin)), //前の点の座標 last2X = diffX * (index - 2), last2Y = Math.floor(self.height - diffY * (self.series.data[index - 2] - dataMin)), //最初の 2 点の座標 nowX = diffX * (index) , nowY = Math.floor(self.height - diffY * (self.series.data[index] - dataMin)), //現在点の座標 nextX = diffX * (index + 1), nextY = Math.floor(self.height - diffY * (self.series.data[index + 1] - dataMin)), //次の点の座標 cAx = last1X + (nowX - last2X) * スケール, cAy = last1Y + (nowY - last2Y) * スケール、cBx = nowX - (nextX - last1X) * スケール、cBy = nowY - (nextY - last1Y) * スケール if(index === 0) { self.ctx.lineTo(nowX, nowY) return } else if(index ===1) { cAx = last1X + (nowX - 0) * スケール cAy = last1Y + (nowY - self.height) * スケール } else if (インデックス === self.series.data.length - 1) { cBx = nowX - (nowX - last1X) * スケール cBy = nowY - (nowY - last1Y) * スケール} self.ctx.bezierCurveTo(cAx, cAy, cBx, cBy, nowX, nowY) //前の点から現在の点までベジェ曲線を描画します})毎回通過するポイントは現在のポイントですが、記事に記載されている式は次のポイントを計算するコントロール ポイント アルゴリズムであるため、コード実装ではすべてのポイントの計算を 1 つ前に移動しました。インデックス = 0 (初期点) の場合、前の点から現在の点まで曲線を描いており、描く必要のある 0 への曲線がないため、曲線を描く必要はありません。インデックス = 1 から開始して、通常どおり 0 から 1 まで曲線の描画を開始できます。インデックス = 1 の場合、その前に 2 番目の点はなく、特別な計算が必要な境界値点になり、最後に A 点になります。 。残りは、通常の公式に従って AB の xy 座標を計算し、ベッセル関数に代入するだけです。
やっとここのソースコードを参照してください
以上がこの記事の全内容です。皆様の学習のお役に立てれば幸いです。また、VeVb Wulin Network をご支援いただければ幸いです。