beyond-rails 0.0.187 → 0.0.192

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/src/js/components/Alert.js +1 -1
  3. data/src/js/components/Autocomplete.js +1 -1
  4. data/src/js/components/AutocompleteMenu.js +1 -1
  5. data/src/js/components/BarChart.js +452 -0
  6. data/src/js/components/Btn.js +1 -1
  7. data/src/js/components/Checkbox.js +1 -1
  8. data/src/js/components/DateInput.js +1 -1
  9. data/src/js/components/DateMenu.js +1 -1
  10. data/src/js/components/DateTimeRanger.js +1 -1
  11. data/src/js/components/Datepicker.js +1 -1
  12. data/src/js/components/DatepickerBtnArrow.js +1 -1
  13. data/src/js/components/Dropdown.js +1 -1
  14. data/src/js/components/LineChart.js +535 -0
  15. data/src/js/components/Menu.js +1 -1
  16. data/src/js/components/Modal.js +76 -31
  17. data/src/js/components/Navbar.js +1 -1
  18. data/src/js/components/Radio.js +1 -1
  19. data/src/js/components/SearchDropdown.js +1 -1
  20. data/src/js/components/Sidebar.js +1 -1
  21. data/src/js/components/Tabbox.js +1 -1
  22. data/src/js/components/TimeInput.js +1 -1
  23. data/src/js/components/TimeMenu.js +1 -1
  24. data/src/js/components/Timepicker.js +1 -1
  25. data/src/js/components/Toast.js +1 -1
  26. data/src/js/components/ToastItem.js +1 -1
  27. data/src/js/components/Tooltip.js +1 -1
  28. data/src/js/decorators/chartCommon.js +218 -0
  29. data/src/js/{utils → decorators}/supportDom.js +1 -1
  30. data/src/js/index.js +6 -2
  31. data/src/js/jquery/bindModalFn.js +57 -6
  32. data/src/js/utils/index.js +10 -1
  33. data/src/js/utils/isDef.js +3 -0
  34. data/src/js/utils/isInt.js +3 -0
  35. data/src/js/utils/isUndef.js +3 -0
  36. data/src/sass/_beyond.scss +1 -0
  37. data/src/sass/abstracts/_variables.scss +1 -1
  38. data/src/sass/components/_breadcrumb.scss +3 -0
  39. data/src/sass/components/_chart.scss +14 -0
  40. data/src/sass/components/_mega-menu.scss +24 -28
  41. data/src/sass/components/_nav.scss +1 -0
  42. metadata +28 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fc1a2f20f1ad5420ea9f42be5223fff92b69278a4984d01416c87dec84d16238
4
- data.tar.gz: 2d4319f9383eea996fad2c5b31b844ded13a9366677c63a79be7a8de7ae5bfcc
3
+ metadata.gz: b6454b3f8506a63482385f68ac87aad1024ff1527e0b66c43faed75dcef83c7c
4
+ data.tar.gz: 967ce7aa6a0fcbe69cbf4393c52a906afe9d38a7b9bd4105b22fe433de2f6032
5
5
  SHA512:
6
- metadata.gz: b9a6fb15c1957154200249b6418892e8ba802f72a6c98bb12f59a954b8cc1e3002d11a8126f3e74a9381ec8c44ba69f1043658dc3c4b8be7cb15afbd500d6c4e
7
- data.tar.gz: 74759c3373679f383b886dc85f04a3e2c79279ec9e2ddae86255518728eca253e95f4b0247f2540ccd1de1737984d0ce988fd6d28c62c288b7cee95438e7d6bc
6
+ metadata.gz: 38d44f307931f8155b9f9660bc22eae0f87d1ca74273cb80366fceb44d25ece3ad9aef1ff60ec54feb3e0aa584dbbba386fa26ee84dcb096d6298b9789053b88
7
+ data.tar.gz: c2dd56c84389d4c4ffffd0c2bbcb0aac5b4544eaa2ca5efc6f8e167dbb697fc9315b1c3ba870cfedb8096b59da08d736ccf53f5a89f4bce17914b2cc8b1d67d3
@@ -1,4 +1,4 @@
1
- import supportDom from '../utils/supportDom'
1
+ import supportDom from '../decorators/supportDom'
2
2
 
3
3
  @supportDom
4
4
  export default class Alert {
@@ -1,6 +1,6 @@
1
1
  import AutocompleteMenu from './AutocompleteMenu'
2
2
  import promisify from '../utils/promisify'
3
- import supportDom from '../utils/supportDom'
3
+ import supportDom from '../decorators/supportDom'
4
4
  import { debounce, noop } from '../utils'
5
5
 
6
6
  const defaultRenderMenuItem = row => {
@@ -1,5 +1,5 @@
1
1
  import getFloatedTargetPos from '../utils/getFloatedTargetPos'
2
- import supportDom from '../utils/supportDom'
2
+ import supportDom from '../decorators/supportDom'
3
3
  import { toPixel } from '../utils'
4
4
 
5
5
  @supportDom
@@ -0,0 +1,452 @@
1
+ import supportDom from '../decorators/supportDom'
2
+ import chartCommon from '../decorators/chartCommon'
3
+ import isDef from '../utils/isDef'
4
+ import isUndef from '../utils/isUndef'
5
+ import isInt from '../utils/isInt'
6
+ import { mem, range, sortBy, throttle, uniqBy } from '../utils'
7
+
8
+ const defaultBarStyles = [
9
+ '#5469d4',
10
+ '#7c54d4',
11
+ '#a254d4'
12
+ ]
13
+
14
+ @supportDom
15
+ @chartCommon
16
+ export default class BarChart {
17
+
18
+ constructor(dom, options = {}) {
19
+ this.dom = dom
20
+ this.options = options
21
+ this.bars = []
22
+
23
+ this.height = options.height || 186
24
+ this.width = options.width
25
+
26
+ this.toYLabel = isDef(options.toYLabel) ? mem(options.toYLabel) : (v => v)
27
+
28
+ this.xPadding = isDef(options.xPadding) ? options.xPadding : 20
29
+ this.yPadding = isDef(options.yPadding) ? options.yPadding : 20
30
+
31
+ this.yStep = options.yStep
32
+ this.yGutter = isDef(options.yGutter) ? options.yGutter : 10
33
+
34
+ this.xLabelMargin = isDef(options.xLabelMargin) ? options.xLabelMargin : 10
35
+ this.yLabelMargin = isDef(options.yLanelMargin) ? options.yLabelMargin : 14
36
+
37
+ this.fontSize = options.fontSize || 12
38
+ this.bgColor = options.bgColor || '#fff'
39
+ this.barStyles = options.barStyles || defaultBarStyles
40
+
41
+ this.yLabelRows = []
42
+ this.barPosMap = new Map()
43
+
44
+ this.init()
45
+ }
46
+
47
+ init() {
48
+ this.setDpr()
49
+ this.setDomWidthIfNeeded()
50
+ this.setCanvas()
51
+ this.clear()
52
+ this.bindMedia()
53
+ this.bindBarVisible()
54
+ }
55
+
56
+ get contentWidth() {
57
+ return this.width - (this.xPadding * 2) - this.yLabelMargin -
58
+ this.yLabelWidth - this.halfXLabelWidth
59
+ }
60
+
61
+ get contentHeight() {
62
+ return this.height - (this.yPadding * 2) - this.xLabelMargin - this.xLabelHeight
63
+ }
64
+
65
+ get firstY() {
66
+ return this.yLabelRows[0].value
67
+ }
68
+
69
+ get halfXLabelWidth() {
70
+ return this.xLabelWidth / 2
71
+ }
72
+
73
+ get halfYLabelHeight() {
74
+ return this.yLabelHeight / 2
75
+ }
76
+
77
+ get xAxisStart() {
78
+ return this.xPadding + this.halfXLabelWidth
79
+ }
80
+
81
+ get xAxisEnd() {
82
+ return this.width - this.xPadding - this.yLabelWidth -
83
+ this.yLabelMargin - this.halfXLabelWidth
84
+ }
85
+
86
+ get yAxisStart() {
87
+ return this.height - this.yPadding - this.xLabelHeight -
88
+ this.xLabelMargin + this.halfYLabelHeight
89
+ }
90
+
91
+ get yAxisEnd() {
92
+ return this.yAxisStart - this.contentHeight
93
+ }
94
+
95
+ get lastY() {
96
+ const { yLabelRows } = this
97
+ return yLabelRows[yLabelRows.length - 1].value
98
+ }
99
+
100
+ get yRatio() {
101
+ const lineHeight = this.yAxisStart - this.yAxisEnd
102
+ const yDelta = Math.abs(this.lastY - this.firstY)
103
+ return yDelta / lineHeight
104
+ }
105
+
106
+ bindBarVisible() {
107
+ if (isUndef(this.options.onBarMouseOver)) {
108
+ return
109
+ }
110
+ if (! ('onmousemove' in this.canvas)) {
111
+ return
112
+ }
113
+ this.addLayer()
114
+ const canvas = this.getHighestCanvas()
115
+ this.addEvent(canvas, 'mousemove', throttle(this.handleMouseMove.bind(this), 30))
116
+ }
117
+
118
+ clearBarPos() {
119
+ this.barPosMap.clear()
120
+ }
121
+
122
+ draw() {
123
+ this.clear()
124
+ this.drawXAxis()
125
+ this.drawYAxis()
126
+ this.drawBgLines()
127
+ this.drawBars()
128
+ }
129
+
130
+ drawBars() {
131
+ const { barPosMap, barStyles, ctx, xLabelRows } = this
132
+ xLabelRows.forEach((row, i) => {
133
+ const pos = barPosMap.get(row)
134
+ if (pos) {
135
+ const { x, y, width, height } = pos
136
+ ctx.fillStyle = barStyles[i] || '#000'
137
+ ctx.fillRect(x, y, width, height)
138
+ }
139
+ })
140
+ }
141
+
142
+ drawBgLines() {
143
+
144
+ const { ctx, yLabelRows, firstY, yAxisStart, yRatio } = this
145
+ const xStart = this.xPadding
146
+ const xEnd = this.width - this.xPadding - this.yLabelWidth - this.yLabelMargin
147
+
148
+ ctx.strokeStyle = 'rgba(224, 224, 224, .5)'
149
+ ctx.lineWidth = 1
150
+
151
+ yLabelRows.forEach(row => {
152
+
153
+ const y = yAxisStart - ((row.value - firstY) / yRatio)
154
+
155
+ ctx.beginPath()
156
+ ctx.moveTo(xStart, y)
157
+ ctx.lineTo(xEnd, y)
158
+ ctx.stroke()
159
+ ctx.closePath
160
+ })
161
+ }
162
+
163
+ drawXAxis() {
164
+ const { ctx, xLabelRows, xAxisStart, xAxisEnd } = this
165
+ const totalWidth = xLabelRows.reduce((w, row) => w + row.length, 0)
166
+ const contentWidth = xAxisEnd - xAxisStart
167
+ const gutter = (contentWidth - totalWidth) / (xLabelRows.length - 1)
168
+ const y = this.height - this.yPadding
169
+ let x = xAxisStart
170
+
171
+ ctx.textBaseline = 'top'
172
+ ctx.fillStyle = '#3c4257'
173
+
174
+ xLabelRows.forEach((row, i) => {
175
+ ctx.fillText(row.label, x, y)
176
+ x += (row.length + gutter)
177
+ })
178
+ }
179
+
180
+ drawYAxis() {
181
+ const { ctx, firstY, yLabelRows, yAxisStart, yRatio, yLabelHeight } = this
182
+ const x = this.width - this.xPadding
183
+ const delta = yLabelHeight * .45
184
+
185
+ ctx.fillStyle = '#3c4257'
186
+ ctx.textAlign = 'right'
187
+
188
+ yLabelRows.forEach(row => {
189
+ const y = yAxisStart - ((row.value - firstY) / yRatio)
190
+ ctx.fillText(row.label, x, y - delta)
191
+ })
192
+ }
193
+
194
+ findMouseOverBarPos(canvasMousePos) {
195
+ const { barPosMap, xLabelRows } = this
196
+ const { x: mouseX, y: mouseY } = canvasMousePos
197
+ let index = 0
198
+ for (const row of xLabelRows) {
199
+ const pos = barPosMap.get(row)
200
+ const { x, y, width, height } = pos
201
+ if ((x <= mouseX) && (mouseX <= (x + width)) &&
202
+ (y <= mouseY) && (mouseY <= (y + height))) {
203
+ return { index, row, pos }
204
+ }
205
+ ++index
206
+ }
207
+ }
208
+
209
+ drawBarGlow(res) {
210
+ this.clearBarGlow()
211
+ const ctx = this.firstLayer.canvas.getContext('2d')
212
+ ctx.save()
213
+ const { x, y, width, height } = res.pos
214
+ const glowWidth = width * 1.4
215
+ const glowHeight = ((glowWidth - width) / 2) + height
216
+ const glowX = x - ((glowWidth - width) / 2)
217
+ const glowY = y - (glowHeight - height)
218
+ ctx.globalAlpha = 0.2
219
+ ctx.fillStyle = this.barStyles[res.index]
220
+ ctx.fillRect(glowX, glowY, glowWidth, glowHeight)
221
+ ctx.restore()
222
+ }
223
+
224
+ clearBarGlow() {
225
+ const ctx = this.firstLayer.canvas.getContext('2d')
226
+ ctx.clearRect(0, 0, this.width, this.height)
227
+ }
228
+
229
+ handleMouseMove(event) {
230
+ const canvasMousePos = this.getMousePosInCanvas(event)
231
+ const mouseOverRes = this.findMouseOverBarPos(canvasMousePos)
232
+ const { lastMouseOverRes } = this
233
+
234
+ // don't repaint the same index
235
+ if (lastMouseOverRes && mouseOverRes && (lastMouseOverRes.index === mouseOverRes.index)) {
236
+ return
237
+ }
238
+
239
+ // don't re-clear
240
+ if (isUndef(mouseOverRes) && isUndef(lastMouseOverRes)) {
241
+ return
242
+ }
243
+
244
+ if (mouseOverRes) {
245
+ this.drawBarGlow(mouseOverRes)
246
+ }
247
+ else {
248
+ this.clearBarGlow()
249
+ }
250
+ this.lastMouseOverRes = mouseOverRes
251
+ const mousePos = this.getMousePos(canvasMousePos)
252
+ const res = this.getBarMouseOverRes(mouseOverRes)
253
+ this.options.onBarMouseOver(mousePos, res)
254
+ }
255
+
256
+ getBarMouseOverRes(res) {
257
+ if (res) {
258
+ return {
259
+ index: res.index,
260
+ bar: res.row
261
+ }
262
+ }
263
+ }
264
+
265
+ getUniqSortedBars() {
266
+ const bars = uniqBy(this.bars, 'value')
267
+ return sortBy(bars, ['value'])
268
+ }
269
+
270
+ getXLabelRows() {
271
+ const { ctx } = this
272
+ return this.bars.map(bar => {
273
+ const { label } = bar
274
+ return {
275
+ label,
276
+ length: ctx.measureText(label).width,
277
+ value: bar.value
278
+ }
279
+ })
280
+ }
281
+
282
+ getYLabelRows() {
283
+
284
+ const { contentHeight } = this
285
+ const gutter = this.yGutter
286
+ const toLabel = this.toYLabel
287
+ const measureLength = () => this.fontSize
288
+
289
+ const bars = this.getUniqSortedBars()
290
+ const firstBar = bars[0]
291
+ const lastBar = bars[bars.length - 1]
292
+
293
+ if (bars.length <= 2) {
294
+ return bars.map(bar => {
295
+ const value = bar.value
296
+ const label = toLabel(value)
297
+ const length = measureLength()
298
+ return { label, length, value }
299
+ })
300
+ }
301
+
302
+ const firstBarValue = firstBar.value
303
+ const lastBarValue = lastBar.value
304
+ const barCount = bars.length
305
+
306
+ let step = this.yStep
307
+
308
+ if (isUndef(step)) {
309
+ step = this.getAutoStep(firstBarValue, lastBarValue, barCount)
310
+ }
311
+
312
+ const [stepStart, stepEnd] = this.getStepStartEnd(step, firstBarValue, lastBarValue)
313
+ const values = range(stepStart, stepEnd + step, step)
314
+ .map(value => {
315
+ return isInt(value) ? value : parseFloat(value.toFixed(2))
316
+ })
317
+
318
+ const valueCount = values.length
319
+ const initialGap = parseInt((valueCount - 2) / 2, 10)
320
+
321
+ const firstValue = values[0]
322
+ const lastValue = values[valueCount - 1]
323
+ const firstLabel = toLabel(firstValue)
324
+ const lastLabel = toLabel(lastValue)
325
+
326
+ let stepRows = [
327
+ { label: firstLabel, length: measureLength(), value: firstValue },
328
+ { label: lastLabel, length: measureLength(), value: lastValue },
329
+ ]
330
+
331
+ for (let gap = initialGap; gap >= 0; gap--) {
332
+ const { lengthTotal, rows } = this.getLengthTotalData(gap, gutter, values, measureLength, toLabel)
333
+ if (lengthTotal <= contentHeight) {
334
+ stepRows = rows
335
+ continue
336
+ }
337
+ return stepRows
338
+ }
339
+ return stepRows
340
+ }
341
+
342
+ refresh() {
343
+ this.raf(() => {
344
+ this.clearBarPos()
345
+ this.setDomWidthIfNeeded()
346
+ this.setCanvasSize(this.canvas)
347
+ this.setLabelWidths()
348
+ this.setLabelHeights()
349
+ this.setAxisData()
350
+ this.setBarPos()
351
+ this.draw()
352
+ })
353
+ }
354
+
355
+ setAxisData() {
356
+ this.xLabelRows = this.getXLabelRows()
357
+ this.yLabelRows = this.getYLabelRows()
358
+ }
359
+
360
+ setBarPos() {
361
+ const barWidth = 45
362
+ const halfBarWidth = parseInt(barWidth / 2, 10)
363
+ const { barPosMap, firstY, xLabelRows, xAxisStart, xAxisEnd, yAxisStart, yRatio } = this
364
+ const totalWidth = xLabelRows.reduce((w, row) => w + row.length, 0)
365
+ const contentWidth = xAxisEnd - xAxisStart
366
+ const gutter = (contentWidth - totalWidth) / (xLabelRows.length - 1)
367
+
368
+ const { centerPoints } = xLabelRows.reduce((res, row, i) => {
369
+ const { x } = res
370
+ const centerPoints = res.centerPoints.slice()
371
+ const width = row.length
372
+ const halfWidth = parseInt(width / 2, 10)
373
+ centerPoints.push(x + halfWidth)
374
+ return {
375
+ x: x + (width + gutter),
376
+ centerPoints
377
+ }
378
+ }, {
379
+ x: xAxisStart,
380
+ centerPoints: []
381
+ })
382
+
383
+ xLabelRows.forEach((row, i) => {
384
+ const barHeight = (row.value - firstY) / yRatio
385
+ const centerPoint = centerPoints[i]
386
+ const x = centerPoint - halfBarWidth
387
+ const y = yAxisStart - barHeight
388
+ const pos = { x, y, width: barWidth, height: barHeight }
389
+ barPosMap.set(row, pos)
390
+ })
391
+ }
392
+
393
+ setData(bars) {
394
+ this.clearBarPos()
395
+ this.bars = bars
396
+ this.setLabelWidths()
397
+ this.setLabelHeights()
398
+ this.setAxisData()
399
+ this.setBarPos()
400
+ this.raf(() => this.draw())
401
+ }
402
+
403
+ setLabelWidths() {
404
+
405
+ const { toYLabel, ctx } = this
406
+ const res = this.bars.filter(bar => bar)
407
+ .reduce((o, bar) => {
408
+
409
+ const { xLabelWidth, yLabelWidth } = o
410
+ const measuredXLabelWidth = ctx.measureText(bar.label).width
411
+ const measuredYLabelWidth = ctx.measureText(toYLabel(bar.value)).width
412
+
413
+ return {
414
+ xLabelWidth: (measuredXLabelWidth > xLabelWidth) ? measuredXLabelWidth : xLabelWidth,
415
+ yLabelWidth: (measuredYLabelWidth > yLabelWidth) ? measuredYLabelWidth : yLabelWidth,
416
+ }
417
+ }, {
418
+ xLabelWidth: 0,
419
+ yLabelWidth: 0
420
+ })
421
+
422
+ this.xLabelWidth = res.xLabelWidth
423
+ this.yLabelWidth = res.yLabelWidth
424
+ }
425
+
426
+ setLabelHeights() {
427
+ this.xLabelHeight = this.fontSize
428
+ this.yLabelHeight = this.fontSize
429
+ }
430
+
431
+ handleDprChange() {
432
+ this.setDpr()
433
+ this.refresh()
434
+ }
435
+
436
+ destroy() {
437
+ const { dom, canvas } = this
438
+ const { toYLabel } = this.options
439
+
440
+ if (isDef(toYLabel)) {
441
+ mem.clear(this.toYLabel)
442
+ }
443
+ this.clearBarPos()
444
+ this.unbindMedia()
445
+ this.removeAllLayers()
446
+
447
+ if (dom.contains(canvas)) {
448
+ dom.removeChild(canvas)
449
+ dom.style.removeProperty('position')
450
+ }
451
+ }
452
+ }