configへ
github-actions opened this issue · 0 comments
github-actions commented
configへ
wfh_monitor/src/ui/control/Chart.h
Line 197 in 100e443
#include <algorithm>
#include <LovyanGFX.h>
#include "DrawDefs.h"
/**
* @brief X軸の描画設定
*/
enum class ChartMode : uint32_t {
Overwrite, /**< 最初の位置に戻って最初のデータの上に上書き */
Scroll, /**< 全体的に左にシフトしてから新しいデータを表示する */
Infinite, /**< 過去のデータを圧縮して新しいデータが常に表示されるようにする */
};
/**
* @brief Y軸の設定
*/
struct AxisY {
float min; /**< 最小値 */
float max; /**< 最大値 */
};
/**
* @brief Chartの描画設定
*/
struct ChartConfig {
ChartMode mode; /**< 描画設定 */
Rect rect; /**< 表示位置とサイズ */
AxisY axisY0; /**< 左側のY軸設定 */
AxisY axisY1; /**< 左側のY軸設定 */
Color axisColor; /**< 軸の色 */
uint32_t axisTickness; /**< 軸の太さ */
Color backColor; /**< 背景色 */
};
/**
* @brief Chartの点追加時の描画設定です
* @note Chart classで任意数のデータ系列を扱うため、内部で保持せず外部で指定する方式にしています
*/
struct PlotConfig {
uint32_t axisYIndex; /**< Y軸のIndex、左なら0、右なら1を指定(それ以上に軸を増やす実装は未対応) */
Color color; /**< 色 */
};
/**
* @brief LovyanGFXを使ってチャートを描画する機能を提供します。
* @note このクラスは描画を行うのみで履歴値は保持しません。点数を大きくしてもリソースを圧迫しません
*/
class Chart {
public:
/**
* @brief Construct a new Chart object
*/
Chart(void) {}
/**
* @brief Destroy the Chart object
*/
virtual ~Chart(void) {}
/**
* @brief グラフ描画設定を初期化します
*
* @param config 描画設定
* @param drawDst 描画先lcd or offscreen bufferを指定します
*
* @retval true 描画完了
* @retval false 描画失敗
*/
bool init(LovyanGFX& drawDst, const ChartConfig& config) {
// release buffer
if (this->isInitialized) {
this->isInitialized = false;
}
// config validation
if (config.rect.width == 0) return false;
if (config.rect.height == 0) return false;
// set variables
this->config = config;
this->xIndex = 0;
// 背景準備
this->drawBackground(drawDst);
this->drawAxis(drawDst);
// 設定完了
this->isInitialized = true;
return true;
}
/**
* @brief 点を追加します
* @remark 一通りの系列データをplotし終わったらflush()を呼び出してX軸位置をincrementしてください
*
* @param y 最新値
* @param plotConfig 描画設定
* @param drawDst 描画先lcd or offscreen bufferを指定します
*/
void plot(LovyanGFX& drawDst, float y, const PlotConfig& plotConfig) {
// 未初期化なら失敗
if (!this->isInitialized) {
return;
}
// TODO: Infinite/Scroll対応
// 描画位置計算
const float minY = (plotConfig.axisYIndex == 0) ? this->config.axisY0.min : this->config.axisY1.min;
const float maxY = (plotConfig.axisYIndex == 0) ? this->config.axisY0.max : this->config.axisY1.max;
const float areaY = (maxY - minY);
if (areaY == 0.0f) return;
const float ratioY = (y - minY) / areaY;
if (ratioY < 0.0f || 1.0f < ratioY) return;
// ratioYに0.0f~1.0fが入っているので描画領域からY座標を推定
const uint32_t plotY = (this->getPlotOffsetY0() + this->getPlotHeight()) - static_cast<uint32_t>(ratioY * this->getPlotHeight());
// 点を打つ
const auto plotColor =
drawDst.color888(
plotConfig.color.r,
plotConfig.color.g,
plotConfig.color.b
);
const uint32_t plotX = this->getPlotOffsetX0() + this->xIndex;
drawDst.drawPixel(plotX, plotY, plotColor);
}
/**
* @brief Xのデータ位置を進め、plot内容を確定させます
*
* @param drawDst 描画先lcd or offscreen bufferを指定します
*/
void next(LovyanGFX& drawDst) {
// 未初期化なら失敗
if (!this->isInitialized) {
return;
}
// x indexをすすめる
switch (this->config.mode) {
case ChartMode::Overwrite:
// 全部描画したら最初に戻る
this->xIndex = (this->xIndex + 1) % this->getPlotWidth();
break;
case ChartMode::Scroll:
case ChartMode::Infinite:
// いずれも一番最後の領域に描く
// 差分は0~n-1のSpriteをシフトするか圧縮するかの差
this->xIndex = std::min(this->xIndex + 1, this->getPlotWidth() - 1);
break;
default:
// 未実装
break;
}
// 予め塗りつぶしておく
const auto backColor =
drawDst.color888(
this->config.backColor.r,
this->config.backColor.g,
this->config.backColor.b
);
// 描画領域初期化
drawDst.fillRect(
this->getPlotOffsetX0() + this->xIndex,
this->getPlotOffsetY0(),
1,
this->getPlotHeight(),
backColor
);
// TODO: 初期化時に全部かけるように関数に切り出す
// 軸の点線
if (this->xIndex % 20 == 0) { // TODO: configへ
const PlotConfig y0Config = {
.axisYIndex = 0,
.color = {
.r = this->config.axisColor.r,
.g = this->config.axisColor.g,
.b = this->config.axisColor.b
},
};
const PlotConfig y1Config = {
.axisYIndex = 1,
.color = {
.r = this->config.axisColor.r,
.g = this->config.axisColor.g,
.b = this->config.axisColor.b
},
};
const uint32_t n = 5; // TODO: configへ
for (uint32_t i = 0; i < n; i ++) {
const float ratio = static_cast<float>(i) / static_cast<float>(n);
const float y0 = ratio * (this->config.axisY0.max - this->config.axisY0.min) + this->config.axisY0.min;
const float y1 = ratio * (this->config.axisY1.max - this->config.axisY1.min) + this->config.axisY1.min;
this->plot(drawDst, y0, y0Config);
this->plot(drawDst, y1, y1Config);
}
}
}
protected:
// local variables
bool isInitialized; /**< initが呼ばれていなければfalse */
ChartConfig config; /**< 描画設定 */
uint32_t xIndex; /**< X軸のデータ位置 */
/**
* @brief 背景を塗りつぶします
*
* @param drawDst 描画先
*/
void drawBackground(LovyanGFX& drawDst) {
// 背景塗りつぶし用
const auto backColor =
drawDst.color888(
this->config.backColor.r,
this->config.backColor.g,
this->config.backColor.b
);
// 描画領域初期化
drawDst.fillRect(
this->config.rect.x,
this->config.rect.y,
this->config.rect.width,
this->config.rect.height,
backColor
);
}
/**
* @brief 軸を描画します
*
* @param drawDst 描画先
*/
void drawAxis(LovyanGFX& drawDst) {
const auto axisColor =
drawDst.color888(
this->config.axisColor.r,
this->config.axisColor.g,
this->config.axisColor.b
);
for (uint32_t t = 0; t < this->config.axisTickness; t++) {
// top
drawDst.drawLine(
this->config.rect.x,
this->config.rect.y + t,
this->config.rect.x + this->config.rect.width,
this->config.rect.y + t,
axisColor
);
// bottom
drawDst.drawLine(
this->config.rect.x,
this->config.rect.y + this->config.rect.height - t,
this->config.rect.x + this->config.rect.width,
this->config.rect.y + this->config.rect.height - t,
axisColor
);
// left
drawDst.drawLine(
this->config.rect.x + t,
this->config.rect.y,
this->config.rect.x + t,
this->config.rect.y + this->config.rect.height,
axisColor
);
// right
drawDst.drawLine(
this->config.rect.x + this->config.rect.width - t,
this->config.rect.y,
this->config.rect.x + this->config.rect.width - t,
this->config.rect.y + this->config.rect.height,
axisColor
);
}
}
/**
* @brief 描画領域の横幅を取得します
*
* @return constexpr uint32_t
*/
constexpr uint32_t getPlotWidth(void) {
return this->config.rect.width - this->config.axisTickness * 2;
}
/**
* @brief 描画領域の高さを取得します
*
* @return constexpr uint32_t
*/
constexpr uint32_t getPlotHeight(void) {
return this->config.rect.height - this->config.axisTickness * 2;
}
/**
* @brief グラフ描画位置の左上を取得します
*
* @return constexpr uint32_t
*/
constexpr uint32_t getPlotOffsetX0(void) {
return this->config.rect.x + this->config.axisTickness;
}
/**
* @brief グラフ描画位置の左上を取得します
*
* @return constexpr uint32_t
*/
constexpr uint32_t getPlotOffsetY0(void) {
return this->config.rect.y + this->config.axisTickness;
}
};
#endif /* CHART_H */
No newline at end of file
ew file mode 100644
ndex 0000000..19fdadc
++ b/src/ui/control/DrawDefs.h
bc7346c7addc6ea63695a69590cf403aa5f0caa5