chart.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. package gui
  2. import (
  3. "fmt"
  4. "github.com/g3n/engine/core"
  5. "github.com/g3n/engine/geometry"
  6. "github.com/g3n/engine/gls"
  7. "github.com/g3n/engine/material"
  8. "github.com/g3n/engine/math32"
  9. "github.com/g3n/engine/renderer/shader"
  10. )
  11. func init() {
  12. shader.AddShader("shaderChartVertex", shaderChartVertex)
  13. shader.AddShader("shaderChartFrag", shaderChartFrag)
  14. shader.AddProgram("shaderChart", "shaderChartVertex", "shaderChartFrag")
  15. }
  16. // ChartLine implements a panel which can contain several line charts
  17. type ChartLine struct {
  18. Panel // Embedded panel
  19. title *Label // Optional title
  20. baseX float32 // NDC x coordinate for y axis
  21. baseY float32 // NDC y coordinate for x axis
  22. scaleX *ChartScaleX // X scale objet
  23. firstX float32 // First value for X label
  24. stepX float32 // Step value for X label
  25. formatX string // Format for X labels
  26. //scaleY *ChartScaleY // Y scale objet
  27. //graphs []*LineGraph // Array of line graphs
  28. }
  29. // NewChartLine creates and returns a new line chart panel with
  30. // the specified dimensions in pixels.
  31. func NewChartLine(width, height float32) *ChartLine {
  32. cl := new(ChartLine)
  33. cl.Panel.Initialize(width, height)
  34. cl.baseX = 0.1
  35. cl.baseY = -0.9
  36. cl.firstX = 0.0
  37. cl.stepX = 1.0
  38. cl.formatX = "%2.1f"
  39. return cl
  40. }
  41. func (cl *ChartLine) SetTitle(title *Label) {
  42. cl.title = title
  43. if cl.title != nil {
  44. cl.Add(cl.title)
  45. } else {
  46. cl.Remove(cl.title)
  47. }
  48. if cl.scaleX != nil {
  49. cl.scaleX.recalc()
  50. }
  51. }
  52. // SetScaleX sets the line chart x scale number of lines and color
  53. func (cl *ChartLine) SetScaleX(lines int, color *math32.Color) {
  54. if cl.scaleX != nil {
  55. cl.Remove(cl.scaleX)
  56. cl.scaleX.Dispose()
  57. }
  58. cl.scaleX = newChartScaleX(cl, lines, color)
  59. cl.Add(cl.scaleX)
  60. }
  61. //// SetScaleY sets the line chart y scale number of lines and color
  62. //func (cl *ChartLine) SetScaleY(lines int, color *math32.Color) {
  63. //
  64. // if cl.scaleY != nil {
  65. // cl.Node.Remove(cl.scaleY)
  66. // cl.scaleY.Dispose()
  67. // }
  68. // cl.scaleY = newChartScaleY(cl, lines, color)
  69. // cl.Node.Add(cl.scaleY)
  70. //}
  71. //
  72. //// AddLine adds a line graph to the chart
  73. //func (cl *ChartLine) AddGraph(name, title string, color *math32.Color, data []float32) {
  74. //
  75. // graph := newLineGraph(&cl.Panel, name, title, color, data)
  76. // cl.graphs = append(cl.graphs, graph)
  77. // cl.Node.Add(graph)
  78. //}
  79. /*
  80. ChartScaleX is a panel with LINE geometry which draws the chart X horizontal scale axis,
  81. vertical lines and line labels.
  82. | |
  83. | |
  84. | |
  85. | |
  86. +-----+------------------
  87. L L
  88. */
  89. type ChartScaleX struct {
  90. Panel
  91. chart *ChartLine // Container chart
  92. }
  93. //func NewChartScaleX(width, height float32, lines int, color *math32.Color) *ChartScaleX {
  94. //
  95. // sx := new(ChartScaleX)
  96. // baseY := float32(-0.9)
  97. //
  98. // // Generates grid lines using Normalized Device Coordinates and
  99. // // considering that the parent panel model coordinates are:
  100. // // 0,0,0 1,0,0
  101. // // +---------------+
  102. // // | |
  103. // // | |
  104. // // +---------------+
  105. // // 0,-1,0 1,-1,0
  106. // positions := math32.NewArrayF32(0, 0)
  107. // // Appends scaleX bottom horizontal base line
  108. // positions.Append(
  109. // 0, baseY, 0, color.R, color.G, color.B, // line start vertex and color
  110. // 1, baseY, 0, color.R, color.G, color.B, // line end vertex and color
  111. // )
  112. // // Appends scale X vertical lines
  113. // step := 1 / (float32(lines) + 1)
  114. // for i := 1; i < lines+1; i++ {
  115. // nx := float32(i) * step
  116. // positions.Append(
  117. // nx, 0, 0, color.R, color.G, color.B, // line start vertex and color
  118. // nx, baseY, 0, color.R, color.G, color.B, // line end vertex and color
  119. // )
  120. // //l := NewLabel(fmt.Sprintf(sx.chart.formatX, float32(i)))
  121. // //px, py := ndc2pix(&sx.chart.Panel, nx, chart.baseY)
  122. // //log.Error("label px:%v py:%v", px, py)
  123. // //l.SetPosition(px, py)
  124. // //sx.Add(l)
  125. // }
  126. //
  127. // // Creates geometry using one interlaced VBO
  128. // geom := geometry.NewGeometry()
  129. // geom.AddVBO(gls.NewVBO().
  130. // AddAttrib("VertexPosition", 3).
  131. // AddAttrib("VertexColor", 3).
  132. // SetBuffer(positions),
  133. // )
  134. //
  135. // // Creates material
  136. // mat := material.NewMaterial()
  137. // mat.SetLineWidth(1.0)
  138. // mat.SetShader("shaderChart")
  139. //
  140. // sx.Panel.InitializeGraphic(width, height, geom, mat, gls.LINES)
  141. // sx.SetBounded(true)
  142. //
  143. // l2 := NewLabel("LABEL......")
  144. // l2.SetPosition(10, 10)
  145. // sx.Panel.Add(l2)
  146. // log.Error("sx children:%v", sx.Children())
  147. // return sx
  148. //}
  149. func newChartScaleX(chart *ChartLine, lines int, color *math32.Color) *ChartScaleX {
  150. sx := new(ChartScaleX)
  151. sx.chart = chart
  152. // Generates grid lines using Normalized Device Coordinates and
  153. // considering that the parent panel model coordinates are:
  154. // 0,0,0 1,0,0
  155. // +---------------+
  156. // | |
  157. // | |
  158. // +---------------+
  159. // 0,-1,0 1,-1,0
  160. positions := math32.NewArrayF32(0, 0)
  161. // Appends scaleX bottom horizontal base line
  162. positions.Append(
  163. 0, chart.baseY, 0, color.R, color.G, color.B, // line start vertex and color
  164. 1, chart.baseY, 0, color.R, color.G, color.B, // line end vertex and color
  165. )
  166. // Appends scale X vertical lines
  167. step := 1 / (float32(lines) + 1)
  168. for i := 1; i < lines+1; i++ {
  169. nx := float32(i) * step
  170. positions.Append(
  171. nx, 0, 0, color.R, color.G, color.B, // line start vertex and color
  172. nx, chart.baseY, 0, color.R, color.G, color.B, // line end vertex and color
  173. )
  174. }
  175. // Creates geometry using one interlaced VBO
  176. geom := geometry.NewGeometry()
  177. geom.AddVBO(gls.NewVBO().
  178. AddAttrib("VertexPosition", 3).
  179. AddAttrib("VertexColor", 3).
  180. SetBuffer(positions),
  181. )
  182. // Creates material
  183. mat := material.NewMaterial()
  184. mat.SetLineWidth(1.0)
  185. mat.SetShader("shaderChart")
  186. // Initializes the panel with this graphic
  187. sx.Panel.InitializeGraphic(chart.ContentWidth(), chart.ContentHeight(), geom, mat, gls.LINES)
  188. // Add labels after the panel is initialized
  189. for i := 1; i < lines+1; i++ {
  190. nx := float32(i) * step
  191. l := NewLabel(fmt.Sprintf(sx.chart.formatX, float32(i)))
  192. px, py := ndc2pix(&sx.chart.Panel, nx, chart.baseY)
  193. log.Error("label x:%v y:%v", px, py)
  194. l.SetPosition(px, py-20)
  195. sx.Add(l)
  196. }
  197. sx.recalc()
  198. return sx
  199. }
  200. func (sx *ChartScaleX) recalc() {
  201. if sx.chart.title != nil {
  202. th := sx.chart.title.Height()
  203. sx.SetPosition(0, th)
  204. sx.SetHeight(sx.chart.ContentHeight() - th)
  205. } else {
  206. sx.SetPosition(0, 0)
  207. sx.SetHeight(sx.chart.ContentHeight())
  208. }
  209. }
  210. // RenderSetup is called by the renderer before drawing this graphic
  211. // Calculates the model matrix and transfer to OpenGL.
  212. func (sx *ChartScaleX) RenderSetup(gs *gls.GLS, rinfo *core.RenderInfo) {
  213. log.Error("ChartScaleX RenderSetup")
  214. // // Set this model matrix the same as the chart panel
  215. // var mm math32.Matrix4
  216. // sx.chart.SetModelMatrix(gs, &mm)
  217. //
  218. // // Sets and transfer the model matrix uniform
  219. // sx.modelMatrixUni.SetMatrix4(&mm)
  220. // sx.modelMatrixUni.Transfer(gs)
  221. }
  222. //func newChartScaleX(chart *ChartLine, lines int, color *math32.Color) *ChartScaleX {
  223. //
  224. // sx := new(ChartScaleX)
  225. // sx.chart = chart
  226. //
  227. // // Generates grid lines using Normalized Device Coordinates and
  228. // // considering that the parent panel model coordinates are:
  229. // // 0,0,0 1,0,0
  230. // // +---------------+
  231. // // | |
  232. // // | |
  233. // // +---------------+
  234. // // 0,-1,0 1,-1,0
  235. // positions := math32.NewArrayF32(0, 0)
  236. //
  237. // // Appends scaleX bottom horizontal base line
  238. // positions.Append(
  239. // 0, chart.baseY, 0, color.R, color.G, color.B, // line start vertex and color
  240. // 1, chart.baseY, 0, color.R, color.G, color.B, // line end vertex and color
  241. // )
  242. // // Appends scale X vertical lines
  243. // step := 1 / (float32(lines) + 1)
  244. // for i := 1; i < lines+1; i++ {
  245. // nx := float32(i) * step
  246. // positions.Append(
  247. // nx, 0, 0, color.R, color.G, color.B, // line start vertex and color
  248. // nx, chart.baseY, 0, color.R, color.G, color.B, // line end vertex and color
  249. // )
  250. // l := NewLabel(fmt.Sprintf(sx.chart.formatX, float32(i)))
  251. // px, py := ndc2pix(&sx.chart.Panel, nx, chart.baseY)
  252. // l.SetPosition(px, py)
  253. // sx.chart.Add(l)
  254. // }
  255. //
  256. // // Creates geometry using one interlaced VBO
  257. // geom := geometry.NewGeometry()
  258. // geom.AddVBO(gls.NewVBO().
  259. // AddAttrib("VertexPosition", 3).
  260. // AddAttrib("VertexColor", 3).
  261. // SetBuffer(positions),
  262. // )
  263. //
  264. // // Creates material
  265. // mat := material.NewMaterial()
  266. // mat.SetLineWidth(1.0)
  267. // mat.SetShader("shaderChart")
  268. //
  269. // // Initializes the grid graphic
  270. // sx.Graphic.Init(geom, gls.LINES)
  271. // sx.AddMaterial(sx, mat, 0, 0)
  272. // sx.modelMatrixUni.Init("ModelMatrix")
  273. //
  274. // return sx
  275. //}
  276. //
  277. //
  278. // Converts panel ndc coordinates to relative pixels inside panel
  279. func ndc2pix(p *Panel, nx, ny float32) (px, py float32) {
  280. w := p.ContentWidth()
  281. h := p.ContentHeight()
  282. return w * nx, -h * ny
  283. }
  284. //// RenderSetup is called by the renderer before drawing this graphic
  285. //// Calculates the model matrix and transfer to OpenGL.
  286. //func (sx *ChartScaleX) RenderSetup(gs *gls.GLS, rinfo *core.RenderInfo) {
  287. //
  288. // // Set this model matrix the same as the chart panel
  289. // var mm math32.Matrix4
  290. // sx.chart.SetModelMatrix(gs, &mm)
  291. //
  292. // // Sets and transfer the model matrix uniform
  293. // sx.modelMatrixUni.SetMatrix4(&mm)
  294. // sx.modelMatrixUni.Transfer(gs)
  295. //}
  296. //
  297. ////
  298. ////
  299. ////
  300. //// ChartScaleY
  301. ////
  302. ////
  303. ////
  304. //type ChartScaleY struct {
  305. // graphic.Graphic // It is a Graphic
  306. // chart *ChartLine // Container chart
  307. // modelMatrixUni gls.UniformMatrix4f // Model matrix uniform
  308. //}
  309. //
  310. //func newChartScaleY(chart *ChartLine, lines int, color *math32.Color) *ChartScaleY {
  311. //
  312. // sy := new(ChartScaleY)
  313. // sy.chart = chart
  314. //
  315. // // Generates grid lines using Normalized Device Coordinates and
  316. // // considering that the parent panel model coordinates are:
  317. // // 0,0,0 1,0,0
  318. // // +---------------+
  319. // // | |
  320. // // | |
  321. // // +---------------+
  322. // // 0,-1,0 1,-1,0
  323. // positions := math32.NewArrayF32(0, 0)
  324. //
  325. // // Appends scaleY left vertical axis line
  326. // positions.Append(
  327. // chart.baseX, 0, 0, color.R, color.G, color.B, // line start vertex and color
  328. // chart.baseX, -1, 0, color.R, color.G, color.B, // line end vertex and color
  329. // )
  330. // // Appends scale horizontal lines starting from baseX
  331. // step := 1 / (float32(lines) + 1)
  332. // for i := 1; i < lines+1; i++ {
  333. // ny := -float32(i) * step
  334. // positions.Append(
  335. // chart.baseX, ny, 0, color.R, color.G, color.B, // line start vertex and color
  336. // 1, ny, 0, color.R, color.G, color.B, // line end vertex and color
  337. // )
  338. // // l := NewLabel(fmt.Sprintf(sx.chart.formatX, float32(i)))
  339. // // px, py := ndc2pix(&sx.chart.Panel, nx, baseY)
  340. // // l.SetPosition(px, py)
  341. // // sx.chart.Add(l)
  342. // }
  343. //
  344. // // Creates geometry using one interlaced VBO
  345. // geom := geometry.NewGeometry()
  346. // geom.AddVBO(gls.NewVBO().
  347. // AddAttrib("VertexPosition", 3).
  348. // AddAttrib("VertexColor", 3).
  349. // SetBuffer(positions),
  350. // )
  351. //
  352. // // Creates material
  353. // mat := material.NewMaterial()
  354. // mat.SetLineWidth(1.0)
  355. // mat.SetShader("shaderChart")
  356. //
  357. // // Initializes the grid graphic
  358. // sy.Graphic.Init(geom, gls.LINES)
  359. // sy.AddMaterial(sy, mat, 0, 0)
  360. // sy.modelMatrixUni.Init("ModelMatrix")
  361. //
  362. // return sy
  363. //}
  364. //
  365. //// RenderSetup is called by the renderer before drawing this graphic
  366. //// Calculates the model matrix and transfer to OpenGL.
  367. //func (sy *ChartScaleY) RenderSetup(gs *gls.GLS, rinfo *core.RenderInfo) {
  368. //
  369. // // Set this model matrix the same as the chart panel
  370. // var mm math32.Matrix4
  371. // sy.chart.SetModelMatrix(gs, &mm)
  372. //
  373. // // Sets and transfer the model matrix uniform
  374. // sy.modelMatrixUni.SetMatrix4(&mm)
  375. // sy.modelMatrixUni.Transfer(gs)
  376. //}
  377. //
  378. ////
  379. ////
  380. ////
  381. //// ChartGrid
  382. ////
  383. ////
  384. ////
  385. //
  386. //// ChartGrid implements a 2D grid used inside charts
  387. //type ChartGrid struct {
  388. // graphic.Graphic // It is a Graphic
  389. // chart *Panel // Container chart
  390. // modelMatrixUni gls.UniformMatrix4f // Model matrix uniform
  391. //}
  392. //
  393. //// NewChartGrid creates and returns a pointer to a chart grid graphic for the
  394. //// specified parent chart and with the specified number of grid lines and color.
  395. //func NewChartGrid(chart *Panel, xcount, ycount int, color *math32.Color) *ChartGrid {
  396. //
  397. // cg := new(ChartGrid)
  398. // cg.chart = chart
  399. //
  400. // // Generates grid lines using Normalized Device Coordinates and
  401. // // considering that the parent panel model coordinates are:
  402. // // 0,0,0 1,0,0
  403. // // +---------------+
  404. // // | |
  405. // // | |
  406. // // +---------------+
  407. // // 0,-1,0 1,-1,0
  408. // positions := math32.NewArrayF32(0, 0)
  409. // xstep := 1 / (float32(xcount) + 1)
  410. // for xi := 1; xi < xcount+1; xi++ {
  411. // posx := float32(xi) * xstep
  412. // positions.Append(
  413. // posx, 0, 0, color.R, color.G, color.B, // line start vertex and color
  414. // posx, -1, 0, color.R, color.G, color.B, // line end vertex and color
  415. // )
  416. // }
  417. // ystep := 1 / (float32(ycount) + 1)
  418. // for yi := 1; yi < ycount+1; yi++ {
  419. // posy := -float32(yi) * ystep
  420. // positions.Append(
  421. // 0, posy, 0, color.R, color.G, color.B, // line start vertex and color
  422. // 1, posy, 0, color.R, color.G, color.B, // line end vertex and color
  423. // )
  424. // }
  425. //
  426. // // Creates geometry using one interlaced VBO
  427. // geom := geometry.NewGeometry()
  428. // geom.AddVBO(
  429. // gls.NewVBO().
  430. // AddAttrib("VertexPosition", 3).
  431. // AddAttrib("VertexColor", 3).
  432. // SetBuffer(positions),
  433. // )
  434. //
  435. // // Creates material
  436. // mat := material.NewMaterial()
  437. // mat.SetLineWidth(1.0)
  438. // mat.SetShader("shaderChart")
  439. //
  440. // // Initializes the grid graphic
  441. // cg.Graphic.Init(geom, gls.LINES)
  442. // cg.AddMaterial(cg, mat, 0, 0)
  443. // cg.modelMatrixUni.Init("ModelMatrix")
  444. // return cg
  445. //}
  446. //
  447. //// RenderSetup is called by the renderer before drawing this graphic
  448. //// Calculates the model matrix and transfer to OpenGL.
  449. //func (cg *ChartGrid) RenderSetup(gs *gls.GLS, rinfo *core.RenderInfo) {
  450. //
  451. // // Set this model matrix the same as the chart panel
  452. // var mm math32.Matrix4
  453. // cg.chart.SetModelMatrix(gs, &mm)
  454. //
  455. // // Sets and transfer the model matrix uniform
  456. // cg.modelMatrixUni.SetMatrix4(&mm)
  457. // cg.modelMatrixUni.Transfer(gs)
  458. //}
  459. //
  460. ////
  461. ////
  462. ////
  463. //// LineGraph
  464. ////
  465. ////
  466. ////
  467. //
  468. //// LineGraph implemens a 2D line graph
  469. //type LineGraph struct {
  470. // graphic.Graphic // It is a Graphic
  471. // chart *Panel // Container chart
  472. // modelMatrixUni gls.UniformMatrix4f // Model matrix uniform
  473. // name string // Name id
  474. // title string // Title string
  475. // color *math32.Color // Line color
  476. // data []float32 // Data
  477. //}
  478. //
  479. //// newLineGraph creates and returns a pointer to a line graph graphic for the
  480. //// specified parent chart
  481. //func newLineGraph(chart *Panel, name, title string, color *math32.Color, data []float32) *LineGraph {
  482. //
  483. // lg := new(LineGraph)
  484. // lg.chart = chart
  485. // lg.name = name
  486. // lg.title = title
  487. // lg.color = color
  488. // lg.data = data
  489. //
  490. // // Generates graph lines using Normalized Device Coordinates and
  491. // // considering that the parent panel model coordinates are:
  492. // // 0,0,0 1,0,0
  493. // // +---------------+
  494. // // | |
  495. // // | |
  496. // // +---------------+
  497. // // 0,-1,0 1,-1,0
  498. // positions := math32.NewArrayF32(0, 0)
  499. // for i := 0; i < len(data); i++ {
  500. // px := float32(i) / float32(len(data))
  501. // py := -1 + data[i]
  502. // positions.Append(px, py, 0, color.R, color.G, color.B)
  503. // }
  504. //
  505. // // Creates geometry using one interlaced VBO
  506. // geom := geometry.NewGeometry()
  507. // geom.AddVBO(gls.NewVBO().
  508. // AddAttrib("VertexPosition", 3).
  509. // AddAttrib("VertexColor", 3).
  510. // SetBuffer(positions),
  511. // )
  512. //
  513. // // Creates material
  514. // mat := material.NewMaterial()
  515. // mat.SetLineWidth(2.5)
  516. // mat.SetShader("shaderChart")
  517. //
  518. // // Initializes the graphic
  519. // lg.Graphic.Init(geom, gls.LINE_STRIP)
  520. // lg.AddMaterial(lg, mat, 0, 0)
  521. // lg.modelMatrixUni.Init("ModelMatrix")
  522. //
  523. // return lg
  524. //}
  525. //
  526. //// RenderSetup is called by the renderer before drawing this graphic
  527. //// Calculates the model matrix and transfer to OpenGL.
  528. //func (lg *LineGraph) RenderSetup(gs *gls.GLS, rinfo *core.RenderInfo) {
  529. //
  530. // // Set this graphic model matrix the same as the container chart panel
  531. // var mm math32.Matrix4
  532. // lg.chart.SetModelMatrix(gs, &mm)
  533. //
  534. // // Sets and transfer the model matrix uniform
  535. // lg.modelMatrixUni.SetMatrix4(&mm)
  536. // lg.modelMatrixUni.Transfer(gs)
  537. //}
  538. //
  539. // Vertex Shader template
  540. //
  541. const shaderChartVertex = `
  542. #version {{.Version}}
  543. // Vertex attributes
  544. {{template "attributes" .}}
  545. // Input uniforms
  546. uniform mat4 ModelMatrix;
  547. // Outputs for fragment shader
  548. out vec3 Color;
  549. void main() {
  550. Color = VertexColor;
  551. // Set position
  552. vec4 pos = vec4(VertexPosition.xyz, 1);
  553. gl_Position = ModelMatrix * pos;
  554. }
  555. `
  556. //
  557. // Fragment Shader template
  558. //
  559. const shaderChartFrag = `
  560. #version {{.Version}}
  561. in vec3 Color;
  562. out vec4 FragColor;
  563. void main() {
  564. FragColor = vec4(Color, 1.0);
  565. }
  566. `