--[[ Name: LibGraph-2.0 Revision: $Rev: 49 $ Author(s): Cryect (cryect@gmail.com), Xinhuan Website: http://www.wowace.com/ Documentation: http://www.wowace.com/wiki/GraphLib SVN: http://svn.wowace.com/root/trunk/GraphLib/ Description: Allows for easy creation of graphs ]] --Thanks to Nelson Minar for catching several errors where width was being used instead of height (damn copy and paste >_>) local major = "LibGraph-2.0" local minor = 90000 + tonumber(("$Revision: 49 $"):match("(%d+)")) -- hard coded path for TSM local TextureDirectory = "Interface\\AddOns\\TradeSkillMaster\\Libs\\LibGraph-2.0\\" if not LibStub then error(major .. " requires LibStub") end local lib, oldLibMinor = LibStub:NewLibrary(major, minor) if not lib then return end local GraphFunctions={} local tinsert, tremove = tinsert, tremove local pairs, ipairs = pairs, ipairs local math_max = math.max local math_min = math.min local math_ceil = math.ceil local math_pi = math.pi local math_floor = math.floor local math_pow = math.pow local math_random = math.random local math_cos = math.cos local math_sin = math.sin local math_deg = math.deg local math_atan = math.atan local math_abs = math.abs local math_fmod = math.fmod local math_huge = math.huge local GetTime = GetTime -- lib upgrade stuff lib.RegisteredGraphRealtime = lib.RegisteredGraphRealtime or {} lib.RegisteredGraphLine = lib.RegisteredGraphLine or {} lib.RegisteredGraphScatterPlot = lib.RegisteredGraphScatterPlot or {} lib.RegisteredGraphPieChart = lib.RegisteredGraphPieChart or {} -------------------------------------------------------------------------------- --Graph Creation Functions -------------------------------------------------------------------------------- --Realtime Graph local function SetupGraphRealtimeFunctions(graph, upgrade) local self = lib --Set the various functions graph.SetXAxis=GraphFunctions.SetXAxis graph.SetYMax=GraphFunctions.SetYMax graph.AddTimeData=GraphFunctions.AddTimeData graph.OnUpdate=GraphFunctions.OnUpdateGraphRealtime graph.CreateGridlines=GraphFunctions.CreateGridlines graph.RefreshGraph=GraphFunctions.RefreshRealtimeGraph graph.SetAxisDrawing=GraphFunctions.SetAxisDrawing graph.SetGridSpacing=GraphFunctions.SetGridSpacing graph.SetAxisColor=GraphFunctions.SetAxisColor graph.SetGridColor=GraphFunctions.SetGridColor graph.SetGridColorSecondary=GraphFunctions.SetGridColorSecondary graph.SetGridSecondaryMultiple=GraphFunctions.SetGridSecondaryMultiple graph.SetFilterRadius=GraphFunctions.SetFilterRadius --graph.SetAutoscaleYAxis=GraphFunctions.SetAutoscaleYAxis graph.SetBarColors=GraphFunctions.SetBarColors graph.SetMode=GraphFunctions.SetMode graph.SetAutoScale=GraphFunctions.SetAutoScale if not upgrade then -- This is the original frame:SetWidth() and frame:SetHeight() -- standard frame functions graph.OldSetWidth=graph.SetWidth graph.OldSetHeight=graph.SetHeight end graph.SetWidth=GraphFunctions.RealtimeSetWidth graph.SetHeight=GraphFunctions.RealtimeSetHeight graph.SetBarColors=GraphFunctions.RealtimeSetColors graph.GetMaxValue=GraphFunctions.GetMaxValue graph.GetValue=GraphFunctions.RealtimeGetValue graph.SetUpdateLimit=GraphFunctions.SetUpdateLimit graph.SetDecay=GraphFunctions.SetDecay graph.SetMinMaxY=GraphFunctions.SetMinMaxY graph.AddBar=GraphFunctions.AddBar graph.SetYLabels=GraphFunctions.SetYLabels graph.DrawLine=self.DrawLine graph.DrawHLine=self.DrawHLine graph.DrawVLine=self.DrawVLine graph.HideLines=self.HideLines graph.HideFontStrings=GraphFunctions.HideFontStrings graph.FindFontString=GraphFunctions.FindFontString graph.SetBars=GraphFunctions.SetBars --Set the update function graph:SetScript("OnUpdate", graph.OnUpdate) end function lib:CreateGraphRealtime(name,parent,relative,relativeTo,offsetX,offsetY,Width,Height) local graph local i graph = CreateFrame("Frame",name,parent) Width=math_floor(Width) graph:SetPoint(relative,parent,relativeTo,offsetX,offsetY) graph:SetWidth(Width) graph:SetHeight(Height) graph:Show() --Create the bars graph.Bars={} graph.BarsUsing={} graph.BarNum=Width graph.Height=Height for i=1,Width do local bar bar = CreateFrame("StatusBar",name.."Bar"..i,graph)--graph:CreateTexture(nil,"ARTWORK") bar:SetPoint("BOTTOMLEFT",graph,"BOTTOMLEFT",i-1,0) bar:SetHeight(Height) bar:SetWidth(1) bar:SetOrientation("VERTICAL") bar:SetMinMaxValues(0,1) bar:SetStatusBarTexture("Interface\\Buttons\\WHITE8X8.blp") bar:GetStatusBarTexture():SetHorizTile(false) bar:GetStatusBarTexture():SetVertTile(false) local t=bar:GetStatusBarTexture() t:SetGradientAlpha("VERTICAL",0.2,0.0,0.0,0.5,1.0,0.0,0.0,1.0) bar:Show() tinsert(graph.Bars,bar) tinsert(graph.BarsUsing,bar) end SetupGraphRealtimeFunctions(graph) --Initialize Data graph.GraphType="REALTIME" graph.YMax=60 graph.YMin=0 graph.XMax=-0.75 graph.XMin=-10 graph.TimeRadius=0.5 graph.Mode="FAST" graph.Filter="RECT" graph.AxisColor={1.0,1.0,1.0,1.0} graph.GridColor={0.5,0.5,0.5,0.5} graph.BarColorTop={1.0,0.0,0.0,1.0} graph.BarColorBot={0.2,0.0,0.0,0.5} graph.AutoScale=false graph.Data={} graph.MinMaxY=0 graph.CurVal=0 graph.LastDataTime=GetTime() graph.Textures={} graph.TexturesUsed={} graph.LimitUpdates=0 graph.NextUpdate=0 graph.BarHeight={} graph.LastShift=GetTime() graph.BarWidth=(graph.XMax-graph.XMin)/graph.BarNum graph.DecaySet=0.8 graph.Decay=math_pow(graph.DecaySet,graph.BarWidth) graph.ExpNorm=1/(1-graph.Decay) graph.FilterOverlap=math_max(math_ceil((graph.TimeRadius+graph.XMax)/graph.BarWidth),0) for i=1,graph.BarNum do graph.BarHeight[i]=0 end graph.TextFrame = CreateFrame("Frame",nil,graph) graph.TextFrame:SetAllPoints(graph) graph.TextFrame:SetFrameLevel(graph:GetFrameLevel()+2) tinsert(self.RegisteredGraphRealtime, graph) return graph end --Line Graph local function SetupGraphLineFunctions(graph) local self = lib --Set the various functions graph.SetXAxis=GraphFunctions.SetXAxis graph.SetYAxis=GraphFunctions.SetYAxis graph.AddDataSeries=GraphFunctions.AddDataSeries graph.AddFilledDataSeries=GraphFunctions.AddFilledDataSeries graph.ResetData=GraphFunctions.ResetData graph.RefreshGraph=GraphFunctions.RefreshLineGraph graph.CreateGridlines=GraphFunctions.CreateGridlines graph.SetAxisDrawing=GraphFunctions.SetAxisDrawing graph.SetGridSpacing=GraphFunctions.SetGridSpacing graph.SetAxisColor=GraphFunctions.SetAxisColor graph.SetGridColor=GraphFunctions.SetGridColor graph.SetGridColorSecondary=GraphFunctions.SetGridColorSecondary graph.SetGridSecondaryMultiple=GraphFunctions.SetGridSecondaryMultiple graph.SetAutoScale=GraphFunctions.SetAutoScale graph.SetYLabels=GraphFunctions.SetYLabels graph.OnUpdate=GraphFunctions.OnUpdateGraph graph.LockXMin=GraphFunctions.LockXMin graph.LockXMax=GraphFunctions.LockXMax graph.LockYMin=GraphFunctions.LockYMin graph.LockYMax=GraphFunctions.LockYMax graph.DrawLine=self.DrawLine graph.DrawHLine=self.DrawHLine graph.DrawVLine=self.DrawVLine graph.HideLines=self.HideLines graph.DrawBar=self.DrawBar graph.HideBars=self.HideBars graph.HideFontStrings=GraphFunctions.HideFontStrings graph.FindFontString=GraphFunctions.FindFontString --Set the update function graph:SetScript("OnUpdate", graph.OnUpdate) end --TODO: Clip lines with the bounds function lib:CreateGraphLine(name,parent,relative,relativeTo,offsetX,offsetY,Width,Height) local graph local i graph = CreateFrame("Frame",name,parent) graph:SetPoint(relative,parent,relativeTo,offsetX,offsetY) graph:SetWidth(Width) graph:SetHeight(Height) graph:Show() SetupGraphLineFunctions(graph) graph.NeedsUpdate=false --Initialize Data graph.GraphType="LINE" graph.YMax=1 graph.YMin=-1 graph.XMax=1 graph.XMin=-1 graph.AxisColor={1.0,1.0,1.0,1.0} graph.GridColor={0.5,0.5,0.5,0.5} graph.XGridInterval=0.25 graph.YGridInterval=0.25 graph.XAxisDrawn=true graph.YAxisDrawn=true graph.LockOnXMin=false graph.LockOnXMax=false graph.LockOnYMin=false graph.LockOnYMax=false graph.Data={} graph.FilledData={} graph.Textures={} graph.TexturesUsed={} graph.TextFrame = CreateFrame("Frame",nil,graph) graph.TextFrame:SetAllPoints(graph) tinsert(self.RegisteredGraphLine, graph) return graph end --Scatter Plot local function SetupGraphScatterPlotFunctions(graph) local self = lib --Set the various functions graph.SetXAxis=GraphFunctions.SetXAxis graph.SetYAxis=GraphFunctions.SetYAxis graph.AddDataSeries=GraphFunctions.AddDataSeries graph.ResetData=GraphFunctions.ResetData graph.RefreshGraph=GraphFunctions.RefreshScatterPlot graph.CreateGridlines=GraphFunctions.CreateGridlines graph.OnUpdate=GraphFunctions.OnUpdateGraph graph.LinearRegression=GraphFunctions.LinearRegression graph.SetAxisDrawing=GraphFunctions.SetAxisDrawing graph.SetGridSpacing=GraphFunctions.SetGridSpacing graph.SetAxisColor=GraphFunctions.SetAxisColor graph.SetGridColor=GraphFunctions.SetGridColor graph.SetGridColorSecondary=GraphFunctions.SetGridColorSecondary graph.SetGridSecondaryMultiple=GraphFunctions.SetGridSecondaryMultiple graph.SetLinearFit=GraphFunctions.SetLinearFit graph.SetAutoScale=GraphFunctions.SetAutoScale graph.SetYLabels=GraphFunctions.SetYLabels graph.LockXMin=GraphFunctions.LockXMin graph.LockXMax=GraphFunctions.LockXMax graph.LockYMin=GraphFunctions.LockYMin graph.LockYMax=GraphFunctions.LockYMax graph.DrawLine=self.DrawLine graph.DrawHLine=self.DrawHLine graph.DrawVLine=self.DrawVLine graph.HideLines=self.HideLines graph.HideTextures=GraphFunctions.HideTextures graph.FindTexture=GraphFunctions.FindTexture graph.HideFontStrings=GraphFunctions.HideFontStrings graph.FindFontString=GraphFunctions.FindFontString --Set the update function graph:SetScript("OnUpdate", graph.OnUpdate) end function lib:CreateGraphScatterPlot(name,parent,relative,relativeTo,offsetX,offsetY,Width,Height) local graph local i graph = CreateFrame("Frame",name,parent) graph:SetPoint(relative,parent,relativeTo,offsetX,offsetY) graph:SetWidth(Width) graph:SetHeight(Height) graph:Show() SetupGraphScatterPlotFunctions(graph) graph.NeedsUpdate=false --Initialize Data graph.GraphType="SCATTER" graph.YMax=1 graph.YMin=-1 graph.XMax=1 graph.XMin=-1 graph.AxisColor={1.0,1.0,1.0,1.0} graph.GridColor={0.5,0.5,0.5,0.5} graph.XGridInterval=0.25 graph.YGridInterval=0.25 graph.XAxisDrawn=true graph.YAxisDrawn=true graph.AutoScale=false graph.LinearFit=false graph.LockOnXMin=false graph.LockOnXMax=false graph.LockOnYMin=false graph.LockOnYMax=false graph.Data={} graph.Textures={} graph.TexturesUsed={} graph.TextFrame = CreateFrame("Frame",nil,graph) graph.TextFrame:SetAllPoints(graph) tinsert(self.RegisteredGraphScatterPlot, graph) return graph end --Pie Chart local function SetupGraphPieChartFunctions(graph) local self = lib --Set the various functions graph.AddPie=GraphFunctions.AddPie graph.CompletePie=GraphFunctions.CompletePie graph.ResetPie=GraphFunctions.ResetPie graph.DrawLine=self.DrawLine graph.DrawHLine=self.DrawHLine graph.DrawVLine=self.DrawVLine graph.DrawLinePie=GraphFunctions.DrawLinePie graph.HideLines=self.HideLines graph.HideTextures=GraphFunctions.HideTextures graph.FindTexture=GraphFunctions.FindTexture graph.OnUpdate=GraphFunctions.PieChart_OnUpdate graph.SetSelectionFunc=GraphFunctions.SetSelectionFunc graph:SetScript("OnUpdate", graph.OnUpdate) end function lib:CreateGraphPieChart(name,parent,relative,relativeTo,offsetX,offsetY,Width,Height) local graph local i graph = CreateFrame("Frame",name,parent) graph:SetPoint(relative,parent,relativeTo,offsetX,offsetY) graph:SetWidth(Width) graph:SetHeight(Height) graph:Show() SetupGraphPieChartFunctions(graph) --Initialize Data graph.GraphType="PIE" graph.PieUsed=0 graph.PercentOn=0 graph.Remaining=0 graph.Textures={} graph.Ratio=Width/Height graph.Radius=0.88*(Width/2) graph.Radius=graph.Radius*graph.Radius graph.Sections={} graph.Textures={} graph.TexturesUsed={} graph.LastSection=nil graph.onColor=1 graph.TotalSections=0 tinsert(self.RegisteredGraphPieChart, graph) return graph end ------------------------------------------------------------------------------- --Functions for Realtime Graphs ------------------------------------------------------------------------------- --AddTimeData - Adds a data value to the realtime graph at this moment in time function GraphFunctions:AddTimeData(value) if type(value)~="number" then return end local t={} t.Time=GetTime() self.LastDataTime=t.Time t.Value=value tinsert(self.Data,t) end --RefreshRealtimeGraph - Refreshes the gridlines for the realtime graph function GraphFunctions:RefreshRealtimeGraph() self:HideLines(self) self:CreateGridlines() end --SetFilterRadius - controls the radius of the filter function GraphFunctions:SetFilterRadius(radius) self.TimeRadius=radius end --SetAutoscaleYAxis - If enabled the maximum y axis is adjusted to be 25% more than the max value function GraphFunctions:SetAutoscaleYAxis(scale) self.AutoScale=scale end --SetBarColors - function GraphFunctions:SetBarColors(BotColor,TopColor) local Temp if BotColor.r then Temp=BotColor BotColor={Temp.r,Temp.g,Temp.b,Temp.a} end if TopColor.r then Temp=TopColor TopColor={Temp.r,Temp.g,Temp.b,Temp.a} end for i=1,self.BarNum do local t=self.Bars[i]:GetStatusBarTexture() t:SetGradientAlpha("VERTICAL",BotColor[1],BotColor[2],BotColor[3],BotColor[4],TopColor[1],TopColor[2],TopColor[3],TopColor[4]) end end function GraphFunctions:SetMode(mode) self.Mode=mode if mode~="SLOW" then self.LastShift=GetTime()+self.XMin end end function GraphFunctions:RealtimeSetColors(BotColor,TopColor) local Temp if BotColor.r then Temp=BotColor BotColor={Temp.r,Temp.g,Temp.b,Temp.a} end if TopColor.r then Temp=TopColor TopColor={Temp.r,Temp.g,Temp.b,Temp.a} end self.BarColorBot=BotColor self.BarColorTop=TopColor for _,v in pairs(self.Bars) do v:GetStatusBarTexture():SetGradientAlpha("VERTICAL",self.BarColorBot[1],self.BarColorBot[2],self.BarColorBot[3],self.BarColorBot[4],self.BarColorTop[1],self.BarColorTop[2],self.BarColorTop[3],self.BarColorTop[4]) end end function GraphFunctions:RealtimeSetWidth(Width) Width=math_floor(Width) if Width==self.BarNum then return end self.BarNum=Width for i=1,Width do if type(self.Bars[i])=="nil" then local bar bar = CreateFrame("StatusBar",self:GetName().."Bar"..i,self) bar:SetPoint("BOTTOMLEFT",self,"BOTTOMLEFT",i-1,0) bar:SetHeight(self.Height) bar:SetWidth(1) bar:SetOrientation("VERTICAL") bar:SetMinMaxValues(0,1) bar:SetStatusBarTexture("Interface\\Buttons\\WHITE8X8.blp") bar:GetStatusBarTexture():SetHorizTile(false) bar:GetStatusBarTexture():SetVertTile(false) local t=bar:GetStatusBarTexture() t:SetGradientAlpha("VERTICAL",self.BarColorBot[1],self.BarColorBot[2],self.BarColorBot[3],self.BarColorBot[4],self.BarColorTop[1],self.BarColorTop[2],self.BarColorTop[3],self.BarColorTop[4]) tinsert(self.Bars,bar) else self.Bars[i]:SetPoint("BOTTOMLEFT",self,"BOTTOMLEFT",i-1,0) end self.BarHeight[i]=0 end local SizeOfBarsUsed=table.maxn(self.BarsUsing) if Width>SizeOfBarsUsed then for i=SizeOfBarsUsed+1,Width do tinsert(self.BarsUsing,self.Bars[i]) self.Bars[i]:Show() end elseif Widthself.XMax then return 0 end Bar=math_min(math_max(math_floor(self.BarNum*(Time-self.XMin)/(self.XMax-self.XMin)+0.5),1),self.BarNum) return self.BarHeight[Bar] end function GraphFunctions:SetUpdateLimit(Time) self.LimitUpdates=Time end function GraphFunctions:SetDecay(decay) self.DecaySet=decay self.Decay=math_pow(self.DecaySet,self.BarWidth) self.ExpNorm=1/(1-self.Decay)/0.95 --Actually a finite geometric series (divide 0.96 instead of 1 since seems doesn't quite work right) end function GraphFunctions:AddBar(value) for i=1,self.BarNum-1 do self.BarHeight[i]=self.BarHeight[i+1] end self.BarHeight[self.BarNum]=value self.AddedBar=true end function GraphFunctions:SetBars() local YHeight=self.YMax-self.YMin for i,bar in pairs(self.BarsUsing) do local h h=(self.BarHeight[i]-self.YMin)/YHeight bar:SetValue(h) end end ------------------------------------------------------------------------------- --Functions for Line Graph Data ------------------------------------------------------------------------------- function GraphFunctions:AddDataSeries(points,color,n2) local data --Make sure there is data points if not points then return end data=points if n2==nil then n2=false end if n2 or (table.getn(points)==2 and table.getn(points[1])~=2) then data={} for k,v in ipairs(points[1]) do tinsert(data,{v,points[2][k]}) end end tinsert(self.Data,{Points=data;Color=color}) self.NeedsUpdate=true end function GraphFunctions:AddFilledDataSeries(points,color,n2) local data --Make sure there is data points if not points or #points==0 then return end data=points if n2==nil then n2=false end if n2 or (table.getn(points)==2 and table.getn(points[1])~=2) then data={} for k,v in ipairs(points[1]) do tinsert(data,{v,points[2][k]}) end end tinsert(self.FilledData,{Points=data;Color=color}) self.NeedsUpdate=true end function GraphFunctions:ResetData() self.Data={} if self.FilledData then self.FilledData={} end self.NeedsUpdate=true end function GraphFunctions:SetLinearFit(fit) self.LinearFit=fit self.NeedsUpdate=true end function GraphFunctions:HideTextures() local k=#self.TexturesUsed while k>0 do self.Textures[#self.Textures+1]=self.TexturesUsed[k] self.TexturesUsed[k]:Hide() self.TexturesUsed[k]=nil k=k-1 end end --Make sure to show a texture after you grab it or its free for anyone else to grab function GraphFunctions:FindTexture() local t if #self.Textures>0 then t=self.Textures[#self.Textures] self.TexturesUsed[#self.TexturesUsed+1]=t self.Textures[#self.Textures]=nil return t end local g=self:CreateTexture(nil,"BACKGROUND") self.TexturesUsed[#self.TexturesUsed+1]=g return g end function GraphFunctions:HideFontStrings() if not self.FontStrings then self.FontStrings={} end for k, t in pairs(self.FontStrings) do t:Hide() end end --Make sure to show a fontstring after you grab it or its free for anyone else to grab function GraphFunctions:FindFontString() for k, t in pairs(self.FontStrings) do if not t:IsShown() then return t end end local g if self.TextFrame then g=self.TextFrame:CreateFontString(nil,"OVERLAY") else g=self:CreateFontString(nil,"OVERLAY") end tinsert(self.FontStrings,g) return g end --Linear Regression via Least Squares function GraphFunctions:LinearRegression(data) local alpha, beta local n, SX,SY,SXX, SXY = 0,0,0,0,0 for k,v in pairs(data) do n=n+1 SX=SX+v[1] SXX=SXX+v[1]*v[1] SY=SY+v[2] SXY=SXY+v[1]*v[2] end beta=(n*SXY-SX*SY)/(n*SXX-SX*SX) alpha=(SY-beta*SX)/n return alpha, beta end ------------------------------------------------------------------------------- --Functions for Pie Chart ------------------------------------------------------------------------------- local PiePieces={"1-2", "1-4", "1-8", "1-16", "1-32", "1-64", "1-128"} --26 Colors local ColorTable={ {0.9,0.1,0.1}, {0.1,0.9,0.1}, {0.1,0.1,0.9}, {0.9,0.9,0.1}, {0.9,0.1,0.9}, {0.1,0.9,0.9}, {0.9,0.9,0.9}, {0.5,0.1,0.1}, {0.1,0.5,0.1}, {0.1,0.1,0.5}, {0.5,0.5,0.1}, {0.5,0.1,0.5}, {0.1,0.5,0.5}, {0.5,0.5,0.5}, {0.75,0.15,0.15}, {0.15,0.75,0.15}, {0.15,0.15,0.75}, {0.75,0.75,0.15}, {0.75,0.15,0.75}, {0.15,0.75,0.75}, {0.9,0.5,0.1}, {0.1,0.5,0.9}, {0.9,0.1,0.5}, {0.5,0.9,0.1}, {0.5,0.1,0.9}, {0.1,0.9,0.5}, } function GraphFunctions:AddPie(Percent, Color) local k,v local PiePercent=self.PercentOn local CurPiece=50 local Angle=180 local CurAngle=PiePercent*360/100 self.TotalSections=self.TotalSections+1 if type(self.Sections[self.TotalSections])~="table" then self.Sections[self.TotalSections]={} end local Section=self.Sections[self.TotalSections] Section.Textures={} if type(Color)~="table" then if self.onColor<=table.maxn(ColorTable) then Color=ColorTable[self.onColor] else Color={math_random(),math_random(),math_random()} end self.onColor=self.onColor+1 end if PiePercent==0 then self:DrawLinePie(0) end Percent=Percent+self.Remaining local LastPiece=0 for k,v in pairs(PiePieces) do if (Percent+0.1)>CurPiece then local t=self:FindTexture() t:SetTexture(TextureDirectory..v) t:ClearAllPoints() t:SetPoint("CENTER",self,"CENTER",0,0) t:SetHeight(self:GetHeight()) t:SetWidth(self:GetWidth()) GraphFunctions:RotateTexture(t,CurAngle) t:Show() t:SetVertexColor(Color[1],Color[2],Color[3],1.0) Percent=Percent-CurPiece PiePercent=PiePercent+CurPiece CurAngle=CurAngle+Angle tinsert(Section.Textures,t) if k == 7 then LastPiece=0.09 end end CurPiece=CurPiece/2 Angle=Angle/2 end --Finish adding section data Section.Color=Color Section.Angle=CurAngle self:DrawLinePie((PiePercent+LastPiece)*360/100) self.PercentOn=PiePercent self.Remaining=Percent return Color end function GraphFunctions:CompletePie(Color) local Percent=100-self.PercentOn local k,v local PiePercent=self.PercentOn local CurPiece=50 local Angle=180 local CurAngle=PiePercent*360/100 self.TotalSections=self.TotalSections+1 if not self.Sections[self.TotalSections] then self.Sections[self.TotalSections]={} end local Section=self.Sections[self.TotalSections] Section.Textures={} if type(Color)~="table" then if self.onColor<=table.maxn(ColorTable) then Color=ColorTable[self.onColor] else Color={math_random(),math_random(),math_random()} end self.onColor=self.onColor+1 end Percent=Percent+self.Remaining if PiePercent~=0 then for k,v in pairs(PiePieces) do if (Percent+0.1)>CurPiece then local t=self:FindTexture() t:SetTexture(TextureDirectory..v) t:ClearAllPoints() t:SetPoint("CENTER",self,"CENTER",0,0) t:SetHeight(self:GetHeight()) t:SetWidth(self:GetWidth()) GraphFunctions:RotateTexture(t,CurAngle) t:Show() t:SetVertexColor(Color[1],Color[2],Color[3],1.0) Percent=Percent-CurPiece PiePercent=PiePercent+CurPiece CurAngle=CurAngle+Angle tinsert(Section.Textures,t) end CurPiece=CurPiece/2 Angle=Angle/2 end else--Special case if its by itself local t=self:FindTexture() t:SetTexture(TextureDirectory.."1-1") t:ClearAllPoints() t:SetPoint("CENTER",self,"CENTER",0,0) t:SetHeight(self:GetHeight()) t:SetWidth(self:GetWidth()) GraphFunctions:RotateTexture(t,CurAngle) t:Show() t:SetVertexColor(Color[1],Color[2],Color[3],1.0) tinsert(Section.Textures,t) end --Finish adding section data Section.Color=Color Section.Angle=360 self.PercentOn=PiePercent self.Remaining=Percent return Color end function GraphFunctions:ResetPie() self:HideTextures() self:HideLines(self) self.PieUsed=0 self.PercentOn=0 self.Remaining=0 self.onColor=1 self.LastSection=nil self.TotalSections=0 --self.Sections={} end function GraphFunctions:DrawLinePie(angle) local sx,sy,ex,ey local Radian=math_pi*(90-angle)/180 local w,h w=self:GetWidth()/2 h=self:GetHeight()/2 sx=w sy=h ex=sx+0.88*w*math_cos(Radian) ey=sx+0.88*h*math_sin(Radian) self:DrawLine(self,sx,sy,ex,ey,34,{0.0,0.0,0.0,1.0},"OVERLAY") end --Used to rotate the pie slices function GraphFunctions:RotateTexture(texture,angle) local Radian=math_pi*(45-angle)/180 local Radian2=math_pi*(45+90-angle)/180 local Radius=0.70710678118654752440084436210485 local tx,ty,tx2,ty2 tx=Radius*math_cos(Radian) ty=Radius*math_sin(Radian) tx2=-ty ty2=tx texture:SetTexCoord(0.5-tx,0.5-ty,0.5+tx2,0.5+ty2,0.5-tx2,0.5-ty2,0.5+tx,0.5+ty) end function GraphFunctions:SetSelectionFunc(f) self.SelectionFunc=f end --TODO: Pie chart pieces need to be clickable function GraphFunctions:PieChart_OnUpdate() if (MouseIsOver(self)) then local sX,sY=self:GetCenter() local Scale=self:GetEffectiveScale() local mX,mY=GetCursorPosition() local dX,dY dX=mX/Scale-sX dY=mY/Scale-sY local Angle=90-math_deg(math_atan(dY/dX)) dY=dY*self.Ratio local Dist=dX*dX+dY*dY if dX<0 then Angle=Angle+180 end local k,v --Are we on the Pie Chart? if Dist12)) and (NoSecondary or math_fmod(i,self.GridSecondaryY)==0) then if self.YLabelsLeft then F=self:FindFontString() F:SetFontObject("GameFontHighlightSmall") F:SetTextColor(1,1,1) F:ClearAllPoints() F:SetPoint("BOTTOMLEFT",T,"LEFT",2,2) F:SetText(i*self.YGridInterval) F:Show() end if self.YLabelsRight then F=self:FindFontString() F:SetFontObject("GameFontHighlightSmall") F:SetTextColor(1,1,1) F:ClearAllPoints() F:SetPoint("BOTTOMRIGHT",T,"RIGHT",-2,2) F:SetText(i*self.YGridInterval) F:Show() end end end end end if self.XGridInterval then local LowerXGridLine,UpperXGridLine LowerXGridLine=self.XMin/self.XGridInterval LowerXGridLine=math_max(math_floor(LowerXGridLine),math_ceil(LowerXGridLine)) UpperXGridLine=self.XMax/self.XGridInterval UpperXGridLine=math_min(math_floor(UpperXGridLine),math_ceil(UpperXGridLine)) for i=LowerXGridLine,UpperXGridLine do if i~=0 or not self.XAxisDrawn then local XPos XPos=Width*(i*self.XGridInterval-self.XMin)/(self.XMax-self.XMin) if NoSecondary or math_fmod(i,self.GridSecondaryX)==0 then self:DrawLine(self,XPos,0,XPos,Height,24,self.GridColor,"BACKGROUND") else self:DrawLine(self,XPos,0,XPos,Height,24,self.GridColorSecondary,"BACKGROUND") end end end end if self.YAxisDrawn and self.YMax>=0 and self.YMin<=0 then local YPos,T YPos=Height*(-self.YMin)/(self.YMax-self.YMin) T=self:DrawLine(self,0,YPos,Width,YPos,24,self.AxisColor,"BACKGROUND") if self.YLabelsLeft then F=self:FindFontString() F:SetFontObject("GameFontHighlightSmall") F:SetTextColor(1,1,1) F:ClearAllPoints() F:SetPoint("BOTTOMLEFT",T,"LEFT",2,2) F:SetText(0) F:Show() end if self.YLabelsRight then F=self:FindFontString() F:SetFontObject("GameFontHighlightSmall") F:SetTextColor(1,1,1) F:ClearAllPoints() F:SetPoint("BOTTOMRIGHT",T,"RIGHT",-2,2) F:SetText(0) F:Show() end end if self.XAxisDrawn and self.XMax>=0 and self.XMin<=0 then local XPos; XPos=Width*(-self.XMin)/(self.XMax-self.XMin) self:DrawLine(self,XPos,0,XPos,Height,24,self.AxisColor,"BACKGROUND") end end -------------------------------------------------------------------------------- --Refresh functions -------------------------------------------------------------------------------- function GraphFunctions:OnUpdateGraph() if self.NeedsUpdate and self.RefreshGraph then self:RefreshGraph() self.NeedsUpdate=false end end --Performs a convolution in realtime allowing to graph Framerate, DPS, or any other data you want graphed in realtime function GraphFunctions:OnUpdateGraphRealtime() local i,j local CurTime=GetTime() local BarsChanged if self.NextUpdate>CurTime or (self.Mode=="RAW" and not (self.NeedsUpdate or self.AddedBar)) then return end self.NextUpdate=CurTime+self.LimitUpdates --Slow Mode performs an entire convolution every frame if self.Mode=="SLOW" then --Initialize Bar Data self.BarHeight={} for i=1,self.BarNum do self.BarHeight[i]=0 end local k,v local BarTimeRadius=(self.XMax-self.XMin)/self.BarNum local DataValue=1/(2*self.TimeRadius) if self.Filter=="RECT" then --Take the convolution of the dataset on to the bars wtih a rectangular filter local DataValue=1/(2*self.TimeRadius) for k,v in pairs(self.Data) do if v.Time<(CurTime+self.XMin-self.TimeRadius) then tremove(self.Data,k) else local DataTime=v.Time-CurTime local LowestBar=math_max(math_floor((DataTime-self.XMin-self.TimeRadius)/BarTimeRadius),1) local HighestBar=math_min(math_ceil((DataTime-self.XMin+self.TimeRadius)/BarTimeRadius),self.BarNum) for i=LowestBar,HighestBar do self.BarHeight[i]=self.BarHeight[i]+v.Value*DataValue end end end elseif self.Filter=="TRI" then --Needs optimization badly --Take the convolution of the dataset on to the bars wtih a triangular filter local DataValue=1/(self.TimeRadius) for k,v in pairs(self.Data) do local Temp if v.Time<(CurTime+self.XMin-self.TimeRadius) then tremove(self.Data,k) else local DataTime=v.Time-CurTime local LowestBar=math_max(math_floor((DataTime-self.XMin-self.TimeRadius)/BarTimeRadius),1) local HighestBar=math_min(math_ceil((DataTime-self.XMin+self.TimeRadius)/BarTimeRadius),self.BarNum) for i=LowestBar,HighestBar do self.BarHeight[i]=self.BarHeight[i]+v.Value*DataValue*math_abs(BarTimeRadius*i+self.XMin-DataTime) end end end end BarsChanged=true elseif self.Mode=="FAST" then local ShiftBars=math_floor((CurTime-self.LastShift)/self.BarWidth) if ShiftBars>0 and not (self.LastDataTime<(self.LastShift+self.XMin-self.TimeRadius*2)) then local RecalcBars=self.BarNum-(ShiftBars+self.FilterOverlap)+1 for i=1,self.BarNum do if i0 then local RecalcBars=self.BarNum-ShiftBars+1 for i=1,self.BarNum do if i0 and not (self.LastDataTime<(self.LastShift+self.XMin-self.TimeRadius)) then for i=1,self.BarNum do if i0.01 then self.YMax=MaxY self.NeedsUpdate=true end end self:SetBars() end if self.NeedsUpdate then self.NeedsUpdate=false self:RefreshGraph() end end --Line Graph function GraphFunctions:RefreshLineGraph() local k1, k2, series self:HideLines(self) self:HideBars(self) if self.AutoScale and self.Data then local MinX, MaxX, MinY, MaxY = math_huge, -math_huge, math_huge, -math_huge --Go through line data first for k1, series in pairs(self.Data) do for k2, point in pairs(series.Points) do MinX=math_min(point[1],MinX) MaxX=math_max(point[1],MaxX) MinY=math_min(point[2],MinY) MaxY=math_max(point[2],MaxY) end end --Now through the Filled Lines for k1, series in pairs(self.FilledData) do for k2, point in pairs(series.Points) do MinX=math_min(point[1],MinX) MaxX=math_max(point[1],MaxX) MinY=math_min(point[2],MinY) MaxY=math_max(point[2],MaxY) end end local XBorder, YBorder XBorder=0.1*(MaxX-MinX) YBorder=0.1*(MaxY-MinY) if not self.LockOnXMin then self.XMin=MinX-XBorder end if not self.LockOnXMax then self.XMax=MaxX+XBorder end if not self.LockOnYMin then self.YMin=MinY-YBorder end if not self.LockOnYMax then self.YMax=MaxY+YBorder end end self:CreateGridlines() local Width=self:GetWidth() local Height=self:GetHeight() for k1, series in pairs(self.Data) do local LastPoint LastPoint=nil for k2, point in pairs(series.Points) do if LastPoint then local TPoint={x=point[1];y=point[2]} TPoint.x=Width*(TPoint.x-self.XMin)/(self.XMax-self.XMin) TPoint.y=Height*(TPoint.y-self.YMin)/(self.YMax-self.YMin) self:DrawLine(self,LastPoint.x,LastPoint.y,TPoint.x,TPoint.y,32,series.Color) LastPoint=TPoint else LastPoint={x=point[1];y=point[2]} LastPoint.x=Width*(LastPoint.x-self.XMin)/(self.XMax-self.XMin) LastPoint.y=Height*(LastPoint.y-self.YMin)/(self.YMax-self.YMin) end end end --Filled Line Graphs for k1, series in pairs(self.FilledData) do local LastPoint LastPoint=nil for k2, point in pairs(series.Points) do if LastPoint then local TPoint={x=point[1];y=point[2]} TPoint.x=Width*(TPoint.x-self.XMin)/(self.XMax-self.XMin) TPoint.y=Height*(TPoint.y-self.YMin)/(self.YMax-self.YMin) self:DrawBar(self,LastPoint.x,LastPoint.y,TPoint.x,TPoint.y,series.Color,k1) LastPoint=TPoint else LastPoint={x=point[1];y=point[2]} LastPoint.x=Width*(LastPoint.x-self.XMin)/(self.XMax-self.XMin) LastPoint.y=Height*(LastPoint.y-self.YMin)/(self.YMax-self.YMin) end end end end --Scatter Plot Refresh function GraphFunctions:RefreshScatterPlot() local k1, k2, series, point self:HideLines(self) if self.AutoScale and self.Data then local MinX, MaxX, MinY, MaxY = math_huge, -math_huge, math_huge, -math_huge for k1, series in pairs(self.Data) do for k2, point in pairs(series.Points) do MinX=math_min(point[1],MinX) MaxX=math_max(point[1],MaxX) MinY=math_min(point[2],MinY) MaxY=math_max(point[2],MaxY) end end local XBorder, YBorder XBorder=0.1*(MaxX-MinX) YBorder=0.1*(MaxY-MinY) if not self.LockOnXMin then self.XMin=MinX-XBorder end if not self.LockOnXMax then self.XMax=MaxX+XBorder end if not self.LockOnYMin then self.YMin=MinY-YBorder end if not self.LockOnYMax then self.YMax=MaxY+YBorder end end self:CreateGridlines() local Width=self:GetWidth() local Height=self:GetHeight() self:HideTextures() for k1, series in pairs(self.Data) do local MinX,MaxX = self.XMax, self.XMin for k2, point in pairs(series.Points) do local x,y MinX=math_min(point[1],MinX) MaxX=math_max(point[1],MaxX) x=Width*(point[1]-self.XMin)/(self.XMax-self.XMin) y=Height*(point[2]-self.YMin)/(self.YMax-self.YMin) local g=self:FindTexture() g:SetTexture("Spells\\GENERICGLOW2_64.blp") g:SetWidth(6) g:SetHeight(6) g:ClearAllPoints() g:SetPoint("CENTER",self,"BOTTOMLEFT",x,y) g:SetVertexColor(series.Color[1],series.Color[2],series.Color[3],series.Color[4]); g:Show() end if self.LinearFit then local alpha, beta = self:LinearRegression(series.Points) local sx,sy,ex,ey sx=MinX sy=beta*sx+alpha ex=MaxX ey=beta*ex+alpha sx=Width*(sx-self.XMin)/(self.XMax-self.XMin) sy=Height*(sy-self.YMin)/(self.YMax-self.YMin) ex=Width*(ex-self.XMin)/(self.XMax-self.XMin) ey=Height*(ey-self.YMin)/(self.YMax-self.YMin) self:DrawLine(self,sx,sy,ex,ey,32,series.Color) end end end --Copied from Blizzard's TaxiFrame code and modifed for IMBA then remodified for GraphLib -- The following function is used with permission from Daniel Stephens local TAXIROUTE_LINEFACTOR = 128/126; -- Multiplying factor for texture coordinates local TAXIROUTE_LINEFACTOR_2 = TAXIROUTE_LINEFACTOR / 2; -- Half of that -- T - Texture -- C - Canvas Frame (for anchoring) -- sx,sy - Coordinate of start of line -- ex,ey - Coordinate of end of line -- w - Width of line -- relPoint - Relative point on canvas to interpret coords (Default BOTTOMLEFT) function lib:DrawLine(C, sx, sy, ex, ey, w, color, layer) local relPoint = "BOTTOMLEFT" if sx==ex then if sy==ey then return else return self:DrawVLine(C,sx,sy,ey,w, color, layer) end elseif sy==ey then return self:DrawHLine(C,sx,ex,sy,w, color, layer) end if not C.GraphLib_Lines then C.GraphLib_Lines={} C.GraphLib_Lines_Used={} end local T = tremove(C.GraphLib_Lines) or C:CreateTexture(nil, "ARTWORK") T:SetTexture(TextureDirectory.."line") tinsert(C.GraphLib_Lines_Used,T) T:SetDrawLayer(layer or "ARTWORK") T:SetVertexColor(color[1],color[2],color[3],color[4]); -- Determine dimensions and center point of line local dx,dy = ex - sx, ey - sy; local cx,cy = (sx + ex) / 2, (sy + ey) / 2; -- Normalize direction if necessary if (dx < 0) then dx,dy = -dx,-dy; end -- Calculate actual length of line local l = sqrt((dx * dx) + (dy * dy)); -- Sin and Cosine of rotation, and combination (for later) local s,c = -dy / l, dx / l; local sc = s * c; -- Calculate bounding box size and texture coordinates local Bwid, Bhgt, BLx, BLy, TLx, TLy, TRx, TRy, BRx, BRy; if (dy >= 0) then Bwid = ((l * c) - (w * s)) * TAXIROUTE_LINEFACTOR_2; Bhgt = ((w * c) - (l * s)) * TAXIROUTE_LINEFACTOR_2; BLx, BLy, BRy = (w / l) * sc, s * s, (l / w) * sc; BRx, TLx, TLy, TRx = 1 - BLy, BLy, 1 - BRy, 1 - BLx; TRy = BRx; else Bwid = ((l * c) + (w * s)) * TAXIROUTE_LINEFACTOR_2; Bhgt = ((w * c) + (l * s)) * TAXIROUTE_LINEFACTOR_2; BLx, BLy, BRx = s * s, -(l / w) * sc, 1 + (w / l) * sc; BRy, TLx, TLy, TRy = BLx, 1 - BRx, 1 - BLx, 1 - BLy; TRx = TLy; end -- Thanks Blizzard for adding (-)10000 as a hard-cap and throwing errors! -- The cap was added in 3.1.0 and I think it was upped in 3.1.1 -- (way less chance to get the error) if TLx > 10000 then TLx = 10000 elseif TLx < -10000 then TLx = -10000 end if TLy > 10000 then TLy = 10000 elseif TLy < -10000 then TLy = -10000 end if BLx > 10000 then BLx = 10000 elseif BLx < -10000 then BLx = -10000 end if BLy > 10000 then BLy = 10000 elseif BLy < -10000 then BLy = -10000 end if TRx > 10000 then TRx = 10000 elseif TRx < -10000 then TRx = -10000 end if TRy > 10000 then TRy = 10000 elseif TRy < -10000 then TRy = -10000 end if BRx > 10000 then BRx = 10000 elseif BRx < -10000 then BRx = -10000 end if BRy > 10000 then BRy = 10000 elseif BRy < -10000 then BRy = -10000 end -- Set texture coordinates and anchors T:ClearAllPoints(); T:SetTexCoord(TLx, TLy, BLx, BLy, TRx, TRy, BRx, BRy); T:SetPoint("BOTTOMLEFT", C, relPoint, cx - Bwid, cy - Bhgt); T:SetPoint("TOPRIGHT", C, relPoint, cx + Bwid, cy + Bhgt); T:Show() return T end --Thanks to Celandro function lib:DrawVLine(C, x, sy, ey, w, color, layer) local relPoint = "BOTTOMLEFT" if not C.GraphLib_Lines then C.GraphLib_Lines={} C.GraphLib_Lines_Used={} end local T = tremove(C.GraphLib_Lines) or C:CreateTexture(nil, "ARTWORK") T:SetTexture(TextureDirectory.."sline"); tinsert(C.GraphLib_Lines_Used,T); T:SetDrawLayer(layer or "ARTWORK") T:SetVertexColor(color[1],color[2],color[3],color[4]); if sy>ey then sy, ey = ey, sy end -- Set texture coordinates and anchors T:ClearAllPoints(); T:SetTexCoord(1, 0, 0, 0, 1, 1, 0, 1); T:SetPoint("BOTTOMLEFT", C, relPoint, x-w/2, sy); T:SetPoint("TOPRIGHT", C, relPoint, x+w/2, ey); T:Show() return T end function lib:DrawHLine(C, sx, ex, y, w, color, layer) local relPoint = "BOTTOMLEFT" if not C.GraphLib_Lines then C.GraphLib_Lines={} C.GraphLib_Lines_Used={} end local T = tremove(C.GraphLib_Lines) or C:CreateTexture(nil, "ARTWORK") T:SetTexture(TextureDirectory.."sline"); tinsert(C.GraphLib_Lines_Used,T); T:SetDrawLayer(layer or "ARTWORK") T:SetVertexColor(color[1],color[2],color[3],color[4]); if sx>ex then sx, ex = ex, sx end -- Set texture coordinates and anchors T:ClearAllPoints(); T:SetTexCoord(0, 0, 0, 1, 1, 0, 1, 1); T:SetPoint("BOTTOMLEFT", C, relPoint, sx, y-w/2); T:SetPoint("TOPRIGHT", C, relPoint, ex, y+w/2); T:Show() return T end function lib:HideLines(C) if C.GraphLib_Lines then for i = #C.GraphLib_Lines_Used, 1, -1 do C.GraphLib_Lines_Used[i]:Hide() tinsert(C.GraphLib_Lines,tremove(C.GraphLib_Lines_Used)) end end end --Two parts to each bar function lib:DrawBar(C, sx, sy, ex, ey, color, level) local Bar, Tri, barNum, MinY, MaxY --Want sx<=ex if not then flip them if sx>ex then sx, ex = ex, sx sy, ey = ey, sy end if not C.GraphLib_Bars then C.GraphLib_Bars={} C.GraphLib_Tris={} C.GraphLib_Bars_Used={} C.GraphLib_Tris_Used={} C.GraphLib_Frames={} end if (#C.GraphLib_Bars)>0 then Bar=C.GraphLib_Bars[#C.GraphLib_Bars] tremove(C.GraphLib_Bars,#C.GraphLib_Bars) Bar:Show() Tri=C.GraphLib_Tris[#C.GraphLib_Tris] tremove(C.GraphLib_Tris,#C.GraphLib_Tris) Tri:Show() end if not Bar then Bar=C:CreateTexture(nil, "ARTWORK") Bar:SetTexture(1,1,1,1) Tri=C:CreateTexture(nil, "ARTWORK") Tri:SetTexture(TextureDirectory.."triangle") end tinsert(C.GraphLib_Bars_Used,Bar) tinsert(C.GraphLib_Tris_Used,Tri) if level then if type(C.GraphLib_Frames[level])=="nil" then local newLevel=C:GetFrameLevel()+level C.GraphLib_Frames[level]=CreateFrame("Frame",nil,C) C.GraphLib_Frames[level]:SetFrameLevel(newLevel) C.GraphLib_Frames[level]:SetAllPoints(C) if C.TextFrame and C.TextFrame:GetFrameLevel()<=newLevel then C.TextFrame:SetFrameLevel(newLevel+1) self.NeedsUpdate=true end end Bar:SetParent(C.GraphLib_Frames[level]) Tri:SetParent(C.GraphLib_Frames[level]) end Bar:SetVertexColor(color[1],color[2],color[3],color[4]) Tri:SetVertexColor(color[1],color[2],color[3],color[4]) if sy=1 then Tri:ClearAllPoints() Tri:SetPoint("BOTTOMLEFT", C, "BOTTOMLEFT", sx, MinY) Tri:SetWidth(Width) Tri:SetHeight(MaxY-MinY) else Tri:Hide() end end function lib:HideBars(C) if not C.GraphLib_Bars then return end while (#C.GraphLib_Bars_Used)>0 do C.GraphLib_Bars[#C.GraphLib_Bars+1]=C.GraphLib_Bars_Used[#C.GraphLib_Bars_Used] C.GraphLib_Bars[#C.GraphLib_Bars]:Hide() C.GraphLib_Bars_Used[#C.GraphLib_Bars_Used]=nil C.GraphLib_Tris[#C.GraphLib_Tris+1]=C.GraphLib_Tris_Used[#C.GraphLib_Tris_Used] C.GraphLib_Tris[#C.GraphLib_Tris]:Hide() C.GraphLib_Tris_Used[#C.GraphLib_Tris_Used]=nil end end -- lib upgrade stuff, overwrite the old function references in -- existing graphs with the ones in this newer library for _, graph in ipairs(lib.RegisteredGraphRealtime) do SetupGraphRealtimeFunctions(graph, true) end for _, graph in ipairs(lib.RegisteredGraphLine) do SetupGraphLineFunctions(graph) end for _, graph in ipairs(lib.RegisteredGraphScatterPlot) do SetupGraphScatterPlotFunctions(graph) end for _, graph in ipairs(lib.RegisteredGraphPieChart) do SetupGraphPieChartFunctions(graph) end --------------------------------------------------- --Test Functions, for reference for addon authors to test, use and copy --To test the library do /script LibStub("LibGraph-2.0"):TestGraph2Lib() local function TestRealtimeGraph() local Graph=LibStub(major) local g=Graph:CreateGraphRealtime("TestRealtimeGraph",UIParent,"CENTER","CENTER",-90,90,150,150) g:SetAutoScale(true) g:SetGridSpacing(1.0,10.0) g:SetYMax(120) g:SetXAxis(-11,-1) g:SetFilterRadius(1) g:SetBarColors({0.2,0.0,0.0,0.4},{1.0,0.0,0.0,1.0}) local f = CreateFrame("Frame") f:SetScript("OnUpdate",function() g:AddTimeData(1) end) f:Show() DEFAULT_CHAT_FRAME:AddMessage("Testing Reattime Graph") end local function TestRealtimeGraphRaw() local Graph=LibStub(major) local g=Graph:CreateGraphRealtime("TestRealtimeGraph",UIParent,"TOP","TOP",0,0,150,150) g:SetAutoScale(true) g:SetGridSpacing(1.0,10.0) g:SetYMax(120) g:SetXAxis(-10,0) g:SetMode("RAW") g:SetBarColors({0.2,0.0,0.0,0.4},{1.0,0.0,0.0,1.0}) local f = CreateFrame("Frame") f.frames=0 f.NextUpdate=GetTime() f:SetScript("OnUpdate",function() if f.NextUpdate>GetTime() then return end g:AddBar(UnitHealth("player")) f.NextUpdate=f.NextUpdate+g.BarWidth end) f:Show() DEFAULT_CHAT_FRAME:AddMessage("Testing 0") end local function TestLineGraph() local Graph=LibStub(major) local g=Graph:CreateGraphLine("TestLineGraph",UIParent,"CENTER","CENTER",90,90,150,150) g:SetXAxis(-1,1) g:SetYAxis(-1,1) g:SetGridSpacing(0.25,0.25) g:SetGridColor({0.5,0.5,0.5,0.5}) g:SetAxisDrawing(true,true) g:SetAxisColor({1.0,1.0,1.0,1.0}) g:SetAutoScale(true) local Data1={{0.05,0.05},{0.2,0.3},{0.4,0.2},{0.9,0.6}} local Data2={{0.05,0.8},{0.3,0.1},{0.5,0.4},{0.95,0.05}} g:AddDataSeries(Data1,{1.0,0.0,0.0,0.8}) g:AddDataSeries(Data2,{0.0,1.0,0.0,0.8}) DEFAULT_CHAT_FRAME:AddMessage("Testing Line Graph") end local function TestScatterPlot() local Graph=LibStub(major) local g=Graph:CreateGraphScatterPlot("TestScatterPlot",UIParent,"CENTER","CENTER",90,-90,150,150) g:SetXAxis(-1,1) g:SetYAxis(-1,1) g:SetGridSpacing(0.25,0.25) g:SetGridColor({0.5,0.5,0.5,0.5}) g:SetAxisDrawing(true,true) g:SetAxisColor({1.0,1.0,1.0,1.0}) g:SetLinearFit(true) g:SetAutoScale(true) local Data1={{0.05,0.05},{0.2,0.3},{0.4,0.2},{0.9,0.6}} local Data2={{0.05,0.8},{0.3,0.1},{0.5,0.4},{0.95,0.05}} g:AddDataSeries(Data1,{1.0,0.0,0.0,0.8}) g:AddDataSeries(Data2,{0.0,1.0,0.0,0.8}) DEFAULT_CHAT_FRAME:AddMessage("Testing Scatter Plot") end local function TestPieChart() local Graph=LibStub(major) local g=Graph:CreateGraphPieChart("TestPieChart",UIParent,"CENTER","CENTER",-90,-90,150,150) g:AddPie(35,{1.0,0.0,0.0}) g:AddPie(21,{0.0,1.0,0.0}) g:AddPie(10,{1.0,1.0,1.0}) g:CompletePie({0.2,0.2,1.0}) DEFAULT_CHAT_FRAME:AddMessage("Testing Pie Chart") end function lib:TestGraph2Lib() DEFAULT_CHAT_FRAME:AddMessage("Testing "..major..", "..gsub(minor, "%$", "")) TestRealtimeGraph() TestLineGraph() TestScatterPlot() TestPieChart() end