Files
XCharts/Runtime/Internal/DrawSerieLiquid.cs
2021-07-08 07:20:06 +08:00

435 lines
18 KiB
C#

/************************************************/
/* */
/* Copyright (c) 2018 - 2021 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/************************************************/
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using XUGL;
namespace XCharts
{
internal class DrawSerieLiquid : IDrawSerie
{
public BaseChart chart;
private bool m_UpdateLabelText = false;
public DrawSerieLiquid(BaseChart chart)
{
this.chart = chart;
}
public void InitComponent()
{
//UpdateRuntimeData();
//SerieLabelHelper.UpdateLabelText(chart.series, chart.theme, m_LegendRealShowName);
}
public void CheckComponent()
{
}
public void Update()
{
if (m_UpdateLabelText)
{
m_UpdateLabelText = false;
foreach (var serie in chart.series.list)
{
if (serie.type == SerieType.Liquid)
{
var colorIndex = chart.m_LegendRealShowName.IndexOf(serie.name);
SerieLabelHelper.SetLiquidLabelText(serie, chart.theme, colorIndex);
}
}
}
}
public void DrawBase(VertexHelper vh)
{
}
public void DrawSerie(VertexHelper vh, Serie serie)
{
if (serie.type != SerieType.Liquid) return;
UpdateRuntimeData(serie);
DrawVesselBackground(vh, serie);
DrawLiquid(vh, serie);
DrawVessel(vh, serie);
}
public void RefreshLabel()
{
}
public bool CheckTootipArea(Vector2 local)
{
return false;
}
public bool OnLegendButtonClick(int index, string legendName, bool show)
{
return false;
}
public bool OnLegendButtonEnter(int index, string legendName)
{
return false;
}
public bool OnLegendButtonExit(int index, string legendName)
{
return false;
}
public void OnPointerDown(PointerEventData eventData)
{
}
private void UpdateRuntimeData()
{
foreach (var vessel in chart.vessels)
{
VesselHelper.UpdateVesselCenter(vessel, chart.chartPosition, chart.chartWidth, chart.chartHeight);
}
}
private void UpdateRuntimeData(Serie serie)
{
var vessel = chart.GetVessel(serie.vesselIndex);
if (vessel != null)
{
VesselHelper.UpdateVesselCenter(vessel, chart.chartPosition, chart.chartWidth, chart.chartHeight);
}
}
private void DrawVesselBackground(VertexHelper vh, Serie serie)
{
var vessel = chart.GetVessel(serie.vesselIndex);
if (vessel != null)
{
if (vessel.backgroundColor.a != 0)
{
switch (vessel.shape)
{
case Vessel.Shape.Circle:
var cenPos = vessel.runtimeCenterPos;
var radius = vessel.runtimeRadius;
UGL.DrawCricle(vh, cenPos, vessel.runtimeInnerRadius + vessel.gap, vessel.backgroundColor,
chart.settings.cicleSmoothness);
UGL.DrawDoughnut(vh, cenPos, vessel.runtimeInnerRadius, vessel.runtimeInnerRadius + vessel.gap,
vessel.backgroundColor, Color.clear, chart.settings.cicleSmoothness);
break;
case Vessel.Shape.Rect:
UGL.DrawRectangle(vh, vessel.runtimeCenterPos, vessel.runtimeWidth / 2, vessel.runtimeHeight / 2,
vessel.backgroundColor);
break;
default:
break;
}
}
}
}
private void DrawVessel(VertexHelper vh, Serie serie)
{
var vessel = chart.GetVessel(serie.vesselIndex);
if (vessel != null)
{
switch (vessel.shape)
{
case Vessel.Shape.Circle:
DrawCirleVessel(vh, vessel);
break;
case Vessel.Shape.Rect:
DrawRectVessel(vh, vessel);
break;
default:
DrawCirleVessel(vh, vessel);
break;
}
}
}
private void DrawCirleVessel(VertexHelper vh, Vessel vessel)
{
var cenPos = vessel.runtimeCenterPos;
var radius = vessel.runtimeRadius;
var serie = SeriesHelper.GetSerieByVesselIndex(chart.series, vessel.index);
var vesselColor = VesselHelper.GetColor(vessel, serie, chart.theme, chart.m_LegendRealShowName);
if (vessel.gap != 0)
{
UGL.DrawDoughnut(vh, cenPos, vessel.runtimeInnerRadius, vessel.runtimeInnerRadius + vessel.gap,
vessel.backgroundColor, Color.clear, chart.settings.cicleSmoothness);
}
UGL.DrawDoughnut(vh, cenPos, radius - vessel.shapeWidth, radius, vesselColor, Color.clear,
chart.settings.cicleSmoothness);
}
private void DrawRectVessel(VertexHelper vh, Vessel vessel)
{
var serie = SeriesHelper.GetSerieByVesselIndex(chart.series, vessel.index);
var vesselColor = VesselHelper.GetColor(vessel, serie, chart.theme, chart.m_LegendRealShowName);
if (vessel.gap != 0)
{
UGL.DrawBorder(vh, vessel.runtimeCenterPos, vessel.runtimeWidth,
vessel.runtimeHeight, vessel.gap, vessel.backgroundColor, 0, vessel.cornerRadius);
}
UGL.DrawBorder(vh, vessel.runtimeCenterPos, vessel.runtimeWidth + 2 * vessel.gap,
vessel.runtimeHeight + 2 * vessel.gap, vessel.shapeWidth, vesselColor, 0, vessel.cornerRadius);
}
private void DrawLiquid(VertexHelper vh, Serie serie)
{
if (!serie.show) return;
if (serie.animation.HasFadeOut()) return;
var vessel = chart.GetVessel(serie.vesselIndex);
if (vessel == null) return;
switch (vessel.shape)
{
case Vessel.Shape.Circle:
DrawCirleLiquid(vh, serie, vessel);
break;
case Vessel.Shape.Rect:
DrawRectLiquid(vh, serie, vessel);
break;
default:
DrawCirleLiquid(vh, serie, vessel);
break;
}
}
private void DrawCirleLiquid(VertexHelper vh, Serie serie, Vessel vessel)
{
var cenPos = vessel.runtimeCenterPos;
var radius = vessel.runtimeInnerRadius;
var serieData = serie.GetSerieData(0);
if (serieData == null) return;
var dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
var value = serieData.GetCurrData(1, dataChangeDuration);
if (serie.runtimeCheckValue != value)
{
serie.runtimeCheckValue = value;
m_UpdateLabelText = true;
}
if (serieData.labelPosition != cenPos)
{
serieData.labelPosition = cenPos;
m_UpdateLabelText = true;
}
if (value <= 0) return;
var colorIndex = chart.m_LegendRealShowName.IndexOf(serie.name);
var realHig = (float)((value - serie.min) / (serie.max - serie.min) * radius * 2);
serie.animation.InitProgress(1, 0, realHig);
var hig = serie.animation.IsFinish() ? realHig : serie.animation.GetCurrDetail();
var a = Mathf.Abs(radius - hig + (hig > radius ? serie.waveHeight : -serie.waveHeight));
var diff = Mathf.Sqrt(radius * radius - Mathf.Pow(a, 2));
var color = SerieHelper.GetItemColor(serie, serieData, chart.theme, colorIndex, false);
var toColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, colorIndex, false);
var isNeedGradient = !ChartHelper.IsValueEqualsColor(color, toColor);
var isFull = hig >= 2 * radius;
if (hig >= 2 * radius) hig = 2 * radius;
if (isFull && !isNeedGradient)
{
UGL.DrawCricle(vh, cenPos, radius, toColor, chart.settings.cicleSmoothness);
}
else
{
var startY = cenPos.y - radius + hig;
var waveStartPos = new Vector3(cenPos.x - diff, startY);
var waveEndPos = new Vector3(cenPos.x + diff, startY);
var startX = hig > radius ? cenPos.x - radius : waveStartPos.x;
var endX = hig > radius ? cenPos.x + radius : waveEndPos.x;
var step = vessel.smoothness;
if (step < 0.5f) step = 0.5f;
var lup = hig > radius ? new Vector3(cenPos.x - radius, cenPos.y) : waveStartPos;
var ldp = lup;
var nup = Vector3.zero;
var ndp = Vector3.zero;
var angle = 0f;
serie.runtimeWaveSpeed += serie.waveSpeed * Time.deltaTime;
var isStarted = false;
var isEnded = false;
var waveHeight = isFull ? 0 : serie.waveHeight;
while (startX < endX)
{
startX += step;
if (startX > endX) startX = endX;
if (startX > waveStartPos.x && !isStarted)
{
startX = waveStartPos.x;
isStarted = true;
}
if (startX > waveEndPos.x && !isEnded)
{
startX = waveEndPos.x;
isEnded = true;
}
var py = Mathf.Sqrt(Mathf.Pow(radius, 2) - Mathf.Pow(Mathf.Abs(cenPos.x - startX), 2));
if (startX < waveStartPos.x || startX > waveEndPos.x)
{
nup = new Vector3(startX, cenPos.y + py);
}
else
{
var py2 = waveHeight * Mathf.Sin(1 / serie.waveLength * angle + serie.runtimeWaveSpeed + serie.waveOffset);
var nupY = waveStartPos.y + py2;
if (nupY > cenPos.y + py) nupY = cenPos.y + py;
else if (nupY < cenPos.y - py) nupY = cenPos.y - py;
nup = new Vector3(startX, nupY);
angle += step;
}
ndp = new Vector3(startX, cenPos.y - py);
if (!ChartHelper.IsValueEqualsColor(color, toColor))
{
var colorMin = cenPos.y - radius;
var colorMax = startY + serie.waveHeight;
var tcolor1 = Color32.Lerp(color, toColor, 1 - (lup.y - colorMin) / (colorMax - colorMin));
var tcolor2 = Color32.Lerp(color, toColor, 1 - (ldp.y - colorMin) / (colorMax - colorMin));
UGL.DrawQuadrilateral(vh, lup, nup, ndp, ldp, tcolor1, tcolor2);
}
else
{
UGL.DrawQuadrilateral(vh, lup, nup, ndp, ldp, color);
}
lup = nup;
ldp = ndp;
}
}
if (serie.waveSpeed != 0 && Application.isPlaying && !isFull)
{
chart.RefreshPainter(serie);
}
if (!serie.animation.IsFinish())
{
serie.animation.CheckProgress(realHig);
chart.m_IsPlayingAnimation = true;
chart.RefreshPainter(serie);
}
}
private void DrawRectLiquid(VertexHelper vh, Serie serie, Vessel vessel)
{
var cenPos = vessel.runtimeCenterPos;
var serieData = serie.GetSerieData(0);
if (serieData == null) return;
var dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
var value = serieData.GetCurrData(1, dataChangeDuration);
if (serie.runtimeCheckValue != value)
{
serie.runtimeCheckValue = value;
m_UpdateLabelText = true;
}
if (serieData.labelPosition != cenPos)
{
serieData.labelPosition = cenPos;
m_UpdateLabelText = true;
}
if (value <= 0) return;
var colorIndex = chart.m_LegendRealShowName.IndexOf(serie.name);
var realHig = (value - serie.min) / (serie.max - serie.min) * vessel.runtimeHeight;
serie.animation.InitProgress(1, 0, (float)realHig);
var hig = serie.animation.IsFinish() ? realHig : serie.animation.GetCurrDetail();
var color = SerieHelper.GetItemColor(serie, serieData, chart.theme, colorIndex, false);
var toColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, colorIndex, false);
var isNeedGradient = !ChartHelper.IsValueEqualsColor(color, toColor);
var isFull = hig >= vessel.runtimeHeight;
if (hig >= vessel.runtimeHeight) hig = vessel.runtimeHeight;
if (isFull && !isNeedGradient)
{
UGL.DrawRectangle(vh, cenPos, vessel.runtimeWidth / 2, vessel.runtimeHeight / 2, toColor);
}
else
{
var startY = (float)(cenPos.y - vessel.runtimeHeight / 2 + hig);
var waveStartPos = new Vector3(cenPos.x - vessel.runtimeWidth / 2, startY);
var waveEndPos = new Vector3(cenPos.x + vessel.runtimeWidth / 2, startY);
var startX = waveStartPos.x;
var endX = waveEndPos.x;
var step = vessel.smoothness;
if (step < 0.5f) step = 0.5f;
var lup = waveStartPos;
var ldp = new Vector3(startX, vessel.runtimeCenterPos.y - vessel.runtimeHeight / 2);
var nup = Vector3.zero;
var ndp = Vector3.zero;
var angle = 0f;
var isStarted = false;
var isEnded = false;
var waveHeight = isFull ? 0 : serie.waveHeight;
serie.runtimeWaveSpeed += serie.waveSpeed * Time.deltaTime;
while (startX < endX)
{
startX += step;
if (startX > endX) startX = endX;
if (startX > waveStartPos.x && !isStarted)
{
startX = waveStartPos.x;
isStarted = true;
}
if (startX > waveEndPos.x && !isEnded)
{
startX = waveEndPos.x;
isEnded = true;
}
var py = Mathf.Sqrt(Mathf.Pow(vessel.runtimeHeight, 2) - Mathf.Pow(Mathf.Abs(cenPos.x - startX), 2));
if (startX < waveStartPos.x || startX > waveEndPos.x)
{
nup = new Vector3(startX, cenPos.y + py);
}
else
{
var py2 = waveHeight * Mathf.Sin(1 / serie.waveLength * angle + serie.runtimeWaveSpeed + serie.waveOffset);
var nupY = waveStartPos.y + py2;
nup = new Vector3(startX, nupY);
angle += step;
}
ndp = new Vector3(startX, cenPos.y - vessel.runtimeHeight / 2);
if (nup.y > cenPos.y + vessel.runtimeHeight / 2)
{
nup.y = cenPos.y + vessel.runtimeHeight / 2;
}
if (nup.y < cenPos.y - vessel.runtimeHeight / 2)
{
nup.y = cenPos.y - vessel.runtimeHeight / 2;
}
if (!ChartHelper.IsValueEqualsColor(color, toColor))
{
var colorMin = cenPos.y - vessel.runtimeHeight;
var colorMax = startY + serie.waveHeight;
var tcolor1 = Color32.Lerp(color, toColor, 1 - (lup.y - colorMin) / (colorMax - colorMin));
var tcolor2 = Color32.Lerp(color, toColor, 1 - (ldp.y - colorMin) / (colorMax - colorMin));
UGL.DrawQuadrilateral(vh, lup, nup, ndp, ldp, tcolor1, tcolor2);
}
else
{
UGL.DrawQuadrilateral(vh, lup, nup, ndp, ldp, color);
}
lup = nup;
ldp = ndp;
}
}
if (serie.waveSpeed != 0 && Application.isPlaying && !isFull)
{
chart.RefreshPainter(serie);
}
if (!serie.animation.IsFinish())
{
serie.animation.CheckProgress(realHig);
chart.m_IsPlayingAnimation = true;
chart.RefreshPainter(serie);
}
}
}
}