chart.go 17 KB

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