CocosCreatorでクールなレーダーチャートを描く方法

CocosCreatorでクールなレーダーチャートを描く方法

序文

レーダー チャートは、ネットワーク チャート、スター チャート、スパイダー ウェブ チャートとも呼ばれます。

これは、同じ点から始まる軸上で表される 3 つ以上の定量的変数の 2 次元グラフの形式で多変量データを表示するグラフィカルな方法です。

3 つ以上の次元を表示する変数に適用されます。

レーダー チャートは、データの統計や比較によく使用されます。どの変数が同様の値を持っているか、変数間に外れ値があるかどうかを確認するのに役立ちます。

同時に、レーダーチャートは多くのゲームで使用されており、非常に直感的にデータを表示および比較できます。

たとえば、King of Glory の戦闘データが使用されます。

この記事では、Pipi が Cocos Creator のグラフィックス コンポーネントを使用してクールなレーダー チャートを描画する方法を紹介します。

読みやすさを確保するために、元のコードは削減されます。

レーダーチャート コンポーネント: https://gitee.com/ifaswind/eazax-ccc/blob/master/components/RadarChart.ts


プレビュー

まずは効果を見てみましょう〜

オンラインプレビュー: https://ifaswind.gitee.io/eazax-cases/?case=radarChart

2つのデータ

緩和データ

ベルとホイッスル

芸術は爆発だ

だんだんと話題が逸れていく

文章

グラフィックコンポーネント

レーダー チャートの作成を始める前に、Cocos Creator エンジンのグラフィックス コンポーネントを見てみましょう。

Graphics コンポーネントはcc.RenderComponentを継承します。このコンポーネントを使用すると、描画ボードや表などの機能を実装できます。

プロパティ

今回使用するプロパティは以下のとおりです。

  • lineCap : 線の両端のスタイルを設定または返します (なし、丸いキャップ、または四角いキャップ)
  • lineJoin : 2本の線が交差するときの角のスタイル(ベベル、丸み、または鋭角)を設定または返します。
  • lineWidth : 現在のブラシの太さ(線の幅)を設定または返します。
  • strokeColor : 現在のブラシの色を設定または返します
  • fillColor : 塗りつぶしの色(ペイントバケツ)を設定または返します。

機能

今回使用する関数は以下のとおりです。

  • moveTo(x, y) : ペンを持ち上げて指定された位置に移動します(線は作成しません)
  • lineTo(x, y) : ペンを下ろして指定した位置まで直線を描く
  • circle(cx, cy, r) : 指定された位置(円の中心)に円を描きます。
  • close() : 作成されたラインを閉じます( lineTo(起點)と同等)
  • stroke() : 作成された(しかし描画されていない)線を描画します(線はデフォルトで透明であると考えてください。この動作により線に色が付きます)
  • fill() : 現在の線で囲まれた領域を塗りつぶします (線が閉じていない場合は、開始点と終了点を「閉じているようにシミュレート」しようとします)
  • clear() : 現在の描画ボード上のすべてを消去します

グラフィックス コンポーネントのドキュメント: http://docs.cocos.com/creator/manual/zh/components/graphics.html?h=graphics

グリッドを描く

まず、標準的なレーダーチャートの特徴を見てみましょう。

見つかりましたか?レーダーチャートの基本的な機能は次のとおりです。

  • 軸が3つ以上ある
  • 軸間の角度は同じです
  • 各軸には、中心点の他に少なくとも 1 つのスケール マークが必要です。
  • 各軸に同じスケール
  • 鱗の間の距離も同じです
  • 軸間の目盛りはグリッド線を形成するように接続されています

軸角度を計算する

まず軸間の角度 [ 360 ÷ 軸數] を計算し、次にすべての軸の角度を計算します。

this.angles = [];
// 軸間の角度 const iAngle = 360 / this.axes;
(i = 0 とします; i < this.axes; i++) {
    // 計算 const angle = iAngle * i;
    this.angles.push(角度);
}

スケール座標を計算する

レーダー チャートには少なくとも 3 つの軸があり、各軸には 1 つ以上のスケール (中心点を除く) が必要です

したがって、描画時に読み取れるように、最も外側のスケール (つまり、軸の端) から始めて、すべてのスケールの座標を保存する 2 次元配列を使用する必要があります。

// 2次元配列を作成します。let scalesSet: cc.Vec2[][] = [];
for (let i = 0; i < 軸上のスケールの数; i++) {
    // 現在のレイヤーのスケール座標を保存するために使用されます。let scales = [];
    // 軸上のスケールの位置を計算します。const length = axis length - (axis length / number of scales on the axis * i);
    (j = 0 とします; j < this.angles.length; j++) {
        // 角度をラジアンに変換 const radian = (Math.PI / 180) * this.angles[j];
        // 三角関数の公式に従って、中心点 (0, 0) を基準としたスケールの座標を計算します。const pos = cc.v2(length * Math.cos(radian), length * Math.sin(radian));
        // 配列をプッシュする scales.push(pos);
    }
    // 2次元配列をプッシュします scalesSet.push(scales);
}

軸線と外側のグリッド線を描く

中心点(0, 0)と最も外側のscalesSet[0]を結ぶスケールが軸です。

// 最も外側のスケールをすべてトラバースします for (let i = 0; i < scalesSet[0].length; i++) {
    // ブラシを中心点に移動します this.graphics.moveTo(0, 0);
    // 線を作成します this.graphics.lineTo(scalesSet[0][i].x, scalesSet[0][i].y);
}

外側のグリッド線

すべての軸上の最も外側のscalesSet[0]スケールを接続すると、外側のグリッド線が形成されます。

// ブラシを最初のポイントに移動します this.graphics.moveTo(scalesSet[0][0].x, scalesSet[0][0].y);
(i = 1; i < scalesSet[0].length; i++) の場合 {
    // 線を作成します this.graphics.lineTo(scalesSet[0][i].x, scalesSet[0][i].y);
}
// 現在の行(外側のグリッド線)を閉じる
this.graphics.close();

塗りつぶして描く

ここでは、最初に色を塗りつぶしてから線を描くように注意する必要があります。そうしないと、軸とグリッド線がブロックされます。

// 線で囲まれた空白領域を塗りつぶします this.graphics.fill();
// 作成した線(軸線と外側のグリッド線)を描画します
this.graphics.stroke();

つまり、次のようになります。

内側のグリッド線を描く

スケールの数が 1 より大きい場合は、スケール座標セットの下付き文字 1 から始めて、内側のグリッド線を描画する必要があります。

// スケールの数が 1 より大きい場合にのみ内側のグリッド線を描画します if (scalesSet.length > 1) {
    // 下から 1 から開始します (下付き文字 0 は外側のグリッド線です)
    (i = 1 とします; i < scalesSet.length; i++) {
        // ブラシを最初のポイントに移動します this.graphics.moveTo(scalesSet[i][0].x, scalesSet[i][0].y);
        (j = 1; j < scalesSet[i].length; j++) の場合 {
            // 線を作成します this.graphics.lineTo(scalesSet[i][j].x, scalesSet[i][j].y);
        }
        // 現在の行(内側のグリッド線)を閉じる
        this.graphics.close();
    }
    // 作成した線(内側のグリッド線)を描画します
    this.graphics.stroke();
}

このようにして、レーダーチャートのベースが描画されます。

図面データ

線描画ロジックを記述する前に、まず必要なデータ構造を決定しましょう。

  • 数値配列(必須、小数形式の比率、少なくとも 3 つの値)
  • 線の幅(オプション、指定しない場合はデフォルト値が使用されます)
  • 線の色(オプション、指定されていない場合はデフォルト値が使用されます)
  • 塗りつぶし色(オプション、指定しない場合はデフォルト値が使用されます)
  • ノードの色(オプション、指定されていない場合はデフォルト値が使用されます)

具体的なデータ構造は以下のとおりです(外部使用にはエクスポートタイプが便利です)。

/**
 * レーダーチャートデータ */
エクスポートインターフェースRadarChartData {

    /** 価値 */
    値: 数値[];

    /** 線の幅 */
    線幅?: 数値;

    /** 線の色 */
    線の色?: cc.Color;

    /** 塗りつぶし色 */
    塗りつぶしの色?: cc.Color;

    /** ノードの色 */
    cc.Color を結合しますか?

}

データのプロット

データのプロットは比較的簡単です。グラフ上のデータ ポイントの位置を把握し、データを接続すればよいだけです。

draw関数では、1 つ以上のレーダー チャート データを受け取り、順番に描画します (⚠️ 長いコード警告):

/**
 * 描画データ * @param data データ */
パブリック描画(データ: RadarChartData | RadarChartData[]) {
    // データを処理 const datas = Array.isArray(data) ? data : [data];

    // データの描画を開始します for (let i = 0; i < datas.length; i++) {
        // 染料をロードします this.graphics.strokeColor = datas[i].lineColor || defaultOptions.lineColor;
        this.graphics.fillColor = datas[i].fillColor || defaultOptions.fillColor;
        this.graphics.lineWidth = datas[i].lineWidth || defaultOptions.lineWidth;

        // ノード座標を計算する let coords = [];
        (j = 0; j < this.axes; j++) の場合 {
            定数値 = datas[i].values[j] > 1 ? 1 : datas[i].values[j];
            定数長さ = 値 * this.axisLength;
            const ラジアン = (Math.PI / 180) * this.angles[j];
            const pos = cc.v2(長さ * Math.cos(ラジアン), 長さ * Math.sin(ラジアン))
            座標をプッシュします。
        }

        // 線を作成します this.graphics.moveTo(coords[0].x, coords[0].y);
        (j = 1; j < coords.length; j++) の場合 {
            this.graphics.lineTo(座標[j].x, 座標[j].y);
        }
        this.graphics.close(); // 線を閉じます // 囲まれた領域を塗りつぶします this.graphics.fill();
        // 線を描画します this.graphics.stroke();

        // データノードを描画する for (let j = 0; j < coords.length; j++) {
            // 大きな円 this.graphics.strokeColor = datas[i].lineColor || defaultOptions.lineColor;
            this.graphics.circle(座標[j].x, 座標[j].y, 2);
            this.graphics.stroke();
            // 小さな円 this.graphics.strokeColor = datas[i].joinColor || defaultOptions.joinColor;
            this.graphics.circle(座標[j].x, 座標[j].y, .65);
            this.graphics.stroke();
        }

    }
}

これまでに、使用可能なレーダー チャートを作成することができました。

しかし!私たちの旅は星の海へ!いくつかの材料を追加する必要があります!

完全に静的なレーダーチャートはあまりにも退屈で平凡です。アニメーション化する方法を考えなければなりません。

レーダーチャートデータの値は配列形式になっています。これらの値をどのように動かすか考えたことはありますか?

Cocos Creator が提供するTween イージング システムのおかげで、複雑なデータをアニメーション化することが非常に簡単になりました。

これを、これを、そしてあれをやるだけ。簡単ですよね?

cc.tweenあらゆるオブジェクトのあらゆるプロパティの緩和をサポートします

イージング システム: http://docs.cocos.com/creator/manual/zh/scripting/tween.html

また、「万能穴掘りシェーダー」のイージングシステムも利用して穴掘りの動きを作ってみました~

オンラインプレビュー: https://ifaswind.gitee.io/eazax-cases/?case=newGuide

私の考えは:

  1. 現在のデータを現在のインスタンスのthis.curDatasに保存します
  2. 新しいデータを受信したら、 cc.tweenを使用してthis.curDataのプロパティを緩和します。
  3. update時にdraw関数を呼び出して、フレームごとにthis.curDatasのデータを再描画します。

すべてのフレームを更新

// 現在のレーダーチャートデータ private curDatas: RadarChartData[] = [];

保護された更新() {
    if (!this.keepUpdating) 戻り値:
    // 現在のデータを描画します this.draw(this.curDatas);
}

緩和データ

/**
 * スローモーション描画* @param data ターゲットデータ* @paramduration アニメーション期間*/
パブリック to(データ: RadarChartData | RadarChartData[], 期間: 数値) {
    // 繰り返しの呼び出しを処理します this.unscheduleAllCallbacks();
    
    // 単一のデータ部分をパックします const datas = Array.isArray(data) ? data : [data];

    // 各フレームの更新をオンにします this.keepUpdating = true;

    // 動く!
    (i = 0 とします; i < datas.length; i++) {
        // 値をアニメーション化します。
        // データ内のすべての値を走査し、1つずつ移動させます。
        (j = 0 とします; j < this.curDatas[i].values.length; j++) {
            // 最大値を 1 (つまり 100%) に制限します
            定数値 = datas[i].values[j] > 1 ? 1 : datas[i].values[j];
            cc.tween(this.curDatas[i].values)
                .to(期間, { [j]: 値 })
                。始める();
        }
        // 動きのあるスタイル!
        // 指定されていない場合は、元のスタイルが使用されます。
        cc.tween(this.curDatas[i])
            .to(期間, {
                線幅: datas[i].lineWidth || this.curDatas[i].lineWidth,
                線の色: datas[i].lineColor || this.curDatas[i].lineColor,
                塗りつぶし色: datas[i].fillColor || this.curDatas[i].fillColor,
                結合カラー: datas[i].結合カラー || this.curDatas[i].結合カラー
            })
            。始める();
    }

    this.scheduleOnce(() => {
        // 各フレームの更新をオフにします this.keepUpdating = false;
    }、 間隔);
}

値とスタイルの両方がアニメーション化されます。

レーダーチャート コンポーネント: https://gitee.com/ifaswind/eazax-ccc/blob/master/components/RadarChart.ts

上記は、CocosCreator でクールなレーダーチャートを描く方法の詳細です。CocosCreator でレーダーチャートを描く方法の詳細については、123WORDPRESS.COM の他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • Unity は物理エンジンを使用してマルチロータードローンの飛行をシミュレートします
  • Android 向け 2D 物理エンジン Box2d を使用する簡単な例
  • CocosCreator ソースコードの解釈: エンジンの起動とメインループ
  • CocosCreator 一般的なフレームワーク設計リソース管理
  • CocosCreatorでリストを作成する方法
  • CocosCreator の新しいリソース管理システムの分析
  • CocosCreator スケルトンアニメーション ドラゴンボーン
  • CocosCreatorでシューティングゲームを作る詳しい解説
  • CocosCreator MVCアーキテクチャの詳細な説明
  • CocosCreator で物理エンジン ジョイントを使用する方法

<<:  MySql Group Byは複数のフィールドのグループ化を実装します

>>:  Linux テキスト検索コマンド find の詳細な使用方法

推薦する

基礎知識: ウェブサイトのアドレスの前の http はどういう意味ですか?

HTTPとは何ですか?ウェブサイトを閲覧したいときは、ブラウザのアドレス バーにウェブサイトのアド...

Linux でファイルプレフィックスを一括で追加する方法

フォルダー内のすべての txt ファイルのファイル名の前に「gt_」を追加する必要があります。つまり...

Rails APIを使用してReactアプリケーションを構築するための詳細な手順

目次バックエンド: Rails API部分フロントエンド: React部分Reactコンポーネントa...

DockerをインストールしてAlibaba Cloud Image Acceleratorを構成する方法

DockerのインストールDocker はオープンソースなので、Windows システムへのインスト...

ReactとReduxの配列処理の説明

この記事では、reduce()、filter()、map()、every()、some()、spre...

Vue3におけるキーの役割と動作原理についての簡単な説明

このキー属性の機能は何ですか?まずは公式の説明を見てみましょう。 kekey 属性は主に、新しいノー...

ウェブページ作成時のHTMLタグの使用に注意してください

この記事では、Web ページの作成を学習するときに注意すべき HTML タグに関するいくつかの問題を...

JavaScript 組み込みオブジェクトの概要

目次1. 組み込みオブジェクト2. 数学オブジェクト1. Mathオブジェクトの使用2. 指定された...

Linux ドメイン ネーム サービス DNS 設定方法

DNSとはDNS の正式名称は Domain Name System で、ドメイン名解決システムを意...

MySQL が暗黙のデフォルト値を処理する方法

何人かの学生は、マスターとスレーブの間の不一致の問題に遭遇したと述べました。一般的な状況としては、m...

CSS3の3D効果を使って立方体を作成する

CSS3 の 3D 効果を使用して立方体を作成する方法を学ぶと、3D シーンの回転と変位のプロパティ...

Mysql でよく使用される時間、日付、変換関数の概要

この記事では、主に実際のアプリケーションでよく使用されるMySQLの時刻と日付、および変換関数につい...

Linux でリモート サーバー ファイルの状態を表示する方法

以下のように表示されます。 test コマンドはファイルが存在するかどうかを判断します。 ssh u...

nginx がアップストリーム アドレスにジャンプしない問題の解決方法

序文今日、nginx で非常に奇妙な問題に遭遇しました。フロントエンドの tomcat がページにジ...