beyond-rails 0.0.188 → 0.0.193

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) 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/components/_breadcrumb.scss +4 -4
  38. data/src/sass/components/_chart.scss +14 -0
  39. data/src/sass/components/_mega-menu.scss +22 -28
  40. data/src/sass/components/_nav.scss +1 -0
  41. metadata +28 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a72c8e57a80e8c6a653ea5356f23c3be9ce034f88d23ec5e42c3a2a6256bda6f
4
- data.tar.gz: cb191ff4300f1f09c79162109b85d44f0e07f0c86f4926b40654f83f25d2dc98
3
+ metadata.gz: d61bb2b7f5dafc4fab6358ca8c032488a4875977edfab11d8b7f3ffe0ac0cf39
4
+ data.tar.gz: 9c139ae7a4e414096c3a9549aecddb07fe662b021032b97bb6c1667ba48cd94d
5
5
  SHA512:
6
- metadata.gz: 12b25834e8759f6c421a785e1fc6e41d5095e197a383f8df7c8f8c85ed9cb35bd6651793e63dfcdb8071cf7a94cb495ac95b42c924f02c453b9e45599a25af00
7
- data.tar.gz: 6b308a81c3ae0cadb78dcacf76fcf41ef76b5f0bae1b79685333632938eb697690093cba2f4db84d3fb131e9fdb934a9b57407809191c9f7d86719c962f8118c
6
+ metadata.gz: 240333d51da01189d62bdcb0e46ee6e23dfb9293afb633eda0e981cf8e6dfb6246a6b5daff0f024586c005ae740bf7c77b14524aedcd0a728e570da654f6bab8
7
+ data.tar.gz: 275a9b0ad65ff19125d3c9420101e7cd0a29467a404cbe171c3d189aab11f9d4daf2a1801a0d231127ce805a036e542ed7cb877b0ba2e6e8430ac3558db2f6c9
@@ -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
+ }