1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-10 22:31:40 +02:00

snap in marker if mouse near data point

This commit is contained in:
Laserlicht
2025-02-22 14:55:16 +01:00
parent 3e942395cf
commit 845f985a13
2 changed files with 46 additions and 14 deletions

View File

@@ -438,7 +438,7 @@ int computeGridStep(int maxAmount, int linesLimit)
} }
LineChart::LineChart(Rect position, std::string title, TData data, TIcons icons, float maxY) LineChart::LineChart(Rect position, std::string title, TData data, TIcons icons, float maxY)
: CIntObject(), maxVal(0), maxDay(0) : CIntObject(), maxVal(0), maxDay(0), data(data)
{ {
OBJECT_CONSTRUCTION; OBJECT_CONSTRUCTION;
@@ -474,13 +474,6 @@ LineChart::LineChart(Rect position, std::string title, TData data, TIcons icons,
niceMaxVal = gridStep * std::ceil(maxVal / gridStep); niceMaxVal = gridStep * std::ceil(maxVal / gridStep);
niceMaxVal = std::max(1, niceMaxVal); // avoid zero size Y axis (if all values are 0) niceMaxVal = std::max(1, niceMaxVal); // avoid zero size Y axis (if all values are 0)
// calculate points in chart
auto getPoint = [this](int i, std::vector<float> data){
float x = (static_cast<float>(chartArea.w) / static_cast<float>(maxDay - 1)) * static_cast<float>(i);
float y = static_cast<float>(chartArea.h) - (static_cast<float>(chartArea.h) / niceMaxVal) * data[i];
return Point(x, y);
};
// draw grid (vertical lines) // draw grid (vertical lines)
int dayGridInterval = maxDay < 700 ? 7 : 28; int dayGridInterval = maxDay < 700 ? 7 : 28;
if(maxDay > 1) if(maxDay > 1)
@@ -541,18 +534,51 @@ LineChart::LineChart(Rect position, std::string title, TData data, TIcons icons,
layout.emplace_back(std::make_shared<CLabel>(p.x, p.y, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->translate("core.genrltxt.64"))); layout.emplace_back(std::make_shared<CLabel>(p.x, p.y, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->translate("core.genrltxt.64")));
} }
Point LineChart::getPoint(int i, std::vector<float> data)
{
float x = (static_cast<float>(chartArea.w) / static_cast<float>(maxDay - 1)) * static_cast<float>(i);
float y = static_cast<float>(chartArea.h) - (static_cast<float>(chartArea.h) / niceMaxVal) * data[i];
return Point(x, y);
};
void LineChart::updateStatusBar(const Point & cursorPosition) void LineChart::updateStatusBar(const Point & cursorPosition)
{ {
statusBar->moveTo(cursorPosition + Point(-statusBar->pos.w / 2, 20)); OBJECT_CONSTRUCTION;
statusBar->fitToRect(pos, 10);
Rect r(pos.x + chartArea.x, pos.y + chartArea.y, chartArea.w, chartArea.h); Rect r(pos.x + chartArea.x, pos.y + chartArea.y, chartArea.w, chartArea.h);
statusBar->setEnabled(r.isInside(cursorPosition)); Point curPos = cursorPosition;
if(r.isInside(cursorPosition)) if(r.isInside(curPos))
{ {
float x = (static_cast<float>(maxDay - 1) / static_cast<float>(chartArea.w)) * (static_cast<float>(cursorPosition.x) - static_cast<float>(r.x)) + 1.0f; std::vector<std::pair<int, Point>> points;
float y = niceMaxVal - (niceMaxVal / static_cast<float>(chartArea.h)) * (static_cast<float>(cursorPosition.y) - static_cast<float>(r.y)); for(const auto & line : data)
{
for(int i = 0; i < line.second.size(); i++)
{
Point p = getPoint(i, line.second) + chartArea.topLeft();
int len = Point(curPos.x - p.x - pos.x, curPos.y - p.y - pos.y).length();
points.push_back(std::make_pair(len, p));
}
}
std::sort(points.begin(), points.end(), [](const auto &a, const auto &b) { return a.first < b.first; });
if(points.size() && points[0].first < 15)
{
// Snap in with marker for nearest point
hoverMarker = std::make_shared<TransparentFilledRectangle>(Rect(points[0].second - Point(3, 3), Point(6, 6)), Colors::ORANGE);
curPos = points[0].second + pos;
}
else
hoverMarker.reset();
float x = (static_cast<float>(maxDay - 1) / static_cast<float>(chartArea.w)) * (static_cast<float>(curPos.x) - static_cast<float>(r.x)) + 1.0f;
float y = niceMaxVal - (niceMaxVal / static_cast<float>(chartArea.h)) * (static_cast<float>(curPos.y) - static_cast<float>(r.y));
statusBar->write(CGI->generaltexth->translate("core.genrltxt.64") + ": " + CStatisticScreen::getDay(x) + " " + CGI->generaltexth->translate("vcmi.statisticWindow.value") + ": " + (static_cast<int>(y) > 0 ? std::to_string(static_cast<int>(y)) : std::to_string(y))); statusBar->write(CGI->generaltexth->translate("core.genrltxt.64") + ": " + CStatisticScreen::getDay(x) + " " + CGI->generaltexth->translate("vcmi.statisticWindow.value") + ": " + (static_cast<int>(y) > 0 ? std::to_string(static_cast<int>(y)) : std::to_string(y)));
} }
statusBar->setEnabled(r.resize(1).isInside(curPos));
statusBar->moveTo(curPos + Point(-statusBar->pos.w / 2, 20));
statusBar->fitToRect(pos, 10);
setRedrawParent(true); setRedrawParent(true);
redraw(); redraw();
} }

View File

@@ -20,6 +20,7 @@ class ComboBox;
class CSlider; class CSlider;
class IImage; class IImage;
class CPicture; class CPicture;
class TransparentFilledRectangle;
using TData = std::vector<std::pair<ColorRGBA, std::vector<float>>>; using TData = std::vector<std::pair<ColorRGBA, std::vector<float>>>;
using TIcons = std::vector<std::tuple<ColorRGBA, int, std::shared_ptr<IImage>, std::string>>; // Color, Day, Image, Helptext using TIcons = std::vector<std::tuple<ColorRGBA, int, std::shared_ptr<IImage>, std::string>>; // Color, Day, Image, Helptext
@@ -118,13 +119,18 @@ class LineChart : public CIntObject
std::vector<std::shared_ptr<CIntObject>> layout; std::vector<std::shared_ptr<CIntObject>> layout;
std::shared_ptr<CGStatusBar> statusBar; std::shared_ptr<CGStatusBar> statusBar;
std::vector<std::shared_ptr<CPicture>> pictures; std::vector<std::shared_ptr<CPicture>> pictures;
std::shared_ptr<TransparentFilledRectangle> hoverMarker;
Rect chartArea; Rect chartArea;
float maxVal; float maxVal;
int niceMaxVal; int niceMaxVal;
int maxDay; int maxDay;
TData data;
void updateStatusBar(const Point & cursorPosition); void updateStatusBar(const Point & cursorPosition);
// calculate points in chart
Point getPoint(int i, std::vector<float> data);
public: public:
LineChart(Rect position, std::string title, TData data, TIcons icons, float maxY); LineChart(Rect position, std::string title, TData data, TIcons icons, float maxY);