8 using System.Collections.Generic;
10 using UnityEngine.EventSystems;
45 [SerializeField]
private string m_Name;
47 [SerializeField]
private int m_Dimension = 1;
48 [SerializeField]
private float m_XPosition;
49 [SerializeField]
private float m_YPosition;
50 [SerializeField]
private double m_XValue;
51 [SerializeField]
private double m_YValue;
52 [SerializeField]
private int m_Group = 0;
53 [SerializeField]
private bool m_ZeroPosition =
false;
61 public int index {
get;
set; }
62 public Vector3 runtimeStartPosition {
get;
internal set; }
63 public Vector3 runtimeEndPosition {
get;
internal set; }
64 public Vector3 runtimeCurrentEndPosition {
get;
internal set; }
65 public ChartLabel runtimeLabel {
get;
internal set; }
66 public double runtimeValue {
get;
internal set; }
74 get {
return m_Name; }
75 set {
if (PropertyUtil.SetClass(ref m_Name, value)) SetVerticesDirty(); }
83 get {
return m_Type; }
84 set {
if (PropertyUtil.SetStruct(ref m_Type, value)) SetVerticesDirty(); }
92 get {
return m_Dimension; }
93 set {
if (PropertyUtil.SetStruct(ref m_Dimension, value)) SetVerticesDirty(); }
101 get {
return m_XPosition; }
102 set {
if (PropertyUtil.SetStruct(ref m_XPosition, value)) SetVerticesDirty(); }
110 get {
return m_YPosition; }
111 set {
if (PropertyUtil.SetStruct(ref m_YPosition, value)) SetVerticesDirty(); }
119 get {
return m_XValue; }
120 set {
if (PropertyUtil.SetStruct(ref m_XValue, value)) SetVerticesDirty(); }
128 get {
return m_YValue; }
129 set {
if (PropertyUtil.SetStruct(ref m_YValue, value)) SetVerticesDirty(); }
137 get {
return m_Group; }
138 set {
if (PropertyUtil.SetStruct(ref m_Group, value)) SetVerticesDirty(); }
146 get {
return m_ZeroPosition; }
147 set {
if (PropertyUtil.SetStruct(ref m_ZeroPosition, value)) SetVerticesDirty(); }
155 get {
return m_StartSymbol; }
156 set {
if (PropertyUtil.SetClass(ref m_StartSymbol, value)) SetVerticesDirty(); }
164 get {
return m_EndSymbol; }
165 set {
if (PropertyUtil.SetClass(ref m_EndSymbol, value)) SetVerticesDirty(); }
173 get {
return m_LineStyle; }
174 set {
if (PropertyUtil.SetClass(ref m_LineStyle, value)) SetVerticesDirty(); }
182 get {
return m_Label; }
183 set {
if (PropertyUtil.SetClass(ref m_Label, value)) SetVerticesDirty(); }
196 [System.Serializable]
199 [SerializeField]
private bool m_Show;
201 [SerializeField]
private List<MarkLineData> m_Data =
new List<MarkLineData>();
209 get {
return m_Show; }
210 set {
if (PropertyUtil.SetStruct(ref m_Show, value)) SetVerticesDirty(); }
218 get {
return m_Animation; }
219 set {
if (PropertyUtil.SetClass(ref m_Animation, value)) SetVerticesDirty(); }
229 public List<MarkLineData>
data
231 get {
return m_Data; }
232 set {
if (PropertyUtil.SetClass(ref m_Data, value)) SetVerticesDirty(); }
234 public static MarkLine defaultMarkLine
241 m_Data =
new List<MarkLineData>()
243 var
data =
new MarkLineData();
244 data.name =
"average";
246 data.lineStyle.type = LineStyle.Type.Dashed;
247 data.lineStyle.color = Color.blue;
248 data.startSymbol.show =
true;
250 data.endSymbol.show =
true;
252 data.label.show =
true;
253 data.label.numericFormatter =
"f1";
254 data.label.formatter =
"{c}";
255 markLine.data.Add(
data);
261 internal class MarkLineHandler : IComponentHandler
263 public CoordinateChart chart;
264 private GameObject m_MarkLineLabelRoot;
266 public MarkLineHandler(CoordinateChart chart)
271 public void DrawBase(VertexHelper vh)
275 public void DrawTop(VertexHelper vh)
282 m_MarkLineLabelRoot = ChartHelper.AddObject(
"markline", chart.transform, chart.chartMinAnchor,
283 chart.chartMaxAnchor, chart.chartPivot, chart.chartSizeDelta);
284 m_MarkLineLabelRoot.hideFlags = chart.chartHideFlags;
285 ChartHelper.HideAllObject(m_MarkLineLabelRoot);
286 foreach (var serie
in chart.series.list) InitMarkLine(serie);
289 public void OnBeginDrag(PointerEventData eventData)
293 public void OnDrag(PointerEventData eventData)
297 public void OnEndDrag(PointerEventData eventData)
301 public void OnPointerDown(PointerEventData eventData)
305 public void OnScroll(PointerEventData eventData)
311 foreach (var serie
in chart.series.list)
313 var show = serie.show && serie.markLine.show;
314 foreach (var data
in serie.markLine.data)
316 if (data.runtimeLabel !=
null)
318 if (data.runtimeLabel.gameObject.activeSelf != show)
319 data.runtimeLabel.gameObject.SetActive(show);
322 data.runtimeLabel.SetPosition(MarkLineHelper.GetLabelPosition(data));
323 data.runtimeLabel.SetText(MarkLineHelper.GetFormatterContent(serie, data));
330 private void InitMarkLine(Serie serie)
332 if (!serie.show || !serie.markLine.show)
return;
333 ResetTempMarkLineGroupData(serie.markLine);
334 var serieColor = (Color)chart.theme.GetColor(chart.GetLegendRealShowNameIndex(serie.name));
335 if (m_TempGroupData.Count > 0)
337 foreach (var kv
in m_TempGroupData)
339 if (kv.Value.Count >= 2)
341 var data = kv.Value[0];
342 InitMarkLineLabel(serie, data, serieColor);
346 foreach (var data
in serie.markLine.data)
348 if (data.group != 0)
continue;
349 InitMarkLineLabel(serie, data, serieColor);
353 private void InitMarkLineLabel(Serie serie, MarkLineData data, Color serieColor)
355 data.painter = chart.m_PainterTop;
356 data.refreshComponent = delegate ()
358 var label = data.label;
359 var textName =
string.Format(
"markLine_{0}_{1}", serie.index, data.index);
360 var color = !ChartHelper.IsClearColor(label.textStyle.color) ? label.textStyle.color : chart.theme.axis.textColor;
361 var element = ChartHelper.AddSerieLabel(textName, m_MarkLineLabelRoot.transform, label.backgroundWidth,
362 label.backgroundHeight, color, label.textStyle, chart.theme);
363 var isAutoSize = label.backgroundWidth == 0 || label.backgroundHeight == 0;
364 var item =
new ChartLabel();
365 item.SetLabel(element, isAutoSize, label.paddingLeftRight, label.paddingTopBottom);
366 item.SetIconActive(
false);
367 item.SetActive(data.label.show);
368 item.SetPosition(MarkLineHelper.GetLabelPosition(data));
369 item.SetText(MarkLineHelper.GetFormatterContent(serie, data));
370 data.runtimeLabel = item;
372 data.refreshComponent();
375 private void DrawMarkLine(VertexHelper vh)
377 foreach (var serie
in chart.series.list)
379 DrawMarkLine(vh, serie);
383 private Dictionary<int, List<MarkLineData>> m_TempGroupData =
new Dictionary<int, List<MarkLineData>>();
384 private void DrawMarkLine(VertexHelper vh, Serie serie)
386 if (!serie.show || !serie.markLine.show)
return;
387 if (serie.markLine.data.Count == 0)
return;
388 var yAxis = chart.GetSerieYAxisOrDefault(serie);
389 var xAxis = chart.GetSerieXAxisOrDefault(serie);
390 var grid = chart.GetSerieGridOrDefault(serie);
391 var dataZoom = DataZoomHelper.GetAxisRelatedDataZoom(xAxis, chart.dataZooms);
392 var animation = serie.markLine.animation;
393 var showData = serie.GetDataList(dataZoom);
394 var sp = Vector3.zero;
395 var ep = Vector3.zero;
396 var colorIndex = chart.GetLegendRealShowNameIndex(serie.name);
397 var serieColor = SerieHelper.GetLineColor(serie, chart.theme, colorIndex,
false);
398 animation.InitProgress(1, 0, 1f);
399 ResetTempMarkLineGroupData(serie.markLine);
400 if (m_TempGroupData.Count > 0)
402 foreach (var kv
in m_TempGroupData)
404 if (kv.Value.Count >= 2)
406 sp = GetSinglePos(xAxis, yAxis, grid, serie, dataZoom, kv.Value[0], showData.Count);
407 ep = GetSinglePos(xAxis, yAxis, grid, serie, dataZoom, kv.Value[1], showData.Count);
408 kv.Value[0].runtimeStartPosition = sp;
409 kv.Value[1].runtimeEndPosition = ep;
410 DrawMakLineData(vh, kv.Value[0], animation, serie, grid, serieColor, sp, ep);
414 foreach (var data
in serie.markLine.data)
416 if (data.group != 0)
continue;
420 data.runtimeValue = SerieHelper.GetMinData(serie, data.dimension, dataZoom);
421 GetStartEndPos(xAxis, yAxis, grid, data.runtimeValue, ref sp, ref ep);
424 data.runtimeValue = SerieHelper.GetMaxData(serie, data.dimension, dataZoom);
425 GetStartEndPos(xAxis, yAxis, grid, data.runtimeValue, ref sp, ref ep);
428 data.runtimeValue = SerieHelper.GetAverageData(serie, data.dimension, dataZoom);
429 GetStartEndPos(xAxis, yAxis, grid, data.runtimeValue, ref sp, ref ep);
432 data.runtimeValue = SerieHelper.GetMedianData(serie, data.dimension, dataZoom);
433 GetStartEndPos(xAxis, yAxis, grid, data.runtimeValue, ref sp, ref ep);
436 if (data.xPosition != 0)
438 data.runtimeValue = data.xPosition;
439 var pX = grid.runtimeX + data.xPosition;
440 sp =
new Vector3(pX, grid.runtimeY);
441 ep =
new Vector3(pX, grid.runtimeY + grid.runtimeHeight);
443 else if (data.yPosition != 0)
445 data.runtimeValue = data.yPosition;
446 var pY = grid.runtimeY + data.yPosition;
447 sp =
new Vector3(grid.runtimeX, pY);
448 ep =
new Vector3(grid.runtimeX + grid.runtimeWidth, pY);
450 else if (data.yValue != 0)
452 data.runtimeValue = data.yValue;
453 if (yAxis.IsCategory())
455 var pY = AxisHelper.GetAxisPosition(grid, yAxis, data.yValue, showData.Count, dataZoom);
456 sp =
new Vector3(grid.runtimeX, pY);
457 ep =
new Vector3(grid.runtimeX + grid.runtimeWidth, pY);
461 GetStartEndPos(xAxis, yAxis, grid, data.yValue, ref sp, ref ep);
466 data.runtimeValue = data.xValue;
467 if (xAxis.IsCategory())
469 var pX = AxisHelper.GetAxisPosition(grid, xAxis, data.xValue, showData.Count, dataZoom);
470 sp =
new Vector3(pX, grid.runtimeY);
471 ep =
new Vector3(pX, grid.runtimeY + grid.runtimeHeight);
475 GetStartEndPos(xAxis, yAxis, grid, data.xValue, ref sp, ref ep);
482 data.runtimeStartPosition = sp;
483 data.runtimeEndPosition = ep;
484 DrawMakLineData(vh, data, animation, serie, grid, serieColor, sp, ep);
486 if (!animation.IsFinish())
488 animation.CheckProgress(1f);
489 chart.RefreshTopPainter();
493 private void ResetTempMarkLineGroupData(MarkLine markLine)
495 m_TempGroupData.Clear();
496 for (
int i = 0; i < markLine.data.Count; i++)
498 var data = markLine.data[i];
500 if (data.group == 0)
continue;
501 if (!m_TempGroupData.ContainsKey(data.group))
503 m_TempGroupData[data.group] =
new List<MarkLineData>();
505 m_TempGroupData[data.group].Add(data);
509 private void DrawMakLineData(VertexHelper vh, MarkLineData data, SerieAnimation animation, Serie serie,
510 Grid grid, Color32 serieColor, Vector3 sp, Vector3 ep)
512 if (!animation.IsFinish())
513 ep = Vector3.Lerp(sp, ep, animation.GetCurrDetail());
514 data.runtimeCurrentEndPosition = ep;
515 if (sp != Vector3.zero || ep != Vector3.zero)
517 chart.ClampInChart(ref sp);
518 chart.ClampInChart(ref ep);
519 var theme = chart.theme.axis;
520 var lineColor = ChartHelper.IsClearColor(data.lineStyle.color) ? serieColor : data.lineStyle.color;
521 var lineWidth = data.lineStyle.width == 0 ? theme.lineWidth : data.lineStyle.width;
522 ChartDrawer.DrawLineStyle(vh, data.lineStyle, sp, ep, lineWidth, LineStyle.Type.Dashed, lineColor, lineColor);
523 if (data.startSymbol !=
null && data.startSymbol.show)
525 DrawMarkLineSymbol(vh, data.startSymbol, serie, grid, chart.theme, sp, sp, lineColor);
527 if (data.endSymbol !=
null && data.endSymbol.show)
529 DrawMarkLineSymbol(vh, data.endSymbol, serie, grid, chart.theme, ep, sp, lineColor);
534 private void DrawMarkLineSymbol(VertexHelper vh, SerieSymbol symbol, Serie serie, Grid grid, ChartTheme theme,
535 Vector3 pos, Vector3 startPos, Color32 lineColor)
537 var symbolSize = symbol.GetSize(
null, theme.serie.lineSymbolSize);
538 var tickness = SerieHelper.GetSymbolBorder(serie,
null, theme,
false);
539 var cornerRadius = SerieHelper.GetSymbolCornerRadius(serie,
null,
false);
540 chart.Internal_CheckClipAndDrawSymbol(vh, symbol.type, symbolSize, tickness, pos, lineColor, lineColor,
541 ColorUtil.clearColor32, symbol.gap,
true, cornerRadius, grid, startPos);
544 private void GetStartEndPos(Axis xAxis, Axis yAxis, Grid grid,
double value, ref Vector3 sp, ref Vector3 ep)
546 if (xAxis.IsCategory())
548 var pY = AxisHelper.GetAxisPosition(grid, yAxis, value);
549 sp =
new Vector3(grid.runtimeX, pY);
550 ep =
new Vector3(grid.runtimeX + grid.runtimeWidth, pY);
554 var pX = AxisHelper.GetAxisPosition(grid, xAxis, value);
555 sp =
new Vector3(pX, grid.runtimeY);
556 ep =
new Vector3(pX, grid.runtimeY + grid.runtimeHeight);
560 private float GetAxisPosition(Grid grid, Axis axis, DataZoom dataZoom,
int dataCount,
double value)
562 return AxisHelper.GetAxisPosition(grid, axis, value, dataCount, dataZoom);
565 private Vector3 GetSinglePos(Axis xAxis, Axis yAxis, Grid grid, Serie serie, DataZoom dataZoom, MarkLineData data,
571 var serieData = SerieHelper.GetMinSerieData(serie, data.dimension, dataZoom);
572 data.runtimeValue = serieData.GetData(data.dimension);
573 var pX = GetAxisPosition(grid, xAxis, dataZoom, serieDataCount, serieData.index);
574 var pY = GetAxisPosition(grid, yAxis, dataZoom, serieDataCount, data.runtimeValue);
575 return new Vector3(pX, pY);
577 serieData = SerieHelper.GetMaxSerieData(serie, data.dimension, dataZoom);
578 data.runtimeValue = serieData.GetData(data.dimension);
579 pX = GetAxisPosition(grid, xAxis, dataZoom, serieDataCount, serieData.index);
580 pY = GetAxisPosition(grid, yAxis, dataZoom, serieDataCount, data.runtimeValue);
581 return new Vector3(pX, pY);
583 if (data.zeroPosition)
585 data.runtimeValue = 0;
586 return grid.runtimePosition;
590 pX = data.xPosition != 0 ? grid.runtimeX + data.xPosition :
591 GetAxisPosition(grid, xAxis, dataZoom, serieDataCount, data.xValue);
592 pY = data.yPosition != 0 ? grid.runtimeY + data.yPosition :
593 GetAxisPosition(grid, yAxis, dataZoom, serieDataCount, data.yValue);
594 data.runtimeValue = data.yValue;
595 return new Vector3(pX, pY);
598 return grid.runtimePosition;
603 internal static class MarkLineHelper
605 public static string GetFormatterContent(Serie serie, MarkLineData data)
607 var serieLabel = data.label;
608 var numericFormatter = serieLabel.numericFormatter;
609 if (serieLabel.formatterFunction !=
null)
611 return serieLabel.formatterFunction(data.index, data.runtimeValue);
613 if (
string.IsNullOrEmpty(serieLabel.formatter))
614 return ChartCached.NumberToStr(data.runtimeValue, numericFormatter);
617 var content = serieLabel.formatter;
618 FormatterHelper.ReplaceSerieLabelContent(ref content, numericFormatter, data.runtimeValue,
619 0, serie.name, data.name, Color.clear);
624 public static Vector3 GetLabelPosition(MarkLineData data)
626 if (!data.label.show)
return Vector3.zero;
627 var dir = (data.runtimeEndPosition - data.runtimeStartPosition).normalized;
628 var horizontal = Mathf.Abs(Vector3.Dot(dir, Vector3.right)) == 1;
629 var labelWidth = data.runtimeLabel ==
null ? 50 : data.runtimeLabel.GetLabelWidth();
630 var labelHeight = data.runtimeLabel ==
null ? 20 : data.runtimeLabel.GetLabelHeight();
631 switch (data.label.position)
633 case SerieLabel.Position.Start:
634 if (horizontal)
return data.runtimeStartPosition + data.label.offset + labelWidth / 2 * Vector3.left;
635 else return data.runtimeStartPosition + data.label.offset + labelHeight / 2 * Vector3.down;
636 case SerieLabel.Position.Middle:
637 var center = (data.runtimeStartPosition + data.runtimeCurrentEndPosition) / 2;
638 if (horizontal)
return center + data.label.offset + labelHeight / 2 * Vector3.up;
639 else return center + data.label.offset + labelWidth / 2 * Vector3.right;
641 if (horizontal)
return data.runtimeCurrentEndPosition + data.label.offset + labelWidth / 2 * Vector3.right;
642 else return data.runtimeCurrentEndPosition + data.label.offset + labelHeight / 2 * Vector3.up;