Browse Source

Merge pull request #4496 from Laserlicht/statistic_improve

Statistics improve
Ivan Savenko 1 year ago
parent
commit
7b746bcaec

+ 1 - 1
Mods/vcmi/config/vcmi/german.json

@@ -163,7 +163,7 @@
 	"vcmi.systemOptions.townsGroup" : "Stadt-Bildschirm",
 
 	"vcmi.statisticWindow.statistics" : "Statistik",
-	"vcmi.statisticWindow.tsvCopy" : "Daten in Zwischenabl.",
+	"vcmi.statisticWindow.tsvCopy" : "In Zwischenablage",
 	"vcmi.statisticWindow.selectView" : "Ansicht wählen",
 	"vcmi.statisticWindow.value" : "Wert",
 	"vcmi.statisticWindow.title.overview" : "Überblick",

+ 61 - 20
client/mainmenu/CStatisticScreen.cpp

@@ -130,13 +130,9 @@ TIcons CStatisticScreen::extractIcons() const
 	std::sort(tmpData.begin(), tmpData.end(), [](const StatisticDataSetEntry & v1, const StatisticDataSetEntry & v2){ return v1.player == v2.player ? v1.day < v2.day : v1.player < v2.player; });
 
 	auto imageTown = GH.renderHandler().loadImage(AnimationPath::builtin("cradvntr"), 3, 0, EImageBlitMode::COLORKEY);
-	imageTown->scaleTo(Point(CHART_ICON_SIZE, CHART_ICON_SIZE));
 	auto imageBattle = GH.renderHandler().loadImage(AnimationPath::builtin("cradvntr"), 5, 0, EImageBlitMode::COLORKEY);
-	imageBattle->scaleTo(Point(CHART_ICON_SIZE, CHART_ICON_SIZE));
-	auto imageDefeated = GH.renderHandler().loadImage(AnimationPath::builtin("tpthchk"), 1, 0, EImageBlitMode::COLORKEY);
-	imageDefeated->scaleTo(Point(CHART_ICON_SIZE, CHART_ICON_SIZE));
+	auto imageDefeated = GH.renderHandler().loadImage(AnimationPath::builtin("crcombat"), 0, 0, EImageBlitMode::COLORKEY);
 	auto imageGrail = GH.renderHandler().loadImage(AnimationPath::builtin("vwsymbol"), 2, 0, EImageBlitMode::COLORKEY);
-	imageGrail->scaleTo(Point(CHART_ICON_SIZE, CHART_ICON_SIZE));
 
 	std::map<PlayerColor, bool> foundDefeated;
 	std::map<PlayerColor, bool> foundGrail;
@@ -273,7 +269,11 @@ OverviewPanel::OverviewPanel(Rect position, std::string title, const StatisticDa
 		},
 		{
 			CGI->generaltexth->translate("vcmi.statisticWindow.param.daysSurvived"), [this](PlayerColor color){
-				return CStatisticScreen::getDay(playerDataFilter(color).size());
+				auto playerData = playerDataFilter(color);
+				for(int i = 0; i < playerData.size(); i++)
+					if(playerData[i].status == EPlayerStatus::LOSER)
+						return CStatisticScreen::getDay(i + 1);
+				return CStatisticScreen::getDay(playerData.size());
 			}
 		},
 		{
@@ -424,12 +424,25 @@ void OverviewPanel::update(int to)
 	}
 }
 
+int computeGridStep(int maxAmount, int linesLimit)
+{
+	for (int lineInterval = 1;;lineInterval *= 10)
+	{
+		for (int factor : { 1, 2, 5 } )
+		{
+			int lineIntervalToTest = lineInterval * factor;
+			if (maxAmount / lineIntervalToTest <= linesLimit)
+				return lineIntervalToTest;
+		}
+	}
+}
+
 LineChart::LineChart(Rect position, std::string title, TData data, TIcons icons, float maxY)
 	: CIntObject(), maxVal(0), maxDay(0)
 {
 	OBJECT_CONSTRUCTION;
 
-	addUsedEvents(LCLICK | MOVE);
+	addUsedEvents(LCLICK | MOVE | GESTURE);
 
 	pos = position + pos.topLeft();
 
@@ -455,15 +468,47 @@ LineChart::LineChart(Rect position, std::string title, TData data, TIcons icons,
 			maxDay = line.second.size();
 	}
 
+	//calculate nice maxVal
+	int gridLineCount = 10;
+	int gridStep = computeGridStep(maxVal, gridLineCount);
+	niceMaxVal = gridStep * std::ceil(maxVal / gridStep);
+
+	// 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)
+	int dayGridInterval = maxDay < 700 ? 7 : 28;
+	for(const auto & line : data)
+	{
+		for(int i = 0; i < line.second.size(); i += dayGridInterval)
+		{
+			Point p = getPoint(i, line.second) + chartArea.topLeft();
+			canvas->addLine(Point(p.x, chartArea.topLeft().y), Point(p.x, chartArea.topLeft().y + chartArea.h), ColorRGBA(70, 70, 70));
+		}
+	}
+
+	// draw grid (horizontal lines)
+	if(maxVal > 0)
+	{
+		int gridStepPx = int((static_cast<float>(chartArea.h) / niceMaxVal) * gridStep);
+		for(int i = 0; i < std::ceil(maxVal / gridStep) + 1; i++)
+		{
+			canvas->addLine(chartArea.topLeft() + Point(0, chartArea.h - gridStepPx * i), chartArea.topLeft() + Point(chartArea.w, chartArea.h - gridStepPx * i), ColorRGBA(70, 70, 70));
+			layout.emplace_back(std::make_shared<CLabel>(chartArea.topLeft().x - 5, chartArea.topLeft().y + 10 + chartArea.h - gridStepPx * i, FONT_SMALL, ETextAlignment::CENTERRIGHT, Colors::WHITE, TextOperations::formatMetric(i * gridStep, 5)));
+		}
+	}
+
 	// draw
 	for(const auto & line : data)
 	{
 		Point lastPoint(-1, -1);
 		for(int i = 0; i < line.second.size(); i++)
 		{
-			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) / maxVal) * line.second[i];
-			Point p = Point(x, y) + chartArea.topLeft();
+			Point p = getPoint(i, line.second) + chartArea.topLeft();
 
 			if(lastPoint.x != -1)
 				canvas->addLine(lastPoint, p, line.first);
@@ -472,7 +517,7 @@ LineChart::LineChart(Rect position, std::string title, TData data, TIcons icons,
 			for(auto & icon : icons)
 				if(std::get<0>(icon) == line.first && std::get<1>(icon) == i + 1) // color && day
 				{
-					pictures.emplace_back(std::make_shared<CPicture>(std::get<2>(icon), Point(x - (CHART_ICON_SIZE / 2), y - (CHART_ICON_SIZE / 2)) + chartArea.topLeft()));
+					pictures.emplace_back(std::make_shared<CPicture>(std::get<2>(icon), Point(p.x - (std::get<2>(icon)->width() / 2), p.y - (std::get<2>(icon)->height() / 2))));
 					pictures.back()->addRClickCallback([icon](){ CRClickPopup::createAndPush(std::get<3>(icon)); });
 				}
 
@@ -484,12 +529,8 @@ LineChart::LineChart(Rect position, std::string title, TData data, TIcons icons,
 	canvas->addLine(chartArea.topLeft() + Point(0, -10), chartArea.topLeft() + Point(0, chartArea.h + 10), Colors::WHITE);
 	canvas->addLine(chartArea.topLeft() + Point(-10, chartArea.h), chartArea.topLeft() + Point(chartArea.w + 10, chartArea.h), Colors::WHITE);
 
-	Point p = chartArea.topLeft() + Point(-5, chartArea.h + 10);
-	layout.emplace_back(std::make_shared<CLabel>(p.x, p.y, FONT_SMALL, ETextAlignment::CENTERRIGHT, Colors::WHITE, "0"));
-	p = chartArea.topLeft() + Point(chartArea.w + 10, chartArea.h + 10);
+	Point p = chartArea.topLeft() + Point(chartArea.w + 10, chartArea.h + 10);
 	layout.emplace_back(std::make_shared<CLabel>(p.x, p.y, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, CStatisticScreen::getDay(maxDay)));
-	p = chartArea.topLeft() + Point(-5, -10);
-	layout.emplace_back(std::make_shared<CLabel>(p.x, p.y, FONT_SMALL, ETextAlignment::CENTERRIGHT, Colors::WHITE, std::to_string(static_cast<int>(maxVal))));
 	p = chartArea.bottomLeft() + Point(chartArea.w / 2, + 20);
 	layout.emplace_back(std::make_shared<CLabel>(p.x, p.y, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->translate("core.genrltxt.64")));
 }
@@ -502,8 +543,8 @@ void LineChart::updateStatusBar(const Point & cursorPosition)
 	statusBar->setEnabled(r.isInside(cursorPosition));
 	if(r.isInside(cursorPosition))
 	{
-		float x = (static_cast<float>(maxDay) / static_cast<float>(chartArea.w)) * (static_cast<float>(cursorPosition.x) - static_cast<float>(r.x)) + 1.0f;
-		float y = maxVal - (maxVal / static_cast<float>(chartArea.h)) * (static_cast<float>(cursorPosition.y) - static_cast<float>(r.y));
+		float x = (static_cast<float>(maxDay - 1) / static_cast<float>(chartArea.w)) * (static_cast<float>(cursorPosition.x) - static_cast<float>(r.x)) + 1.0f;
+		float y = niceMaxVal - (niceMaxVal / static_cast<float>(chartArea.h)) * (static_cast<float>(cursorPosition.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)));
 	}
 	setRedrawParent(true);
@@ -515,7 +556,7 @@ void LineChart::mouseMoved(const Point & cursorPosition, const Point & lastUpdat
 	updateStatusBar(cursorPosition);
 }
 
-void LineChart::clickPressed(const Point & cursorPosition)
+void LineChart::gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance)
 {
-	updateStatusBar(cursorPosition);
+	updateStatusBar(currentPosition);
 }

+ 2 - 3
client/mainmenu/CStatisticScreen.h

@@ -24,8 +24,6 @@ class CPicture;
 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
 
-const int CHART_ICON_SIZE = 32;
-
 class CStatisticScreen : public CWindowObject
 {
 	enum Content {
@@ -123,6 +121,7 @@ class LineChart : public CIntObject
 
 	Rect chartArea;
 	float maxVal;
+	int niceMaxVal;
 	int maxDay;
 
 	void updateStatusBar(const Point & cursorPosition);
@@ -130,5 +129,5 @@ public:
 	LineChart(Rect position, std::string title, TData data, TIcons icons, float maxY);
 
 	void mouseMoved(const Point & cursorPosition, const Point & lastUpdateDistance) override;
-	void clickPressed(const Point & cursorPosition) override;
+	void gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance) override;
 };