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.
- checksums.yaml +4 -4
- data/src/js/components/Alert.js +1 -1
- data/src/js/components/Autocomplete.js +1 -1
- data/src/js/components/AutocompleteMenu.js +1 -1
- data/src/js/components/BarChart.js +452 -0
- data/src/js/components/Btn.js +1 -1
- data/src/js/components/Checkbox.js +1 -1
- data/src/js/components/DateInput.js +1 -1
- data/src/js/components/DateMenu.js +1 -1
- data/src/js/components/DateTimeRanger.js +1 -1
- data/src/js/components/Datepicker.js +1 -1
- data/src/js/components/DatepickerBtnArrow.js +1 -1
- data/src/js/components/Dropdown.js +1 -1
- data/src/js/components/LineChart.js +535 -0
- data/src/js/components/Menu.js +1 -1
- data/src/js/components/Modal.js +76 -31
- data/src/js/components/Navbar.js +1 -1
- data/src/js/components/Radio.js +1 -1
- data/src/js/components/SearchDropdown.js +1 -1
- data/src/js/components/Sidebar.js +1 -1
- data/src/js/components/Tabbox.js +1 -1
- data/src/js/components/TimeInput.js +1 -1
- data/src/js/components/TimeMenu.js +1 -1
- data/src/js/components/Timepicker.js +1 -1
- data/src/js/components/Toast.js +1 -1
- data/src/js/components/ToastItem.js +1 -1
- data/src/js/components/Tooltip.js +1 -1
- data/src/js/decorators/chartCommon.js +218 -0
- data/src/js/{utils → decorators}/supportDom.js +1 -1
- data/src/js/index.js +6 -2
- data/src/js/jquery/bindModalFn.js +57 -6
- data/src/js/utils/index.js +10 -1
- data/src/js/utils/isDef.js +3 -0
- data/src/js/utils/isInt.js +3 -0
- data/src/js/utils/isUndef.js +3 -0
- data/src/sass/_beyond.scss +1 -0
- data/src/sass/components/_breadcrumb.scss +4 -4
- data/src/sass/components/_chart.scss +14 -0
- data/src/sass/components/_mega-menu.scss +22 -28
- data/src/sass/components/_nav.scss +1 -0
- metadata +28 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d61bb2b7f5dafc4fab6358ca8c032488a4875977edfab11d8b7f3ffe0ac0cf39
|
4
|
+
data.tar.gz: 9c139ae7a4e414096c3a9549aecddb07fe662b021032b97bb6c1667ba48cd94d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 240333d51da01189d62bdcb0e46ee6e23dfb9293afb633eda0e981cf8e6dfb6246a6b5daff0f024586c005ae740bf7c77b14524aedcd0a728e570da654f6bab8
|
7
|
+
data.tar.gz: 275a9b0ad65ff19125d3c9420101e7cd0a29467a404cbe171c3d189aab11f9d4daf2a1801a0d231127ce805a036e542ed7cb877b0ba2e6e8430ac3558db2f6c9
|
data/src/js/components/Alert.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import AutocompleteMenu from './AutocompleteMenu'
|
2
2
|
import promisify from '../utils/promisify'
|
3
|
-
import supportDom from '../
|
3
|
+
import supportDom from '../decorators/supportDom'
|
4
4
|
import { debounce, noop } from '../utils'
|
5
5
|
|
6
6
|
const defaultRenderMenuItem = row => {
|
@@ -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
|
+
}
|