Added ability to select part of pie chart.
This commit is contained in:
		
							parent
							
								
									bedefee1d1
								
							
						
					
					
						commit
						42215343cf
					
				
					 3 changed files with 116 additions and 2 deletions
				
			
		|  | @ -47,6 +47,7 @@ statisticsDetailsBottomCaptionStyle: TextStyle(defaultTextStyle) { | |||
| } | ||||
| 
 | ||||
| statisticsPieChartFont: font(20px); | ||||
| statisticsPieChartPartOffset: 8px; | ||||
| 
 | ||||
| statisticsChartHeaderHeight: 20px; | ||||
| statisticsHeaderTitleTextStyle: TextStyle(defaultTextStyle) { | ||||
|  |  | |||
|  | @ -437,10 +437,17 @@ void StackLinearChartView::paintZoomed(QPainter &p, const PaintContext &c) { | |||
| 
 | ||||
| 		p.setBrush(c.chartData.lines[k].color); | ||||
| 		p.setPen(Qt::NoPen); | ||||
| 		const auto textAngle = (previous + kPieAngleOffset) | ||||
| 			+ (now - previous) / 2.; | ||||
| 		const auto partOffset = _piePartController.offset( | ||||
| 			c.chartData.lines[k].id, | ||||
| 			textAngle); | ||||
| 		p.translate(partOffset); | ||||
| 		p.drawPie( | ||||
| 			rectF, | ||||
| 			-(previous + kPieAngleOffset) * 16, | ||||
| 			-(now - previous) * 16); | ||||
| 		p.translate(-partOffset); | ||||
| 	} | ||||
| 	paintPieText(p, c); | ||||
| } | ||||
|  | @ -482,9 +489,14 @@ void StackLinearChartView::paintPieText(QPainter &p, const PaintContext &c) { | |||
| 		const auto textRect = QRectF( | ||||
| 			textRectCenter - QPointF(textXShift, textYShift), | ||||
| 			textRectCenter + QPointF(textXShift, textYShift)); | ||||
| 		const auto partOffset = _piePartController.offset( | ||||
| 			c.chartData.lines[k].id, | ||||
| 			textAngle); | ||||
| 		p.setTransform( | ||||
| 			QTransform() | ||||
| 				.translate(textRectCenter.x(), textRectCenter.y()) | ||||
| 				.translate( | ||||
| 					textRectCenter.x() + partOffset.x(), | ||||
| 					textRectCenter.y() + partOffset.y()) | ||||
| 				.scale(scale, scale) | ||||
| 				.translate(-textRectCenter.x(), -textRectCenter.y())); | ||||
| 		p.setOpacity(opacity * alpha(c.chartData.lines[k].id)); | ||||
|  | @ -493,6 +505,81 @@ void StackLinearChartView::paintPieText(QPainter &p, const PaintContext &c) { | |||
| 	p.resetTransform(); | ||||
| } | ||||
| 
 | ||||
| void StackLinearChartView::setUpdateCallback(Fn<void()> callback) { | ||||
| 	if (callback) { | ||||
| 		_piePartAnimation.init([=] { callback(); }); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| bool StackLinearChartView::PiePartController::set(int id) { | ||||
| 	if (_selected != id) { | ||||
| 		update(_selected); | ||||
| 		_selected = id; | ||||
| 		update(_selected); | ||||
| 		return true; | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| void StackLinearChartView::PiePartController::update(int id) { | ||||
| 	if (id >= 0) { | ||||
| 		const auto was = _startedAt[id]; | ||||
| 		const auto p = (crl::now() - was) / st::slideWrapDuration; | ||||
| 		const auto progress = ((p > 0) && (p < 1)) ? (1. - p) : 0.; | ||||
| 		_startedAt[id] = crl::now() - (st::slideWrapDuration * progress); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| float64 StackLinearChartView::PiePartController::progress(int id) { | ||||
| 	const auto it = _startedAt.find(id); | ||||
| 	if (it == end(_startedAt)) { | ||||
| 		return 0.; | ||||
| 	} | ||||
| 	const auto at = it->second; | ||||
| 	const auto show = (_selected == id); | ||||
| 	const auto progress = std::clamp( | ||||
| 		(crl::now() - at) / float64(st::slideWrapDuration), | ||||
| 		0., | ||||
| 		1.); | ||||
| 	return std::clamp(show ? progress : (1. - progress), 0., 1.); | ||||
| } | ||||
| 
 | ||||
| QPointF StackLinearChartView::PiePartController::offset( | ||||
| 		LineId id, | ||||
| 		float64 angle) { | ||||
| 	const auto offset = st::statisticsPieChartPartOffset * progress(id); | ||||
| 	const auto radians = angle * M_PI / 180.; | ||||
| 	return { std::cos(radians) * offset, std::sin(radians) * offset }; | ||||
| } | ||||
| 
 | ||||
| void StackLinearChartView::handleMouseMove( | ||||
| 		const Data::StatisticalChart &chartData, | ||||
| 		const QPoint ¢er, | ||||
| 		const QPoint &p) { | ||||
| 	if (_transitionProgress < 1) { | ||||
| 		return; | ||||
| 	} | ||||
| 	const auto theta = std::atan2(center.y() - p.y(), (center.x() - p.x())); | ||||
| 	const auto angle = [&] { | ||||
| 		const auto a = theta * (180. / M_PI) + 90.; | ||||
| 		return (a > 180.) ? (a - 360.) : a; | ||||
| 	}(); | ||||
| 	for (auto k = 0; k < chartData.lines.size(); k++) { | ||||
| 		const auto previous = k | ||||
| 			? _cachedTransition.lines[k - 1].angle | ||||
| 			: -180; | ||||
| 		const auto now = _cachedTransition.lines[k].angle; | ||||
| 		if (angle > previous && angle <= now) { | ||||
| 			if (_piePartController.set(chartData.lines[k].id)) { | ||||
| 				if (!_piePartAnimation.animating()) { | ||||
| 					_piePartAnimation.start(); | ||||
| 				} | ||||
| 			} | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void StackLinearChartView::paintSelectedXIndex( | ||||
| 		QPainter &p, | ||||
| 		const Data::StatisticalChart &chartData, | ||||
|  | @ -548,7 +635,9 @@ int StackLinearChartView::findXIndexByPosition( | |||
| 		const Limits &xPercentageLimits, | ||||
| 		const QRect &rect, | ||||
| 		float64 x) { | ||||
| 	if (x < rect.x()) { | ||||
| 	if (_transitionProgress == 1.) { | ||||
| 		return -1; | ||||
| 	} else if (x < rect.x()) { | ||||
| 		return 0; | ||||
| 	} else if (x > (rect.x() + rect.width())) { | ||||
| 		return chartData.xPercentage.size() - 1; | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL | |||
| #include "statistics/segment_tree.h" | ||||
| #include "statistics/statistics_common.h" | ||||
| #include "statistics/view/abstract_chart_view.h" | ||||
| #include "ui/effects/animations.h" | ||||
| #include "ui/effects/animation_value.h" | ||||
| 
 | ||||
| namespace Data { | ||||
|  | @ -61,6 +62,12 @@ public: | |||
| 	void tick(crl::time now) override; | ||||
| 	void update(float64 dt) override; | ||||
| 
 | ||||
| 	void setUpdateCallback(Fn<void()> callback); | ||||
| 	void handleMouseMove( | ||||
| 		const Data::StatisticalChart &chartData, | ||||
| 		const QPoint ¢er, | ||||
| 		const QPoint &p); | ||||
| 
 | ||||
| private: | ||||
| 	struct PaintContext final { | ||||
| 		const Data::StatisticalChart &chartData; | ||||
|  | @ -115,6 +122,23 @@ private: | |||
| 
 | ||||
| 	std::vector<bool> _skipPoints; | ||||
| 
 | ||||
| 	class PiePartController final { | ||||
| 	public: | ||||
| 		using LineId = int; | ||||
| 		bool set(LineId id); | ||||
| 		[[nodiscard]] float64 progress(LineId id); | ||||
| 		[[nodiscard]] QPointF offset(LineId id, float64 angle); | ||||
| 
 | ||||
| 	private: | ||||
| 		void update(LineId id); | ||||
| 
 | ||||
| 		base::flat_map<LineId, crl::time> _startedAt; | ||||
| 		LineId _selected = -1; | ||||
| 
 | ||||
| 	}; | ||||
| 	PiePartController _piePartController; | ||||
| 	Ui::Animations::Basic _piePartAnimation; | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| } // namespace Statistic
 | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 23rd
						23rd