AirControl  1.3.0
Open Source, Modular, and Extensible Flight Simulator For Deep Learning Research
VisualMap.cs
1 /************************************************/
2 /* */
3 /* Copyright (c) 2018 - 2021 monitor1394 */
4 /* https://github.com/monitor1394 */
5 /* */
6 /************************************************/
7 
8 using System.Collections.Generic;
9 using UnityEngine;
10 using UnityEngine.EventSystems;
11 using UnityEngine.UI;
12 using XUGL;
13 
14 namespace XCharts
15 {
20  [System.Serializable]
21  public class VisualMap : MainComponent
22  {
26  public enum Type
27  {
31  Continuous,
35  Piecewise
36  }
37 
41  public enum SelectedMode
42  {
46  Multiple,
50  Single
51  }
52 
53  [System.Serializable]
54  public class Pieces
55  {
56  [SerializeField] private double m_Min;
57  [SerializeField] private double m_Max;
58  [SerializeField] private string m_Label;
59  [SerializeField] private Color32 m_Color;
60 
64  public double min { get { return m_Min; } set { m_Min = value; } }
68  public double max { get { return m_Max; } set { m_Max = value; } }
72  public string label { get { return m_Label; } set { m_Label = value; } }
76  public Color32 color { get { return m_Color; } set { m_Color = value; } }
77 
78  public bool Contains(double value, double minMaxRange)
79  {
80  var cmin = System.Math.Abs(m_Min) < 1 ? minMaxRange * m_Min : m_Min;
81  var cmax = System.Math.Abs(m_Max) < 1 ? minMaxRange * m_Max : m_Max;
82  return value >= cmin && value < cmax;
83  }
84  }
85 
86  [SerializeField] private bool m_Enable = false;
87  [SerializeField] private bool m_Show = true;
88  [SerializeField] private Type m_Type = Type.Continuous;
89  [SerializeField] private SelectedMode m_SelectedMode = SelectedMode.Multiple;
90  [SerializeField] private double m_Min = 0;
91  [SerializeField] private double m_Max = 100;
92 
93  [SerializeField] private double[] m_Range = new double[2] { 0, 100 };
94  [SerializeField] private string[] m_Text = new string[2] { "", "" };
95  [SerializeField] private float[] m_TextGap = new float[2] { 10f, 10f };
96  [SerializeField] private int m_SplitNumber = 5;
97  [SerializeField] private bool m_Calculable = false;
98  [SerializeField] private bool m_Realtime = true;
99  [SerializeField] private float m_ItemWidth = 20f;
100  [SerializeField] private float m_ItemHeight = 140f;
101  [SerializeField] private float m_ItemGap = 10f;
102  [SerializeField] private float m_BorderWidth = 0;
103  [SerializeField] private int m_Dimension = -1;
104  [SerializeField] private bool m_HoverLink = true;
105  [SerializeField] private bool m_AutoMinMax = true;
106  [SerializeField] private Orient m_Orient = Orient.Horizonal;
107  [SerializeField] private Location m_Location = Location.defaultLeft;
108  [SerializeField] private List<Color32> m_InRange = new List<Color32>();
109  [SerializeField] private List<Color32> m_OutOfRange = new List<Color32>() { Color.gray };
110  [SerializeField] private List<Pieces> m_Pieces = new List<Pieces>();
111 
119  public bool enable
120  {
121  get { return m_Enable; }
122  set { if (PropertyUtil.SetStruct(ref m_Enable, value)) SetVerticesDirty(); }
123  }
131  public bool show
132  {
133  get { return m_Show; }
134  set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetVerticesDirty(); }
135  }
140  public Type type
141  {
142  get { return m_Type; }
143  set { if (PropertyUtil.SetStruct(ref m_Type, value)) SetVerticesDirty(); }
144  }
150  {
151  get { return m_SelectedMode; }
152  set { if (PropertyUtil.SetStruct(ref m_SelectedMode, value)) SetVerticesDirty(); }
153  }
159  public double min
160  {
161  get { return m_Min; }
162  set { if (PropertyUtil.SetStruct(ref m_Min, value)) SetVerticesDirty(); }
163  }
169  public double max
170  {
171  get { return m_Max; }
172  set { m_Max = (value < min ? min + 1 : value); SetVerticesDirty(); }
173  }
179  public double[] range { get { return m_Range; } }
184  public string[] text { get { return m_Text; } }
189  public float[] textGap { get { return m_TextGap; } }
197  public int splitNumber
198  {
199  get { return m_SplitNumber; }
200  set { if (PropertyUtil.SetStruct(ref m_SplitNumber, value)) SetVerticesDirty(); }
201  }
207  public bool calculable
208  {
209  get { return m_Calculable; }
210  set { if (PropertyUtil.SetStruct(ref m_Calculable, value)) SetVerticesDirty(); }
211  }
217  public bool realtime
218  {
219  get { return m_Realtime; }
220  set { if (PropertyUtil.SetStruct(ref m_Realtime, value)) SetVerticesDirty(); }
221  }
227  public float itemWidth
228  {
229  get { return m_ItemWidth; }
230  set { if (PropertyUtil.SetStruct(ref m_ItemWidth, value)) SetVerticesDirty(); }
231  }
237  public float itemHeight
238  {
239  get { return m_ItemHeight; }
240  set { if (PropertyUtil.SetStruct(ref m_ItemHeight, value)) SetVerticesDirty(); }
241  }
245  public float itemGap
246  {
247  get { return m_ItemGap; }
248  set { if (PropertyUtil.SetStruct(ref m_ItemGap, value)) SetVerticesDirty(); }
249  }
255  public float borderWidth
256  {
257  get { return m_BorderWidth; }
258  set { if (PropertyUtil.SetStruct(ref m_BorderWidth, value)) SetVerticesDirty(); }
259  }
266  public int dimension
267  {
268  get { return m_Dimension; }
269  set { if (PropertyUtil.SetStruct(ref m_Dimension, value)) SetVerticesDirty(); }
270  }
281  public bool hoverLink
282  {
283  get { return m_HoverLink; }
284  set { if (PropertyUtil.SetStruct(ref m_HoverLink, value)) SetVerticesDirty(); }
285  }
290  public bool autoMinMax
291  {
292  get { return m_AutoMinMax; }
293  set { if (PropertyUtil.SetStruct(ref m_AutoMinMax, value)) SetVerticesDirty(); }
294  }
300  public Orient orient
301  {
302  get { return m_Orient; }
303  set { if (PropertyUtil.SetStruct(ref m_Orient, value)) SetVerticesDirty(); }
304  }
309  public Location location
310  {
311  get { return m_Location; }
312  set { if (PropertyUtil.SetClass(ref m_Location, value)) SetVerticesDirty(); }
313  }
318  public List<Color32> inRange
319  {
320  get { return m_InRange; }
321  set { if (value != null) { m_InRange = value; SetVerticesDirty(); } }
322  }
327  public List<Color32> outOfRange
328  {
329  get { return m_OutOfRange; }
330  set { if (value != null) { m_OutOfRange = value; SetVerticesDirty(); } }
331  }
335  public List<Pieces> pieces
336  {
337  get { return m_Pieces; }
338  set { if (value != null) { m_Pieces = value; SetVerticesDirty(); } }
339  }
340 
341  public override bool vertsDirty { get { return m_VertsDirty || location.anyDirty; } }
342  public override void ClearVerticesDirty()
343  {
344  base.ClearVerticesDirty();
345  location.ClearVerticesDirty();
346  }
347 
348  public override void ClearComponentDirty()
349  {
350  base.ClearComponentDirty();
351  location.ClearComponentDirty();
352  }
353 
358  public int runtimeSelectedIndex { get; set; }
359  public double runtimeSelectedValue { get; set; }
364  public Vector2 runtimePointerPos { get; set; }
365  public bool runtimeIsVertical { get { return orient == Orient.Vertical; } }
366  public double rangeMin
367  {
368  get
369  {
370  if (m_Range[0] < min || m_Range[0] > max) return min;
371  else return m_Range[0];
372  }
373  set
374  {
375  if (value >= min && value <= m_Range[1]) m_Range[0] = value;
376  }
377  }
378 
379  public double rangeMax
380  {
381  get
382  {
383  if (m_Range[1] >= m_Range[0] && m_Range[1] < max) return m_Range[1];
384  else return max;
385  }
386  set
387  {
388  if (value >= m_Range[0] && value <= max) m_Range[1] = value;
389  }
390  }
391 
392  public int runtimeSplitNumber
393  {
394  get
395  {
396  if (splitNumber > 0 && splitNumber <= m_InRange.Count) return splitNumber;
397  else return m_InRange.Count;
398  }
399  }
400 
401  public float runtimeRangeMinHeight { get { return (float)((rangeMin - min) / (max - min) * itemHeight); } }
402  public float runtimeRangeMaxHeight { get { return (float)((rangeMax - min) / (max - min) * itemHeight); } }
403  public bool runtimeMinDrag { get; internal set; }
404  public bool runtimeMaxDrag { get; internal set; }
405 
406  private List<Color32> m_RtInRange = new List<Color32>();
407  public List<Color32> runtimeInRange
408  {
409  get
410  {
411  if (splitNumber == 0 || m_InRange.Count >= splitNumber || m_InRange.Count < 1 || IsPiecewise())
412  {
413  return m_InRange;
414  }
415  else
416  {
417  if (m_RtInRange.Count != runtimeSplitNumber)
418  {
419  m_RtInRange.Clear();
420  var total = max - min;
421  var diff1 = total / (m_InRange.Count - 1);
422  var diff2 = total / splitNumber;
423 
424  var inCount = 0;
425  var inValue = min;
426  var rtValue = min;
427 
428 
429  for (int i = 0; i < splitNumber; i++)
430  {
431  rtValue += diff2;
432  if (rtValue > inValue + diff1)
433  {
434  inValue += diff1;
435  inCount++;
436  }
437  if (i == splitNumber - 1)
438  {
439  m_RtInRange.Add(m_InRange[m_InRange.Count - 1]);
440  }
441  else
442  {
443  var rate = (float)((rtValue - inValue) / diff1);
444  m_RtInRange.Add(Color32.Lerp(m_InRange[inCount], m_InRange[inCount + 1], rate));
445  }
446  }
447  }
448  return m_RtInRange;
449  }
450  }
451  }
452 
453  public Color32 GetColor(double value)
454  {
455  switch (type)
456  {
457  case Type.Continuous:
458  return GetContinuousColor(value);
459  case Type.Piecewise:
460  return GetPiecesColor(value);
461  default:
462  return ColorUtil.clearColor32;
463  }
464  }
465 
466  private Color32 GetPiecesColor(double value)
467  {
468  foreach (var piece in m_Pieces)
469  {
470  if (piece.Contains(value, max - min))
471  {
472  return piece.color;
473  }
474  }
475  if (m_OutOfRange.Count > 0) return m_OutOfRange[0];
476  else return ChartConst.clearColor32;
477  }
478 
479  private Color32 GetContinuousColor(double value)
480  {
481  if (value < m_Min || value > m_Max)
482  {
483  if (m_OutOfRange.Count > 0) return m_OutOfRange[0];
484  else return ChartConst.clearColor32;
485  }
486  int splitNumber = runtimeInRange.Count;
487  if (splitNumber <= 0) return ChartConst.clearColor32;
488  var index = GetIndex(value);
489  if (m_Type == VisualMap.Type.Piecewise)
490  {
491  if (index >= 0 && index < runtimeInRange.Count)
492  return runtimeInRange[index];
493  else return ChartConst.clearColor32;
494  }
495  else
496  {
497  var diff = (m_Max - m_Min) / (splitNumber - 1);
498  var nowMin = m_Min + index * diff;
499  var rate = (value - nowMin) / diff;
500  if (index == splitNumber - 1) return runtimeInRange[index];
501  else return Color32.Lerp(runtimeInRange[index], runtimeInRange[index + 1], (float)rate);
502  }
503  }
504 
505  public int GetIndex(double value)
506  {
507  int splitNumber = runtimeInRange.Count;
508  if (splitNumber <= 0) return -1;
509  value = MathUtil.Clamp(value, m_Min, m_Max);
510 
511  var diff = (m_Max - m_Min) / (splitNumber - 1);
512  var index = -1;
513  for (int i = 0; i < splitNumber; i++)
514  {
515  if (value <= m_Min + (i + 1) * diff)
516  {
517  index = i;
518  break;
519  }
520  }
521  return index;
522  }
523 
524  public bool IsPiecewise()
525  {
526  return m_Type == VisualMap.Type.Piecewise;
527  }
528 
529  public bool IsInSelectedValue(double value)
530  {
531  if (runtimeSelectedIndex < 0) return true;
532  else
533  {
534  return runtimeSelectedIndex == GetIndex(value);
535  }
536  }
537 
538  public double GetValue(Vector3 pos, Rect chartRect)
539  {
540  var centerPos = new Vector3(chartRect.x, chartRect.y) + location.GetPosition(chartRect.width, chartRect.height);
541  var pos1 = centerPos + (runtimeIsVertical ? Vector3.down : Vector3.left) * itemHeight / 2;
542  var pos2 = centerPos + (runtimeIsVertical ? Vector3.up : Vector3.right) * itemHeight / 2;
543  if (runtimeIsVertical)
544  {
545  if (pos.y < pos1.y) return min;
546  else if (pos.y > pos2.y) return max;
547  else return min + (pos.y - pos1.y) / (pos2.y - pos1.y) * (max - min);
548  }
549  else
550  {
551  if (pos.x < pos1.x) return min;
552  else if (pos.x > pos2.x) return max;
553  else return min + (pos.x - pos1.x) / (pos2.x - pos1.x) * (max - min);
554  }
555  }
556 
557  public bool IsInRect(Vector3 local, Rect chartRect, float triangleLen = 20)
558  {
559  var centerPos = new Vector3(chartRect.x, chartRect.y) + location.GetPosition(chartRect.width, chartRect.height);
560  var diff = calculable ? triangleLen : 0;
561  if (local.x >= centerPos.x - itemWidth / 2 - diff && local.x <= centerPos.x + itemWidth / 2 + diff &&
562  local.y >= centerPos.y - itemHeight / 2 - diff && local.y <= centerPos.y + itemHeight / 2 + diff)
563  {
564  return true;
565  }
566  else
567  {
568  return false;
569  }
570  }
571 
572  public bool IsInRangeRect(Vector3 local, Rect chartRect)
573  {
574  var centerPos = new Vector3(chartRect.x, chartRect.y) + location.GetPosition(chartRect.width, chartRect.height);
575  if (orient == Orient.Vertical)
576  {
577  var pos1 = centerPos + Vector3.down * itemHeight / 2;
578  return local.x >= centerPos.x - itemWidth / 2 && local.x <= centerPos.x + itemWidth / 2 &&
579  local.y >= pos1.y + runtimeRangeMinHeight && local.y <= pos1.y + runtimeRangeMaxHeight;
580  }
581  else
582  {
583  var pos1 = centerPos + Vector3.left * itemHeight / 2;
584  return local.x >= pos1.x + runtimeRangeMinHeight && local.x <= pos1.x + runtimeRangeMaxHeight &&
585  local.y >= centerPos.y - itemWidth / 2 && local.y <= centerPos.y + itemWidth / 2;
586  }
587  }
588 
589  public bool IsInRangeMinRect(Vector3 local, Rect chartRect, float triangleLen)
590  {
591  var centerPos = new Vector3(chartRect.x, chartRect.y) + location.GetPosition(chartRect.width, chartRect.height);
592  if (orient == Orient.Vertical)
593  {
594  var radius = triangleLen / 2;
595  var pos1 = centerPos + Vector3.down * itemHeight / 2;
596  var cpos = new Vector3(pos1.x + itemWidth / 2 + radius, pos1.y + runtimeRangeMinHeight - radius);
597 
598  return local.x >= cpos.x - radius && local.x <= cpos.x + radius &&
599  local.y >= cpos.y - radius && local.y <= cpos.y + radius;
600  }
601  else
602  {
603  var radius = triangleLen / 2;
604  var pos1 = centerPos + Vector3.left * itemHeight / 2;
605  var cpos = new Vector3(pos1.x + runtimeRangeMinHeight, pos1.y + itemWidth / 2 + radius);
606  return local.x >= cpos.x - radius && local.x <= cpos.x + radius &&
607  local.y >= cpos.y - radius && local.y <= cpos.y + radius;
608  }
609  }
610 
611  public bool IsInRangeMaxRect(Vector3 local, Rect chartRect, float triangleLen)
612  {
613  var centerPos = new Vector3(chartRect.x, chartRect.y) + location.GetPosition(chartRect.width, chartRect.height);
614  if (orient == Orient.Vertical)
615  {
616  var radius = triangleLen / 2;
617  var pos1 = centerPos + Vector3.down * itemHeight / 2;
618  var cpos = new Vector3(pos1.x + itemWidth / 2 + radius, pos1.y + runtimeRangeMaxHeight + radius);
619 
620  return local.x >= cpos.x - radius && local.x <= cpos.x + radius &&
621  local.y >= cpos.y - radius && local.y <= cpos.y + radius;
622  }
623  else
624  {
625  var radius = triangleLen / 2;
626  var pos1 = centerPos + Vector3.left * itemHeight / 2;
627  var cpos = new Vector3(pos1.x + runtimeRangeMaxHeight + radius, pos1.y + itemWidth / 2 + radius);
628  return local.x >= cpos.x - radius && local.x <= cpos.x + radius &&
629  local.y >= cpos.y - radius && local.y <= cpos.y + radius;
630  }
631  }
632  }
633 
634  internal class VisualMapHandler : IComponentHandler
635  {
636  public BaseChart chart;
637 
638  public VisualMapHandler(BaseChart chart)
639  {
640  this.chart = chart;
641  }
642 
643  public void Init() { }
644  public void OnBeginDrag(PointerEventData eventData)
645  {
646  foreach (var visualMap in chart.visualMaps)
647  {
648  OnDragVisualMapStart(visualMap);
649  }
650  }
651  public void OnDrag(PointerEventData eventData)
652  {
653  foreach (var visualMap in chart.visualMaps)
654  {
655  OnDragVisualMap(visualMap);
656  }
657  }
658 
659  public void OnEndDrag(PointerEventData eventData)
660  {
661  foreach (var visualMap in chart.visualMaps)
662  {
663  OnDragVisualMapEnd(visualMap);
664  }
665  }
666  public void OnPointerDown(PointerEventData eventData) { }
667  public void OnScroll(PointerEventData eventData) { }
668 
669  public void Update()
670  {
671  foreach (var visualMap in chart.visualMaps)
672  {
673  CheckVisualMap(visualMap);
674  }
675  }
676 
677  public void DrawBase(VertexHelper vh)
678  {
679  foreach (var visualMap in chart.visualMaps)
680  {
681  if (!visualMap.enable || !visualMap.show) continue;
682  switch (visualMap.type)
683  {
684  case VisualMap.Type.Continuous:
685  DrawContinuousVisualMap(vh, visualMap);
686  break;
687  case VisualMap.Type.Piecewise:
688  //DrawPiecewiseVisualMap(vh, visualMap);
689  break;
690  }
691  }
692  }
693 
694  public void DrawTop(VertexHelper vh)
695  {
696  }
697 
698  private void CheckVisualMap(VisualMap visualMap)
699  {
700  if (visualMap == null || !visualMap.enable || !visualMap.show) return;
701  Vector2 local;
702  if (chart.canvas == null) return;
703 
704  if (!chart.ScreenPointToChartPoint(Input.mousePosition, out local))
705  {
706  if (visualMap.runtimeSelectedIndex >= 0)
707  {
708  visualMap.runtimeSelectedIndex = -1;
709  chart.RefreshChart();
710  }
711  return;
712  }
713  if (local.x < chart.chartX || local.x > chart.chartX + chart.chartWidth ||
714  local.y < chart.chartY || local.y > chart.chartY + chart.chartHeight ||
715  !visualMap.IsInRangeRect(local, chart.chartRect))
716  {
717  if (visualMap.runtimeSelectedIndex >= 0)
718  {
719  visualMap.runtimeSelectedIndex = -1;
720  chart.RefreshChart();
721  }
722  return;
723  }
724  var pos1 = Vector3.zero;
725  var pos2 = Vector3.zero;
726  var halfHig = visualMap.itemHeight / 2;
727  var centerPos = chart.chartPosition + visualMap.location.GetPosition(chart.chartWidth, chart.chartHeight);
728  var selectedIndex = -1;
729  double value = 0;
730  switch (visualMap.orient)
731  {
732  case Orient.Horizonal:
733  pos1 = centerPos + Vector3.left * halfHig;
734  pos2 = centerPos + Vector3.right * halfHig;
735  value = visualMap.min + (local.x - pos1.x) / (pos2.x - pos1.x) * (visualMap.max - visualMap.min);
736  selectedIndex = visualMap.GetIndex(value);
737  break;
738  case Orient.Vertical:
739  pos1 = centerPos + Vector3.down * halfHig;
740  pos2 = centerPos + Vector3.up * halfHig;
741  value = visualMap.min + (local.y - pos1.y) / (pos2.y - pos1.y) * (visualMap.max - visualMap.min);
742  selectedIndex = visualMap.GetIndex(value);
743  break;
744  }
745  visualMap.runtimeSelectedValue = value;
746  visualMap.runtimeSelectedIndex = selectedIndex;
747  chart.RefreshChart();
748  }
749 
750  private void DrawContinuousVisualMap(VertexHelper vh, VisualMap visualMap)
751  {
752  var centerPos = chart.chartPosition + visualMap.location.GetPosition(chart.chartWidth, chart.chartHeight);
753  var pos1 = Vector3.zero;
754  var pos2 = Vector3.zero;
755  var dir = Vector3.zero;
756  var halfWid = visualMap.itemWidth / 2;
757  var halfHig = visualMap.itemHeight / 2;
758  var xRadius = 0f;
759  var yRadius = 0f;
760  var splitNum = visualMap.runtimeInRange.Count;
761  var splitWid = visualMap.itemHeight / (splitNum - 1);
762  var isVertical = false;
763  var colors = visualMap.runtimeInRange;
764  var triangeLen = chart.theme.visualMap.triangeLen;
765  switch (visualMap.orient)
766  {
767  case Orient.Horizonal:
768  pos1 = centerPos + Vector3.left * halfHig;
769  pos2 = centerPos + Vector3.right * halfHig;
770  dir = Vector3.right;
771  xRadius = splitWid / 2;
772  yRadius = halfWid;
773  isVertical = false;
774  if (visualMap.calculable)
775  {
776  var p0 = pos1 + Vector3.right * visualMap.runtimeRangeMinHeight;
777  var p1 = p0 + Vector3.up * halfWid;
778  var p2 = p0 + Vector3.up * (halfWid + triangeLen);
779  var p3 = p2 + Vector3.left * triangeLen;
780  var color = visualMap.GetColor(visualMap.rangeMin);
781  UGL.DrawTriangle(vh, p1, p2, p3, color);
782  p0 = pos1 + Vector3.right * visualMap.runtimeRangeMaxHeight;
783  p1 = p0 + Vector3.up * halfWid;
784  p2 = p0 + Vector3.up * (halfWid + triangeLen);
785  p3 = p2 + Vector3.right * triangeLen;
786  color = visualMap.GetColor(visualMap.rangeMax);
787  UGL.DrawTriangle(vh, p1, p2, p3, color);
788  }
789  break;
790  case Orient.Vertical:
791  pos1 = centerPos + Vector3.down * halfHig;
792  pos2 = centerPos + Vector3.up * halfHig;
793  dir = Vector3.up;
794  xRadius = halfWid;
795  yRadius = splitWid / 2;
796  isVertical = true;
797  if (visualMap.calculable)
798  {
799  var p0 = pos1 + Vector3.up * visualMap.runtimeRangeMinHeight;
800  var p1 = p0 + Vector3.right * halfWid;
801  var p2 = p0 + Vector3.right * (halfWid + triangeLen);
802  var p3 = p2 + Vector3.down * triangeLen;
803  var color = visualMap.GetColor(visualMap.rangeMin);
804  UGL.DrawTriangle(vh, p1, p2, p3, color);
805  p0 = pos1 + Vector3.up * visualMap.runtimeRangeMaxHeight;
806  p1 = p0 + Vector3.right * halfWid;
807  p2 = p0 + Vector3.right * (halfWid + triangeLen);
808  p3 = p2 + Vector3.up * triangeLen;
809  color = visualMap.GetColor(visualMap.rangeMax);
810  UGL.DrawTriangle(vh, p1, p2, p3, color);
811  }
812  break;
813  }
814  if (visualMap.calculable && (visualMap.rangeMin > visualMap.min
815  || visualMap.rangeMax < visualMap.max))
816  {
817  var rangeMin = visualMap.rangeMin;
818  var rangeMax = visualMap.rangeMax;
819  var diff = (visualMap.max - visualMap.min) / (splitNum - 1);
820  for (int i = 1; i < splitNum; i++)
821  {
822  var splitMin = visualMap.min + (i - 1) * diff;
823  var splitMax = splitMin + diff;
824  if (rangeMin > splitMax || rangeMax < splitMin)
825  {
826  continue;
827  }
828  else if (rangeMin <= splitMin && rangeMax >= splitMax)
829  {
830  var splitPos = pos1 + dir * (i - 1 + 0.5f) * splitWid;
831  var startColor = colors[i - 1];
832  var toColor = visualMap.IsPiecewise() ? startColor : colors[i];
833  UGL.DrawRectangle(vh, splitPos, xRadius, yRadius, startColor, toColor, isVertical);
834  }
835  else if (rangeMin > splitMin && rangeMax >= splitMax)
836  {
837  var p0 = pos1 + dir * visualMap.runtimeRangeMinHeight;
838  var splitMaxPos = pos1 + dir * i * splitWid;
839  var splitPos = p0 + (splitMaxPos - p0) / 2;
840  var startColor = visualMap.GetColor(visualMap.rangeMin);
841  var toColor = visualMap.IsPiecewise() ? startColor : colors[i];
842  var yRadius1 = Vector3.Distance(p0, splitMaxPos) / 2;
843  if (visualMap.orient == Orient.Vertical)
844  UGL.DrawRectangle(vh, splitPos, xRadius, yRadius1, startColor, toColor, isVertical);
845  else
846  UGL.DrawRectangle(vh, splitPos, yRadius1, yRadius, startColor, toColor, isVertical);
847  }
848  else if (rangeMax < splitMax && rangeMin <= splitMin)
849  {
850  var p0 = pos1 + dir * visualMap.runtimeRangeMaxHeight;
851  var splitMinPos = pos1 + dir * (i - 1) * splitWid;
852  var splitPos = splitMinPos + (p0 - splitMinPos) / 2;
853  var startColor = colors[i - 1];
854  var toColor = visualMap.IsPiecewise() ? startColor : visualMap.GetColor(visualMap.rangeMax);
855  var yRadius1 = Vector3.Distance(p0, splitMinPos) / 2;
856  if (visualMap.orient == Orient.Vertical)
857  UGL.DrawRectangle(vh, splitPos, xRadius, yRadius1, startColor, toColor, isVertical);
858  else
859  UGL.DrawRectangle(vh, splitPos, yRadius1, yRadius, startColor, toColor, isVertical);
860  }
861  else
862  {
863  var p0 = pos1 + dir * visualMap.runtimeRangeMinHeight;
864  var p1 = pos1 + dir * visualMap.runtimeRangeMaxHeight;
865  var splitPos = (p0 + p1) / 2;
866  var startColor = visualMap.GetColor(visualMap.rangeMin);
867  var toColor = visualMap.GetColor(visualMap.rangeMax);
868  var yRadius1 = Vector3.Distance(p0, p1) / 2;
869  if (visualMap.orient == Orient.Vertical)
870  UGL.DrawRectangle(vh, splitPos, xRadius, yRadius1, startColor, toColor, isVertical);
871  else
872  UGL.DrawRectangle(vh, splitPos, yRadius1, yRadius, startColor, toColor, isVertical);
873  }
874  }
875  }
876  else
877  {
878  for (int i = 1; i < splitNum; i++)
879  {
880  var splitPos = pos1 + dir * (i - 1 + 0.5f) * splitWid;
881  var startColor = colors[i - 1];
882  var toColor = visualMap.IsPiecewise() ? startColor : colors[i];
883  UGL.DrawRectangle(vh, splitPos, xRadius, yRadius, startColor, toColor, isVertical);
884  }
885  }
886 
887  if (visualMap.rangeMin > visualMap.min)
888  {
889  var p0 = pos1 + dir * visualMap.runtimeRangeMinHeight;
890  UGL.DrawRectangle(vh, pos1, p0, visualMap.itemWidth / 2, chart.theme.visualMap.backgroundColor);
891  }
892  if (visualMap.rangeMax < visualMap.max)
893  {
894  var p1 = pos1 + dir * visualMap.runtimeRangeMaxHeight;
895  UGL.DrawRectangle(vh, p1, pos2, visualMap.itemWidth / 2, chart.theme.visualMap.backgroundColor);
896  }
897 
898  if (visualMap.hoverLink)
899  {
900  if (visualMap.runtimeSelectedIndex >= 0)
901  {
902  var p0 = pos1 + dir * visualMap.runtimeRangeMinHeight;
903  var p1 = pos1 + dir * visualMap.runtimeRangeMaxHeight;
904  var pointerPos = chart.pointerPos;
905  if (visualMap.orient == Orient.Vertical)
906  {
907  var p2 = new Vector3(centerPos.x + halfWid, Mathf.Clamp(pointerPos.y + (triangeLen / 2), p0.y, p1.y));
908  var p3 = new Vector3(centerPos.x + halfWid, Mathf.Clamp(pointerPos.y - (triangeLen / 2), p0.y, p1.y));
909  var p4 = new Vector3(centerPos.x + halfWid + triangeLen / 2, pointerPos.y);
910  UGL.DrawTriangle(vh, p2, p3, p4, colors[visualMap.runtimeSelectedIndex]);
911  }
912  else
913  {
914  var p2 = new Vector3(Mathf.Clamp(pointerPos.x + (triangeLen / 2), p0.x, p1.x), centerPos.y + halfWid);
915  var p3 = new Vector3(Mathf.Clamp(pointerPos.x - (triangeLen / 2), p0.x, p1.x), centerPos.y + halfWid);
916  var p4 = new Vector3(pointerPos.x, centerPos.y + halfWid + triangeLen / 2);
917  UGL.DrawTriangle(vh, p2, p3, p4, colors[visualMap.runtimeSelectedIndex]);
918  }
919  }
920  }
921  }
922  private void DrawPiecewiseVisualMap(VertexHelper vh, VisualMap visualMap)
923  {
924  var centerPos = chart.chartPosition + visualMap.location.GetPosition(chart.chartWidth, chart.chartHeight);
925  var pos1 = Vector3.zero;
926  var pos2 = Vector3.zero;
927  var dir = Vector3.zero;
928  var halfWid = visualMap.itemWidth / 2;
929  var halfHig = visualMap.itemHeight / 2;
930  var splitNum = visualMap.runtimeInRange.Count;
931  var colors = visualMap.runtimeInRange;
932  switch (visualMap.orient)
933  {
934  case Orient.Horizonal:
935  for (int i = 0; i < visualMap.pieces.Count; i++)
936  {
937  var piece = visualMap.pieces[i];
938 
939  }
940  break;
941  case Orient.Vertical:
942  var each = visualMap.itemHeight + visualMap.itemGap;
943  for (int i = 0; i < visualMap.pieces.Count; i++)
944  {
945  var piece = visualMap.pieces[i];
946  var pos = new Vector3(centerPos.x, centerPos.y - each * i);
947  UGL.DrawRectangle(vh, pos, halfWid, halfHig, piece.color);
948  }
949  break;
950  }
951  }
952 
953  protected void OnDragVisualMapStart(VisualMap visualMap)
954  {
955  if (!visualMap.enable || !visualMap.show || !visualMap.calculable) return;
956  var inMinRect = visualMap.IsInRangeMinRect(chart.pointerPos, chart.chartRect, chart.theme.visualMap.triangeLen);
957  var inMaxRect = visualMap.IsInRangeMaxRect(chart.pointerPos, chart.chartRect, chart.theme.visualMap.triangeLen);
958  if (inMinRect || inMaxRect)
959  {
960  if (inMinRect)
961  {
962  visualMap.runtimeMinDrag = true;
963  }
964  else
965  {
966  visualMap.runtimeMaxDrag = true;
967  }
968  }
969  }
970 
971  protected void OnDragVisualMap(VisualMap visualMap)
972  {
973  if (!visualMap.enable || !visualMap.show || !visualMap.calculable) return;
974  if (!visualMap.runtimeMinDrag && !visualMap.runtimeMaxDrag) return;
975 
976  var value = visualMap.GetValue(chart.pointerPos, chart.chartRect);
977  if (visualMap.runtimeMinDrag)
978  {
979  visualMap.rangeMin = value;
980  }
981  else
982  {
983  visualMap.rangeMax = value;
984  }
985  chart.RefreshChart();
986  }
987 
988  protected void OnDragVisualMapEnd(VisualMap visualMap)
989  {
990  if (!visualMap.enable || !visualMap.show || !visualMap.calculable) return;
991  if (visualMap.runtimeMinDrag || visualMap.runtimeMaxDrag)
992  {
993  chart.RefreshChart();
994  visualMap.runtimeMinDrag = false;
995  visualMap.runtimeMaxDrag = false;
996  }
997  }
998  }
999 }
XCharts.VisualMap.location
Location location
The location of component. 组件显示的位置。
Definition: VisualMap.cs:310
XCharts.Orient
Orient
the layout is horizontal or vertical. 垂直还是水平布局方式。
Definition: BaseChart.cs:22
XCharts.RadarType.Single
@ Single
单圈雷达图。此时一个雷达只能绘制一个圈,多个serieData组成一个圈,数据取自data[1]。
XCharts.VisualMap.range
double[] range
Specifies the position of the numeric value corresponding to the handle. Range should be within the r...
Definition: VisualMap.cs:179
XCharts.RadarType.Multiple
@ Multiple
多圈雷达图。此时可一个雷达里绘制多个圈,一个serieData就可组成一个圈(多维数据)。
XCharts.VisualMap.outOfRange
List< Color32 > outOfRange
Defines a visual color outside of the selected range. 定义 在选中范围外 的视觉颜色。
Definition: VisualMap.cs:328
XCharts.Location.GetPosition
Vector3 GetPosition(float chartWidth, float chartHeight)
返回在坐标系中的具体位置
Definition: Location.cs:283
XCharts.VisualMap
VisualMap component. Mapping data to visual elements such as colors. 视觉映射组件。用于进行『视觉编码』,也就是将数据映射到视觉元素(...
Definition: VisualMap.cs:21
XCharts.VisualMap.itemGap
float itemGap
每个图元之间的间隔距离。
Definition: VisualMap.cs:246
XCharts.VisualMap.Pieces
Definition: VisualMap.cs:54
XCharts.VisualMap.inRange
List< Color32 > inRange
Defines the visual color in the selected range. 定义 在选中范围中 的视觉颜色。
Definition: VisualMap.cs:319
XCharts.VisualMap.text
string[] text
Text on both ends. 两端的文本,如 ['High', 'Low']。
Definition: VisualMap.cs:184
XCharts.Location
Location type. Quick to set the general location. 位置类型。通过Align快速设置大体位置,再通过left,right,top,bottom微调具体位置...
Definition: Location.cs:21
XCharts.VisualMap.autoMinMax
bool autoMinMax
Automatically set min, Max value 自动设置min,max的值
Definition: VisualMap.cs:291
XCharts.VisualMap.selectedMode
SelectedMode selectedMode
the selected mode for Piecewise visualMap. 选择模式。
Definition: VisualMap.cs:150
XCharts.VisualMap.itemWidth
float itemWidth
The width of the figure, that is, the width of the color bar.
Definition: VisualMap.cs:228
XCharts.VisualMap.min
double min
The minimum allowed. 'min' must be user specified. [visualmap.min, visualmap.max] forms the "domain" ...
Definition: VisualMap.cs:160
XCharts.MainComponent
Definition: ChartComponent.cs:67
XCharts.ChartComponent.anyDirty
bool anyDirty
需要重绘图表或重新初始化组件。
Definition: ChartComponent.cs:29
XCharts.VisualMap.realtime
bool realtime
Whether to update in real time while dragging.
Definition: VisualMap.cs:218
XCharts.VisualMap.runtimePointerPos
Vector2 runtimePointerPos
the current pointer position. 当前鼠标位置。
Definition: VisualMap.cs:364
XCharts
Definition: RewardChart.cs:14
XCharts.VisualMap.max
double? max
The maximum allowed. 'max' must be user specified. [visualmap.min, visualmap.max] forms the "domain" ...
Definition: VisualMap.cs:170
XCharts.VisualMap.splitNumber
int splitNumber
For continuous data, it is automatically evenly divided into several segments and automatically match...
Definition: VisualMap.cs:198
XCharts.VisualMap.enable
bool enable
Whether enable visualMap component.
Definition: VisualMap.cs:120
XCharts.VisualMap.Type
Type
类型。分为连续型和分段型。
Definition: VisualMap.cs:26
XCharts.VisualMap.show
bool show
Whether to display components. If set to false, it will not show up, but the data mapping function st...
Definition: VisualMap.cs:132
XCharts.VisualMap.hoverLink
bool hoverLink
When the hoverLink function is turned on, when the mouse hovers over the visualMap component,...
Definition: VisualMap.cs:282
XCharts.VisualMap.Pieces.max
double max
范围最大值
Definition: VisualMap.cs:68
XUGL
Definition: UGL.cs:12
XCharts.VisualMap.type
Type type
the type of visualmap component. 组件类型。
Definition: VisualMap.cs:141
XCharts.VisualMap.runtimeSelectedIndex
int runtimeSelectedIndex
鼠标悬停选中的index
Definition: VisualMap.cs:358
XCharts.VisualMap.itemHeight
float itemHeight
The height of the figure, that is, the height of the color bar.
Definition: VisualMap.cs:238
XCharts.VisualMap.calculable
bool calculable
Whether the handle used for dragging is displayed (the handle can be dragged to adjust the selected r...
Definition: VisualMap.cs:208
XCharts.VisualMap.textGap
float[] textGap
The distance between the two text bodies. 两端文字主体之间的距离,单位为px。
Definition: VisualMap.cs:189
XCharts.VisualMap.orient
Orient orient
Specify whether the layout of component is horizontal or vertical.
Definition: VisualMap.cs:301
XCharts.VisualMap.pieces
List< Pieces > pieces
分段式每一段的相关配置。
Definition: VisualMap.cs:336
XCharts.VisualMap.Pieces.color
Color32 color
颜色
Definition: VisualMap.cs:76
XCharts.VisualMap.dimension
int dimension
Specifies "which dimension" of the data to map to the visual element. "Data" is series....
Definition: VisualMap.cs:267
XCharts.VisualMap.SelectedMode
SelectedMode
选择模式
Definition: VisualMap.cs:41
XCharts.VisualMap.Pieces.label
string label
文字描述
Definition: VisualMap.cs:72
XCharts.VisualMap.Pieces.min
double min
范围最小值
Definition: VisualMap.cs:64
XCharts.VisualMap.borderWidth
float borderWidth
Border line width.
Definition: VisualMap.cs:256