beyond-rails 0.0.240 → 0.0.246
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/src/js/components/BarChart.js +3 -8
- data/src/js/components/LineChart.js +11 -48
- data/src/js/components/MonthInput.js +75 -0
- data/src/js/components/MonthMenu.js +262 -0
- data/src/js/components/Monthpicker.js +90 -0
- data/src/js/components/PieChart.js +256 -0
- data/src/js/consts/index.js +10 -0
- data/src/js/decorators/chartCommon.js +67 -1
- data/src/js/decorators/supportDom.js +6 -1
- data/src/js/index.js +6 -0
- data/src/js/utils/index.js +10 -0
- data/src/js/utils/isFn.js +3 -0
- data/src/sass/_beyond.scss +1 -0
- data/src/sass/components/_chart.scss +20 -0
- data/src/sass/components/_month-menu.scss +70 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ebefc15d0cab8d8554a18f030ae3041af23f3aab56633bd12aa9e80f823454d9
|
4
|
+
data.tar.gz: a54e416999fce854ecdcc3194d3e7226475f56f8d3ae63d59d638a1651eb8751
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: acb1c4dba756a4d2fa6a0ca378c02e52d2ffb7703bc5d13d1ff298e9604e76250c7124066918e7b45809355f358d100f2b8a293be81292ec00579d93a91433f9
|
7
|
+
data.tar.gz: 78dc63e30de5eb027bba31a7cbdefe1c9737774f3090dc69a3f2e243a3d2ffd9a2bb17a33248e6f1d5c5928b5558f50629d460fac15e5eef96d2a4bfb8b66604
|
@@ -4,12 +4,7 @@ import isDef from '../utils/isDef'
|
|
4
4
|
import isUndef from '../utils/isUndef'
|
5
5
|
import isInt from '../utils/isInt'
|
6
6
|
import { mem, range, sortBy, throttle, uniqBy } from '../utils'
|
7
|
-
|
8
|
-
const defaultBarStyles = [
|
9
|
-
'#5469d4',
|
10
|
-
'#7c54d4',
|
11
|
-
'#a254d4'
|
12
|
-
]
|
7
|
+
import { DEFAULT_CHART_STYLES } from '../consts'
|
13
8
|
|
14
9
|
@supportDom
|
15
10
|
@chartCommon
|
@@ -35,8 +30,8 @@ export default class BarChart {
|
|
35
30
|
this.yLabelMargin = isDef(options.yLanelMargin) ? options.yLabelMargin : 14
|
36
31
|
|
37
32
|
this.fontSize = options.fontSize || 12
|
38
|
-
this.
|
39
|
-
this.barStyles = options.barStyles ||
|
33
|
+
this.bg = options.bg || '#fff'
|
34
|
+
this.barStyles = options.barStyles || DEFAULT_CHART_STYLES
|
40
35
|
|
41
36
|
this.yLabelRows = []
|
42
37
|
this.barPosMap = new Map()
|
@@ -3,6 +3,7 @@ import chartCommon from '../decorators/chartCommon'
|
|
3
3
|
import isDef from '../utils/isDef'
|
4
4
|
import isUndef from '../utils/isUndef'
|
5
5
|
import { mem, range, sortBy, throttle, uniqBy } from '../utils'
|
6
|
+
import { DEFAULT_CHART_STYLES } from '../consts'
|
6
7
|
|
7
8
|
/**
|
8
9
|
* -------------------------------------------------------------------------------------------------
|
@@ -27,11 +28,6 @@ import { mem, range, sortBy, throttle, uniqBy } from '../utils'
|
|
27
28
|
* v |
|
28
29
|
* --------------------------------------------------------------------------------------------------
|
29
30
|
**/
|
30
|
-
const defaultLineStyles = [
|
31
|
-
'#5469d4',
|
32
|
-
'#7c54d4',
|
33
|
-
'#a254d4'
|
34
|
-
]
|
35
31
|
|
36
32
|
@supportDom
|
37
33
|
@chartCommon
|
@@ -56,16 +52,15 @@ export default class LineChart {
|
|
56
52
|
this.xLabelMargin = isDef(options.xLabelMargin) ? options.xLabelMargin : 10
|
57
53
|
this.yLabelMargin = isDef(options.yLanelMargin) ? options.yLabelMargin : 10
|
58
54
|
|
59
|
-
this.lineStyles = options.lineStyles ||
|
55
|
+
this.lineStyles = options.lineStyles || DEFAULT_CHART_STYLES
|
60
56
|
|
61
|
-
this.
|
57
|
+
this.bg = options.bg || '#fff'
|
62
58
|
this.fontSize = options.fontSize || 12
|
63
59
|
|
64
60
|
this.xStep = options.xStep
|
65
61
|
this.yStep = options.yStep
|
66
62
|
|
67
63
|
this.lineLabels = options.lineLabels || []
|
68
|
-
this.lineLabelMargin = isDef(options.lineLabelMargin) ? options.lineLabelMargin : 20
|
69
64
|
|
70
65
|
this.pointPosMap = new Map()
|
71
66
|
this.xLabelRows = []
|
@@ -78,6 +73,7 @@ export default class LineChart {
|
|
78
73
|
this.setDpr()
|
79
74
|
this.setDomSizeIfNeeded()
|
80
75
|
this.setCanvas()
|
76
|
+
this.setLabelBox()
|
81
77
|
this.clear()
|
82
78
|
this.bindMedia()
|
83
79
|
this.bindPointMouseOver()
|
@@ -93,8 +89,7 @@ export default class LineChart {
|
|
93
89
|
}
|
94
90
|
|
95
91
|
get contentHeight() {
|
96
|
-
return this.height - (this.yPadding * 2) - this.xLabelMargin -
|
97
|
-
this.xLabelHeight - this.lineLabelBoxHeight
|
92
|
+
return this.height - (this.yPadding * 2) - this.xLabelMargin - this.xLabelHeight
|
98
93
|
}
|
99
94
|
|
100
95
|
get firstX() {
|
@@ -115,17 +110,6 @@ export default class LineChart {
|
|
115
110
|
return yLabelRows[yLabelRows.length - 1].value
|
116
111
|
}
|
117
112
|
|
118
|
-
get lineLabelHeight() {
|
119
|
-
return this.fontSize
|
120
|
-
}
|
121
|
-
|
122
|
-
get lineLabelBoxHeight() {
|
123
|
-
if (this.lineLabels.length > 0) {
|
124
|
-
return this.lineLabelMargin + this.lineLabelHeight
|
125
|
-
}
|
126
|
-
return 0
|
127
|
-
}
|
128
|
-
|
129
113
|
get xAxisStart() {
|
130
114
|
return this.xPadding + (this.xLabelWidth / 2)
|
131
115
|
}
|
@@ -145,7 +129,7 @@ export default class LineChart {
|
|
145
129
|
}
|
146
130
|
|
147
131
|
get yAxisStart() {
|
148
|
-
return this.height - this.yPadding -
|
132
|
+
return this.height - this.yPadding -
|
149
133
|
this.xLabelHeight - this.xLabelMargin + (this.yLabelHeight / 2)
|
150
134
|
}
|
151
135
|
|
@@ -185,7 +169,6 @@ export default class LineChart {
|
|
185
169
|
this.drawYAxis()
|
186
170
|
this.drawBgLines()
|
187
171
|
this.drawLines()
|
188
|
-
this.drawLineLables()
|
189
172
|
}
|
190
173
|
|
191
174
|
drawBgLines() {
|
@@ -232,29 +215,6 @@ export default class LineChart {
|
|
232
215
|
})
|
233
216
|
}
|
234
217
|
|
235
|
-
drawLineLables() {
|
236
|
-
const { ctx, lineStyles, lineLabelHeight } = this
|
237
|
-
const rectSize = 7
|
238
|
-
|
239
|
-
const rectGutter = 7
|
240
|
-
const labelGutter = 14
|
241
|
-
const rectMargin = 1
|
242
|
-
const y = this.height - this.yPadding
|
243
|
-
let x = this.xPadding
|
244
|
-
|
245
|
-
this.lineLabels.forEach((name, i) => {
|
246
|
-
ctx.fillStyle = lineStyles[i] || '#000'
|
247
|
-
ctx.fillRect(x, y - lineLabelHeight + rectMargin, rectSize, rectSize)
|
248
|
-
|
249
|
-
x += (rectSize + rectGutter)
|
250
|
-
ctx.fillStyle = '#000'
|
251
|
-
ctx.textAlign = 'left'
|
252
|
-
ctx.textBaseline = 'top'
|
253
|
-
ctx.fillText(name, x, y - lineLabelHeight)
|
254
|
-
x += (ctx.measureText(name).width + labelGutter)
|
255
|
-
})
|
256
|
-
}
|
257
|
-
|
258
218
|
clearVerticalLine() {
|
259
219
|
const { ctx } = this.firstLayer
|
260
220
|
ctx.clearRect(0, 0, this.width, this.height)
|
@@ -279,7 +239,7 @@ export default class LineChart {
|
|
279
239
|
drawXAxis() {
|
280
240
|
const { ctx, firstX, xLabelRows, xAxisStart, xRatio } = this
|
281
241
|
|
282
|
-
const y = this.height - this.yPadding
|
242
|
+
const y = this.height - this.yPadding
|
283
243
|
|
284
244
|
const scaleMargin = 4
|
285
245
|
const scaleSize = 4
|
@@ -538,7 +498,10 @@ export default class LineChart {
|
|
538
498
|
return this.raf(() => this.clear())
|
539
499
|
}
|
540
500
|
this.setPointPos()
|
541
|
-
this.raf(() =>
|
501
|
+
this.raf(() => {
|
502
|
+
this.drawLabels(this.lineLabels, this.lineStyles)
|
503
|
+
this.draw()
|
504
|
+
})
|
542
505
|
}
|
543
506
|
|
544
507
|
setPointPos() {
|
@@ -0,0 +1,75 @@
|
|
1
|
+
import { DEFAULT_TIMEZONE } from '../consts'
|
2
|
+
import supportDom from '../decorators/supportDom'
|
3
|
+
import isTouchDevice from '../utils/isTouchDevice'
|
4
|
+
import { format } from '../utils'
|
5
|
+
|
6
|
+
@supportDom
|
7
|
+
export default class MonthInput {
|
8
|
+
|
9
|
+
constructor(dom, date, options = {}) {
|
10
|
+
this.active = false
|
11
|
+
this.danger = false
|
12
|
+
this.dom = dom
|
13
|
+
this.date = date
|
14
|
+
this.options = options
|
15
|
+
this.tz = options.tz || DEFAULT_TIMEZONE
|
16
|
+
this.datePattern = options.datePattern || 'yyyy/MM'
|
17
|
+
this.init()
|
18
|
+
}
|
19
|
+
|
20
|
+
focus() {
|
21
|
+
this.dom.focus()
|
22
|
+
}
|
23
|
+
|
24
|
+
init() {
|
25
|
+
this.initInput()
|
26
|
+
this.addEvents()
|
27
|
+
}
|
28
|
+
|
29
|
+
initInput() {
|
30
|
+
const { dom } = this
|
31
|
+
if (this.date) {
|
32
|
+
dom.value = this.format(this.date)
|
33
|
+
}
|
34
|
+
if (! dom.hasAttribute('placeholder')) {
|
35
|
+
dom.setAttribute('placeholder', this.datePattern.toUpperCase())
|
36
|
+
}
|
37
|
+
if (isTouchDevice()) {
|
38
|
+
dom.setAttribute('readonly', 'readonly')
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
format(date) {
|
43
|
+
return format(date, this.datePattern, { timezone: this.tz })
|
44
|
+
}
|
45
|
+
|
46
|
+
setDate(date) {
|
47
|
+
this.date = date
|
48
|
+
this.dom.value = date ? this.format(date) : ''
|
49
|
+
}
|
50
|
+
|
51
|
+
setActive(active) {
|
52
|
+
this.active = active
|
53
|
+
const func = active ? 'add' : 'remove'
|
54
|
+
this.dom.classList[func]('active')
|
55
|
+
}
|
56
|
+
|
57
|
+
setDanger(danger) {
|
58
|
+
this.danger = danger
|
59
|
+
const func = danger ? 'add' : 'remove'
|
60
|
+
this.dom.classList[func]('danger')
|
61
|
+
}
|
62
|
+
|
63
|
+
clearStatus() {
|
64
|
+
this.setActive(false)
|
65
|
+
this.setDanger(false)
|
66
|
+
}
|
67
|
+
|
68
|
+
addEvents() {
|
69
|
+
const { dom } = this
|
70
|
+
this.addEvent(dom, 'click', event => this.fire('click', event))
|
71
|
+
this.addEvent(dom, 'focus', event => this.fire('focus', event))
|
72
|
+
this.addEvent(dom, 'keyup', event => this.fire('keyup', event))
|
73
|
+
this.addEvent(dom, 'blur', event => this.fire('blur', event))
|
74
|
+
}
|
75
|
+
}
|
@@ -0,0 +1,262 @@
|
|
1
|
+
import supportDom from '../decorators/supportDom'
|
2
|
+
import getFloatedTargetPos from '../utils/getFloatedTargetPos'
|
3
|
+
import isTouchDevice from '../utils/isTouchDevice'
|
4
|
+
import { DEFAULT_TIMEZONE, DEFAULT_LOCALE } from '../consts'
|
5
|
+
import {
|
6
|
+
chunk,
|
7
|
+
format,
|
8
|
+
range,
|
9
|
+
setYear,
|
10
|
+
setMonth,
|
11
|
+
getYear,
|
12
|
+
getMonth,
|
13
|
+
addYears,
|
14
|
+
toPixel,
|
15
|
+
subYears,
|
16
|
+
noop
|
17
|
+
} from '../utils'
|
18
|
+
|
19
|
+
@supportDom
|
20
|
+
export default class MonthMenu {
|
21
|
+
|
22
|
+
constructor(options = {}) {
|
23
|
+
const { dom, date } = options
|
24
|
+
this.container = dom
|
25
|
+
this.date = date
|
26
|
+
this.menuDate = this.date || new Date()
|
27
|
+
this.options = options
|
28
|
+
this.tz = options.tz || DEFAULT_TIMEZONE
|
29
|
+
this.locale = options.locale || DEFAULT_LOCALE
|
30
|
+
this.change = options.change || noop
|
31
|
+
this.isVisible = false
|
32
|
+
this.loopIndex = 0
|
33
|
+
this.init()
|
34
|
+
}
|
35
|
+
|
36
|
+
init() {
|
37
|
+
this.addMenu()
|
38
|
+
this.addEvents()
|
39
|
+
}
|
40
|
+
|
41
|
+
renderTableContent() {
|
42
|
+
const { date, menuDate, locale } = this
|
43
|
+
|
44
|
+
const currentYear = date ? getYear(date) : null
|
45
|
+
const currentMonth = date ? getMonth(date) : null
|
46
|
+
|
47
|
+
return chunk(range(0, 12), 3)
|
48
|
+
.map(months => {
|
49
|
+
const tds = months.map(month => {
|
50
|
+
const d = setMonth(menuDate, month)
|
51
|
+
const text = format(d, 'MMM', { locale })
|
52
|
+
|
53
|
+
const isCurrentMonth = (currentYear === getYear(d)) && (currentMonth === getMonth(d))
|
54
|
+
|
55
|
+
const classname = isCurrentMonth ? 'cell selected-ex' : 'cell'
|
56
|
+
return `<td class="${classname}" data-month-td="${month}">${text}</td>`
|
57
|
+
}).join('')
|
58
|
+
return `<tr>${tds}</tr>`
|
59
|
+
})
|
60
|
+
.join('')
|
61
|
+
}
|
62
|
+
|
63
|
+
updateTableContent() {
|
64
|
+
this.table.innerHTML = this.renderTableContent()
|
65
|
+
}
|
66
|
+
|
67
|
+
addMenu() {
|
68
|
+
const { container } = this
|
69
|
+
const dom = document.createElement('div')
|
70
|
+
dom.classList.add('month-menu')
|
71
|
+
|
72
|
+
if (container) {
|
73
|
+
dom.classList.add('static')
|
74
|
+
}
|
75
|
+
const title = getYear(this.menuDate)
|
76
|
+
dom.innerHTML = `
|
77
|
+
<div class="month-menu-content">
|
78
|
+
<div class="month-menu-caption">
|
79
|
+
<button class="month-menu-caption-btn"
|
80
|
+
type="button"
|
81
|
+
data-prev-month-btn>
|
82
|
+
<i class="icon-chevron-left"></i>
|
83
|
+
</button>
|
84
|
+
<div data-month-menu-title>${title}</div>
|
85
|
+
<button class="month-menu-caption-btn"
|
86
|
+
type="button"
|
87
|
+
data-next-month-btn>
|
88
|
+
<i class="icon-chevron-right"></i>
|
89
|
+
</button>
|
90
|
+
</div>
|
91
|
+
<table class="month-menu-table"
|
92
|
+
data-month-table>
|
93
|
+
${this.renderTableContent()}
|
94
|
+
</table>
|
95
|
+
</div>
|
96
|
+
`
|
97
|
+
if (container) {
|
98
|
+
container.appendChild(dom)
|
99
|
+
}
|
100
|
+
else {
|
101
|
+
document.body.appendChild(dom)
|
102
|
+
}
|
103
|
+
this.menuTitle = dom.querySelector('[data-month-menu-title]')
|
104
|
+
this.prevBtn = dom.querySelector('[data-prev-month-btn]')
|
105
|
+
this.nextBtn = dom.querySelector('[data-next-month-btn]')
|
106
|
+
this.table = dom.querySelector('[data-month-table]')
|
107
|
+
this.dom = dom
|
108
|
+
}
|
109
|
+
|
110
|
+
setTitle(date) {
|
111
|
+
this.menuTitle.textContent = getYear(date)
|
112
|
+
}
|
113
|
+
|
114
|
+
addYear(year = 1) {
|
115
|
+
this.menuDate = addYears(this.menuDate, year)
|
116
|
+
this.setTitle(this.menuDate)
|
117
|
+
this.updateTableContent()
|
118
|
+
}
|
119
|
+
|
120
|
+
addYearLoop() {
|
121
|
+
const duration = (this.loopIndex === 0) ? 500 : 100
|
122
|
+
this.addYearTimer = setTimeout(() => {
|
123
|
+
this.loopIndex += 1
|
124
|
+
const year = parseInt((this.loopIndex / 5) + 1, 10)
|
125
|
+
this.addYear(year)
|
126
|
+
this.addYearLoop()
|
127
|
+
}, duration)
|
128
|
+
}
|
129
|
+
|
130
|
+
clearAddYearLoop() {
|
131
|
+
clearTimeout(this.addYearTimer)
|
132
|
+
this.loopIndex = 0
|
133
|
+
}
|
134
|
+
|
135
|
+
subYear(year = 1) {
|
136
|
+
this.menuDate = subYears(this.menuDate, year)
|
137
|
+
this.setTitle(this.menuDate)
|
138
|
+
this.updateTableContent()
|
139
|
+
}
|
140
|
+
|
141
|
+
subYearLoop() {
|
142
|
+
const duration = (this.loopIndex === 0) ? 500 : 100
|
143
|
+
this.subYearTimer = setTimeout(() => {
|
144
|
+
this.loopIndex += 1
|
145
|
+
const year = parseInt((this.loopIndex / 5) + 1, 10)
|
146
|
+
const currentYear = getYear(this.menuDate)
|
147
|
+
if ((currentYear - year) > 0) {
|
148
|
+
this.subYear(year)
|
149
|
+
this.subYearLoop()
|
150
|
+
}
|
151
|
+
}, duration)
|
152
|
+
}
|
153
|
+
|
154
|
+
clearSubYearLoop() {
|
155
|
+
clearTimeout(this.subYearTimer)
|
156
|
+
this.loopIndex = 0
|
157
|
+
}
|
158
|
+
|
159
|
+
stop(event) {
|
160
|
+
event.preventDefault()
|
161
|
+
event.stopPropagation()
|
162
|
+
}
|
163
|
+
|
164
|
+
addEvents() {
|
165
|
+
const isTouch = isTouchDevice()
|
166
|
+
const downEvent = isTouch ? 'touchstart' : 'mousedown'
|
167
|
+
|
168
|
+
this.addEvent(this.prevBtn, downEvent, event => {
|
169
|
+
this.stop(event)
|
170
|
+
const currentYear = getYear(this.menuDate)
|
171
|
+
if ((currentYear - 1) <= 0) {
|
172
|
+
return
|
173
|
+
}
|
174
|
+
this.subYear()
|
175
|
+
this.subYearLoop()
|
176
|
+
})
|
177
|
+
|
178
|
+
this.addEvent(this.nextBtn, 'click', event => event.stopPropagation())
|
179
|
+
this.addEvent(this.prevBtn, 'click', event => event.stopPropagation())
|
180
|
+
|
181
|
+
this.addEvent(this.nextBtn, downEvent, event => {
|
182
|
+
this.stop(event)
|
183
|
+
this.addYear()
|
184
|
+
this.addYearLoop()
|
185
|
+
})
|
186
|
+
|
187
|
+
const upEvent = isTouch ? 'touchend' : 'mouseup'
|
188
|
+
this.addEvent(this.prevBtn, upEvent, event => {
|
189
|
+
this.stop(event)
|
190
|
+
this.clearSubYearLoop()
|
191
|
+
})
|
192
|
+
this.addEvent(this.nextBtn, upEvent, event => {
|
193
|
+
this.stop(event)
|
194
|
+
this.clearAddYearLoop()
|
195
|
+
})
|
196
|
+
|
197
|
+
this.addEvent(this.table, 'click', event => {
|
198
|
+
this.stop(event)
|
199
|
+
const { target } = event
|
200
|
+
if ('monthTd' in target.dataset) {
|
201
|
+
const year = getYear(this.menuDate)
|
202
|
+
const month = parseInt(target.dataset.monthTd, 10)
|
203
|
+
|
204
|
+
if (! this.date) {
|
205
|
+
this.date = new Date(this.menuDate.getTime())
|
206
|
+
}
|
207
|
+
|
208
|
+
this.date = setYear(this.date, year)
|
209
|
+
this.date = setMonth(this.date, month)
|
210
|
+
this.updateTableContent()
|
211
|
+
this.emitChange()
|
212
|
+
}
|
213
|
+
})
|
214
|
+
}
|
215
|
+
|
216
|
+
setDate(date) {
|
217
|
+
this.date = date
|
218
|
+
this.menuDate = date
|
219
|
+
this.setTitle(date)
|
220
|
+
this.updateTableContent()
|
221
|
+
}
|
222
|
+
|
223
|
+
emitChange() {
|
224
|
+
this.change(this.date)
|
225
|
+
}
|
226
|
+
|
227
|
+
pos(src) {
|
228
|
+
const { dom } = this
|
229
|
+
const { pos } = getFloatedTargetPos({
|
230
|
+
src,
|
231
|
+
target: dom,
|
232
|
+
place: 'bottom',
|
233
|
+
align: 'left',
|
234
|
+
offset: 4
|
235
|
+
})
|
236
|
+
dom.style.left = toPixel(pos.left)
|
237
|
+
dom.style.top = toPixel(pos.top)
|
238
|
+
}
|
239
|
+
|
240
|
+
show(src) {
|
241
|
+
const { dom } = this
|
242
|
+
dom.style.display = 'block'
|
243
|
+
if (src) {
|
244
|
+
this.pos(src)
|
245
|
+
}
|
246
|
+
dom.style.opacity = 1
|
247
|
+
this.isVisible = true
|
248
|
+
}
|
249
|
+
|
250
|
+
hide() {
|
251
|
+
this.dom.style.display = 'none'
|
252
|
+
this.isVisible = false
|
253
|
+
}
|
254
|
+
|
255
|
+
destroy() {
|
256
|
+
this.menuTitle = null
|
257
|
+
this.prevBtn = null
|
258
|
+
this.nextBtn = null
|
259
|
+
this.table = null
|
260
|
+
this.dom.remove()
|
261
|
+
}
|
262
|
+
}
|
@@ -0,0 +1,90 @@
|
|
1
|
+
import MonthInput from './MonthInput'
|
2
|
+
import MonthMenu from './MonthMenu'
|
3
|
+
import supportDom from '../decorators/supportDom'
|
4
|
+
import { DEFAULT_TIMEZONE } from '../consts'
|
5
|
+
import { noop, parse } from '../utils'
|
6
|
+
|
7
|
+
@supportDom
|
8
|
+
export default class Monthpicker {
|
9
|
+
|
10
|
+
constructor(dom, options = {}) {
|
11
|
+
this.dom = dom
|
12
|
+
this.tz = options.tz || DEFAULT_TIMEZONE
|
13
|
+
this.date = options.date
|
14
|
+
this.menuDate = this.date
|
15
|
+
|
16
|
+
this.options = options
|
17
|
+
this.backdropMode = options.backdropMode || 'auto'
|
18
|
+
this.change = options.change || noop
|
19
|
+
this.init()
|
20
|
+
}
|
21
|
+
|
22
|
+
init() {
|
23
|
+
const { dom } = this
|
24
|
+
this.monthInput = new MonthInput(
|
25
|
+
dom.querySelector('[data-month]'),
|
26
|
+
this.date,
|
27
|
+
this.options
|
28
|
+
)
|
29
|
+
this.monthMenu = new MonthMenu({
|
30
|
+
date: this.menuDate,
|
31
|
+
change: date => {
|
32
|
+
this.monthInput.setDate(date)
|
33
|
+
this.monthInput.clearStatus()
|
34
|
+
this.monthMenu.hide()
|
35
|
+
}
|
36
|
+
})
|
37
|
+
this.addEvents()
|
38
|
+
}
|
39
|
+
|
40
|
+
handleMonthInputFocus() {
|
41
|
+
const { monthInput } = this
|
42
|
+
monthInput.clearStatus()
|
43
|
+
monthInput.setActive(true)
|
44
|
+
this.monthMenu.show(this.dom)
|
45
|
+
}
|
46
|
+
|
47
|
+
handleMonthInputKeyUp(event) {
|
48
|
+
const { monthInput } = this
|
49
|
+
const { value } = event.target
|
50
|
+
const res = parse(value, monthInput.datePattern, this.date)
|
51
|
+
|
52
|
+
if (res.toString() === 'Invalid Date') {
|
53
|
+
monthInput.setDanger(true)
|
54
|
+
this.nextDate = null
|
55
|
+
}
|
56
|
+
else {
|
57
|
+
monthInput.setDanger(false)
|
58
|
+
this.nextDate = res
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
handleMonthInputBlur() {
|
63
|
+
if (this.nextDate) {
|
64
|
+
this.date = this.nextDate
|
65
|
+
this.menuDate = this.date
|
66
|
+
this.monthMenu.setDate(this.menuDate)
|
67
|
+
this.nextDate = null
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
addEvents() {
|
72
|
+
const { monthInput } = this
|
73
|
+
monthInput.on('focus', () => this.handleMonthInputFocus())
|
74
|
+
monthInput.on('click', event => event.stopPropagation())
|
75
|
+
monthInput.on('keyup', event => this.handleMonthInputKeyUp(event))
|
76
|
+
monthInput.on('blur', () => this.handleMonthInputBlur())
|
77
|
+
|
78
|
+
if (this.backdropMode === 'auto') {
|
79
|
+
this.addEvent(document, 'click', () => {
|
80
|
+
this.monthMenu.hide()
|
81
|
+
this.monthInput.clearStatus()
|
82
|
+
})
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
destroy() {
|
87
|
+
this.monthInput.destroy()
|
88
|
+
this.monthMenu.destroy()
|
89
|
+
}
|
90
|
+
}
|
@@ -0,0 +1,256 @@
|
|
1
|
+
import supportDom from '../decorators/supportDom'
|
2
|
+
import chartCommon from '../decorators/chartCommon'
|
3
|
+
import isFn from '../utils/isFn'
|
4
|
+
import isDef from '../utils/isDef'
|
5
|
+
import isUndef from '../utils/isUndef'
|
6
|
+
import { throttle } from '../utils'
|
7
|
+
import { DEFAULT_CHART_STYLES } from '../consts'
|
8
|
+
|
9
|
+
@supportDom
|
10
|
+
@chartCommon
|
11
|
+
export default class PieChart {
|
12
|
+
|
13
|
+
constructor(dom, options = {}) {
|
14
|
+
this.dom = dom
|
15
|
+
this.data = []
|
16
|
+
this.total = 0
|
17
|
+
|
18
|
+
this.options = options
|
19
|
+
this.height = options.height
|
20
|
+
this.width = options.width
|
21
|
+
this.padding = isDef(options.padding) ? options.padding : 30
|
22
|
+
this.styles = options.styles || DEFAULT_CHART_STYLES
|
23
|
+
this.bg = options.bg || '#fff'
|
24
|
+
|
25
|
+
this.init()
|
26
|
+
}
|
27
|
+
|
28
|
+
init() {
|
29
|
+
this.setDpr()
|
30
|
+
this.setDomSizeIfNeeded()
|
31
|
+
this.setCanvas()
|
32
|
+
this.setLabelBox()
|
33
|
+
this.clear()
|
34
|
+
this.bindMedia()
|
35
|
+
this.bindPointMouseOver()
|
36
|
+
}
|
37
|
+
|
38
|
+
get x() {
|
39
|
+
return this.width / 2
|
40
|
+
}
|
41
|
+
|
42
|
+
get y() {
|
43
|
+
return this.height / 2
|
44
|
+
}
|
45
|
+
|
46
|
+
get radius() {
|
47
|
+
return this.contentWidth / 2
|
48
|
+
}
|
49
|
+
|
50
|
+
get pieWidth() {
|
51
|
+
return this.radius * .3
|
52
|
+
}
|
53
|
+
|
54
|
+
get centerCircleRadius() {
|
55
|
+
return this.radius - this.pieWidth
|
56
|
+
}
|
57
|
+
|
58
|
+
get contentWidth() {
|
59
|
+
return this.width - (this.padding * 2)
|
60
|
+
}
|
61
|
+
|
62
|
+
get contentHeight() {
|
63
|
+
return this.height - (this.padding * 2)
|
64
|
+
}
|
65
|
+
|
66
|
+
bindPointMouseOver() {
|
67
|
+
if (isUndef(this.options.onPieMouseOver)) {
|
68
|
+
return
|
69
|
+
}
|
70
|
+
if (! ('onmousemove' in this.canvas)) {
|
71
|
+
return
|
72
|
+
}
|
73
|
+
this.addLayer()
|
74
|
+
const canvas = this.getHighestCanvas()
|
75
|
+
this.addEvent(canvas, 'mousemove', throttle(this.handleMouseMove.bind(this), 30))
|
76
|
+
}
|
77
|
+
|
78
|
+
draw() {
|
79
|
+
this.clear()
|
80
|
+
this.drawPie()
|
81
|
+
}
|
82
|
+
|
83
|
+
drawPie() {
|
84
|
+
const { x, y, radius, centerCircleRadius, ctx, total } = this
|
85
|
+
|
86
|
+
let distance = 0
|
87
|
+
|
88
|
+
this.data.forEach((row, i) => {
|
89
|
+
|
90
|
+
const ratio = (row.value / total)
|
91
|
+
const startAngle = Math.PI * (-.5 + 2 * distance)
|
92
|
+
const endAngle = Math.PI * (-.5 + 2 * (distance + ratio))
|
93
|
+
|
94
|
+
const options = {
|
95
|
+
style: this.styles[i]
|
96
|
+
}
|
97
|
+
this.fillArc(ctx, x, y, radius, startAngle, endAngle, options)
|
98
|
+
distance += ratio
|
99
|
+
})
|
100
|
+
|
101
|
+
this.fillCircle(ctx, x, y, centerCircleRadius, '#fff')
|
102
|
+
}
|
103
|
+
|
104
|
+
handleDprChange() {
|
105
|
+
this.setDpr()
|
106
|
+
this.refresh()
|
107
|
+
}
|
108
|
+
|
109
|
+
getPosAngle(x1, y1, x2, y2) {
|
110
|
+
|
111
|
+
let x = x2
|
112
|
+
let y = y2
|
113
|
+
|
114
|
+
if (x1 >= 0) {
|
115
|
+
x -= x1
|
116
|
+
}
|
117
|
+
if (y1 >= 0) {
|
118
|
+
y -= y1
|
119
|
+
}
|
120
|
+
if (x1 < 0) {
|
121
|
+
x += x1
|
122
|
+
}
|
123
|
+
if (y2 < 0) {
|
124
|
+
y += y2
|
125
|
+
}
|
126
|
+
|
127
|
+
let angle = Math.atan2(y, x) * 180 / Math.PI
|
128
|
+
if (angle < 0) {
|
129
|
+
angle = 180 + (180 + angle)
|
130
|
+
}
|
131
|
+
return (angle + 90) % 360
|
132
|
+
}
|
133
|
+
|
134
|
+
handleMouseMove(event) {
|
135
|
+
|
136
|
+
const { x, y } = this
|
137
|
+
const canvasMousePos = this.getMousePosInCanvas(event)
|
138
|
+
const mousePos = this.getMousePos(canvasMousePos)
|
139
|
+
const mouseX = canvasMousePos.x
|
140
|
+
const mouseY = canvasMousePos.y
|
141
|
+
|
142
|
+
const distanceToCenterPoint = Math.sqrt(Math.pow(mouseX - x, 2) +
|
143
|
+
Math.pow(mouseY - y, 2))
|
144
|
+
|
145
|
+
const inCenterCircle = distanceToCenterPoint <= this.centerCircleRadius
|
146
|
+
|
147
|
+
this.clearSliceGlow()
|
148
|
+
|
149
|
+
if (inCenterCircle) {
|
150
|
+
return this.options.onPieMouseOver(mousePos, null)
|
151
|
+
}
|
152
|
+
|
153
|
+
const inPieCircle = distanceToCenterPoint <= this.radius
|
154
|
+
if (! inPieCircle) {
|
155
|
+
return this.options.onPieMouseOver(mousePos, null)
|
156
|
+
}
|
157
|
+
const angle = this.getPosAngle(x, y, mouseX, mouseY)
|
158
|
+
const matchedRow = this.data.find(row => {
|
159
|
+
return (row.startAngle <= angle) && (angle <= row.endAngle)
|
160
|
+
})
|
161
|
+
if (matchedRow) {
|
162
|
+
this.drawSliceGlow(matchedRow)
|
163
|
+
this.options.onPieMouseOver(mousePos, matchedRow)
|
164
|
+
}
|
165
|
+
}
|
166
|
+
|
167
|
+
drawSliceGlow(row) {
|
168
|
+
const index = this.data.findIndex(r => r === row)
|
169
|
+
this.clearSliceGlow()
|
170
|
+
const { x, y, radius, centerCircleRadius } = this
|
171
|
+
const ctx = this.firstLayer.canvas.getContext('2d')
|
172
|
+
|
173
|
+
const delta = 90 * Math.PI / 180
|
174
|
+
const startAngle = (row.startAngle * Math.PI / 180) - delta
|
175
|
+
const endAngle = (row.endAngle * Math.PI / 180) - delta
|
176
|
+
|
177
|
+
const options = {
|
178
|
+
style: this.styles[index],
|
179
|
+
alpha: .3
|
180
|
+
}
|
181
|
+
const radiusDelta = (radius - centerCircleRadius) * .3
|
182
|
+
this.fillArc(ctx, x, y, radius + radiusDelta, startAngle, endAngle, options)
|
183
|
+
this.fillCircle(this.firstLayer.ctx, x, y, centerCircleRadius, '#fff')
|
184
|
+
}
|
185
|
+
|
186
|
+
clearSliceGlow() {
|
187
|
+
const ctx = this.firstLayer.canvas.getContext('2d')
|
188
|
+
ctx.clearRect(0, 0, this.width, this.height)
|
189
|
+
}
|
190
|
+
|
191
|
+
refresh() {
|
192
|
+
this.raf(() => {
|
193
|
+
this.clearCanvasSize(this.canvas)
|
194
|
+
this.layers.forEach(layer => this.clearCanvasSize(layer.canvas))
|
195
|
+
this.setDomSizeIfNeeded()
|
196
|
+
this.setCanvasSize(this.canvas)
|
197
|
+
this.layers.forEach(layer => this.setCanvasSize(layer.canvas))
|
198
|
+
this.draw()
|
199
|
+
})
|
200
|
+
}
|
201
|
+
|
202
|
+
setAngles(data) {
|
203
|
+
const { total } = this
|
204
|
+
let startAngle = 0
|
205
|
+
return data.map(row => {
|
206
|
+
const endAngle = startAngle + ((row.value / total) * 360)
|
207
|
+
const nextRow = Object.assign({}, row, { startAngle, endAngle })
|
208
|
+
startAngle = endAngle
|
209
|
+
return nextRow
|
210
|
+
})
|
211
|
+
}
|
212
|
+
|
213
|
+
handleLabelMouseOver(event, index) {
|
214
|
+
const row = this.data[index]
|
215
|
+
this.drawSliceGlow(row)
|
216
|
+
|
217
|
+
if (isFn(this.options.onLabelMouseOver)) {
|
218
|
+
const canvasMousePos = this.getMousePosInCanvas(event)
|
219
|
+
const mousePos = this.getMousePos(canvasMousePos)
|
220
|
+
this.options.onLabelMouseOver(mousePos, row)
|
221
|
+
}
|
222
|
+
}
|
223
|
+
|
224
|
+
handleLabelMouseLeave(event, index) {
|
225
|
+
this.clearSliceGlow()
|
226
|
+
|
227
|
+
if (isFn(this.options.onLabelMouseOver)) {
|
228
|
+
const canvasMousePos = this.getMousePosInCanvas(event)
|
229
|
+
const mousePos = this.getMousePos(canvasMousePos)
|
230
|
+
this.options.onLabelMouseOver(mousePos)
|
231
|
+
}
|
232
|
+
}
|
233
|
+
|
234
|
+
setData(arr) {
|
235
|
+
const data = arr || []
|
236
|
+
this.total = data.reduce((t, row) => t + row.value, 0)
|
237
|
+
this.data = this.setAngles(data)
|
238
|
+
this.raf(() => {
|
239
|
+
const labels = this.data.map(row => row.label)
|
240
|
+
this.drawLabels(labels, this.styles)
|
241
|
+
this.draw()
|
242
|
+
})
|
243
|
+
}
|
244
|
+
|
245
|
+
destroy() {
|
246
|
+
const { dom, canvas } = this
|
247
|
+
|
248
|
+
this.unbindMedia()
|
249
|
+
this.removeAllLayers()
|
250
|
+
|
251
|
+
if (dom.contains(canvas)) {
|
252
|
+
dom.removeChild(canvas)
|
253
|
+
dom.style.removeProperty('position')
|
254
|
+
}
|
255
|
+
}
|
256
|
+
}
|
data/src/js/consts/index.js
CHANGED
@@ -3,3 +3,13 @@ import locale from 'date-fns/locale/zh-TW'
|
|
3
3
|
export const DEFAULT_TIMEZONE = 'Asia/Taipei'
|
4
4
|
|
5
5
|
export const DEFAULT_LOCALE = locale
|
6
|
+
|
7
|
+
export const DEFAULT_CHART_STYLES = [
|
8
|
+
'#5469d4',
|
9
|
+
'#7c54d4',
|
10
|
+
'#a254d4',
|
11
|
+
'#c040a2',
|
12
|
+
'#ff5604',
|
13
|
+
'#0be4e3',
|
14
|
+
'#00d924'
|
15
|
+
]
|
@@ -1,6 +1,8 @@
|
|
1
1
|
import raf from '../utils/raf'
|
2
2
|
import isUndef from '../utils/isUndef'
|
3
|
+
import isFn from '../utils/isFn'
|
3
4
|
import { getDomPos, range, toPixel, isFunction } from '../utils'
|
5
|
+
import { DEFAULT_CHART_STYLES } from '../consts'
|
4
6
|
|
5
7
|
export default function chartCommon(target) {
|
6
8
|
|
@@ -12,6 +14,7 @@ export default function chartCommon(target) {
|
|
12
14
|
}
|
13
15
|
|
14
16
|
init() {
|
17
|
+
this.offLabels = []
|
15
18
|
this.layers = []
|
16
19
|
if (isFunction(super.init)) {
|
17
20
|
super.init()
|
@@ -50,10 +53,15 @@ export default function chartCommon(target) {
|
|
50
53
|
|
51
54
|
clear() {
|
52
55
|
const { ctx } = this
|
53
|
-
ctx.fillStyle = this.
|
56
|
+
ctx.fillStyle = this.bg
|
54
57
|
ctx.fillRect(0, 0, this.width, this.height)
|
55
58
|
}
|
56
59
|
|
60
|
+
getHypotenuse(x1, y1, x2, y2) {
|
61
|
+
return Math.sqrt(Math.pow(x2 - x1, 2) +
|
62
|
+
Math.pow(y2 - y1, 2))
|
63
|
+
}
|
64
|
+
|
57
65
|
fillCircle(ctx, x, y, radius, style, alpha) {
|
58
66
|
ctx.save()
|
59
67
|
ctx.beginPath()
|
@@ -65,6 +73,18 @@ export default function chartCommon(target) {
|
|
65
73
|
ctx.restore()
|
66
74
|
}
|
67
75
|
|
76
|
+
fillArc(ctx, x, y, radius, startAngle = 0, endAngle = 2 * Math.PI, options = {}) {
|
77
|
+
ctx.save()
|
78
|
+
ctx.beginPath()
|
79
|
+
ctx.arc(x, y, radius, startAngle, endAngle)
|
80
|
+
ctx.fillStyle = options.style || '#555'
|
81
|
+
ctx.globalAlpha = options.alpha || 1
|
82
|
+
ctx.lineTo(x, y)
|
83
|
+
ctx.fill()
|
84
|
+
ctx.closePath()
|
85
|
+
ctx.restore()
|
86
|
+
}
|
87
|
+
|
68
88
|
getAutoStep(firstValue, lastValue, pointsLength) {
|
69
89
|
return (lastValue - firstValue) / (pointsLength - 1)
|
70
90
|
}
|
@@ -186,6 +206,52 @@ export default function chartCommon(target) {
|
|
186
206
|
this.dom.appendChild(canvas)
|
187
207
|
}
|
188
208
|
|
209
|
+
setLabelBox() {
|
210
|
+
const box = document.createElement('div')
|
211
|
+
box.className = 'chart-box'
|
212
|
+
this.labelBox = box
|
213
|
+
this.dom.appendChild(box)
|
214
|
+
}
|
215
|
+
|
216
|
+
drawLabels(labels, styles = DEFAULT_CHART_STYLES) {
|
217
|
+
if (labels.length <= 0) {
|
218
|
+
return
|
219
|
+
}
|
220
|
+
const { labelBox, handleLabelMouseOver, handleLabelMouseLeave } = this
|
221
|
+
this.dom.style.backgroundColor = this.bg
|
222
|
+
|
223
|
+
this.offLabels.forEach(off => off())
|
224
|
+
labelBox.innerHTML = ''
|
225
|
+
|
226
|
+
this.offLabels.length = 0
|
227
|
+
|
228
|
+
labels.forEach((label, i) => {
|
229
|
+
|
230
|
+
const div = document.createElement('div')
|
231
|
+
div.className = 'chart-box-item'
|
232
|
+
|
233
|
+
const square = document.createElement('div')
|
234
|
+
square.className = 'chart-box-square'
|
235
|
+
square.style.backgroundColor = styles[i]
|
236
|
+
div.appendChild(square)
|
237
|
+
|
238
|
+
const span = document.createElement('span')
|
239
|
+
span.textContent = label
|
240
|
+
div.appendChild(span)
|
241
|
+
|
242
|
+
labelBox.appendChild(div)
|
243
|
+
|
244
|
+
if (isFn(handleLabelMouseOver)) {
|
245
|
+
const off = this.addEvent(div, 'mouseover', event => this.handleLabelMouseOver(event, i))
|
246
|
+
this.offLabels.push(off)
|
247
|
+
}
|
248
|
+
if (isFn(handleLabelMouseLeave)) {
|
249
|
+
const off = this.addEvent(div, 'mouseleave', event => this.handleLabelMouseLeave(event, i))
|
250
|
+
this.offLabels.push(off)
|
251
|
+
}
|
252
|
+
})
|
253
|
+
}
|
254
|
+
|
189
255
|
setCanvasFontSize(canvas, fontSize) {
|
190
256
|
const ctx = canvas.getContext('2d')
|
191
257
|
const args = ctx.font.split(' ')
|
@@ -25,7 +25,12 @@ export default function supportDom(target) {
|
|
25
25
|
|
26
26
|
addEvent(dom, name, func) {
|
27
27
|
dom.addEventListener(name, func)
|
28
|
-
|
28
|
+
const listener = { dom, name, func }
|
29
|
+
this._listeners.push(listener)
|
30
|
+
|
31
|
+
return () => {
|
32
|
+
this._listeners = this._listeners.filter(l => l !== listener)
|
33
|
+
}
|
29
34
|
}
|
30
35
|
|
31
36
|
removeEvents() {
|
data/src/js/index.js
CHANGED
@@ -14,9 +14,12 @@ import DateTimeRanger from './components/DateTimeRanger'
|
|
14
14
|
import Datepicker from './components/Datepicker'
|
15
15
|
import Dropdown from './components/Dropdown'
|
16
16
|
import LineChart from './components/LineChart'
|
17
|
+
import Monthpicker from './components/Monthpicker'
|
18
|
+
import MonthMenu from './components/MonthMenu'
|
17
19
|
import Menu from './components/Menu'
|
18
20
|
import Modal from './components/Modal'
|
19
21
|
import Navbar from './components/Navbar'
|
22
|
+
import PieChart from './components/PieChart'
|
20
23
|
import Radio from './components/Radio'
|
21
24
|
import SearchDropdown from './components/SearchDropdown'
|
22
25
|
import Sidebar from './components/Sidebar'
|
@@ -50,9 +53,12 @@ export {
|
|
50
53
|
Datepicker,
|
51
54
|
Dropdown,
|
52
55
|
LineChart,
|
56
|
+
Monthpicker,
|
57
|
+
MonthMenu,
|
53
58
|
Menu,
|
54
59
|
Modal,
|
55
60
|
Navbar,
|
61
|
+
PieChart,
|
56
62
|
Radio,
|
57
63
|
SearchDropdown,
|
58
64
|
Sidebar,
|
data/src/js/utils/index.js
CHANGED
@@ -9,6 +9,8 @@ import toPixel from '@superlanding/topixel'
|
|
9
9
|
// date-fns
|
10
10
|
import addDays from 'date-fns/addDays'
|
11
11
|
import addMonths from 'date-fns/addMonths'
|
12
|
+
import subYears from 'date-fns/subYears'
|
13
|
+
import addYears from 'date-fns/addYears'
|
12
14
|
import compareAsc from 'date-fns/compareAsc'
|
13
15
|
import endOfDay from 'date-fns/endOfDay'
|
14
16
|
import endOfMonth from 'date-fns/endOfMonth'
|
@@ -18,9 +20,11 @@ import getHours from 'date-fns/getHours'
|
|
18
20
|
import getMinutes from 'date-fns/getMinutes'
|
19
21
|
import getMonth from 'date-fns/getMonth'
|
20
22
|
import getSeconds from 'date-fns/getSeconds'
|
23
|
+
import setYear from 'date-fns/setYear'
|
21
24
|
import getYear from 'date-fns/getYear'
|
22
25
|
import parse from 'date-fns/parse'
|
23
26
|
import set from 'date-fns/set'
|
27
|
+
import setMonth from 'date-fns/setMonth'
|
24
28
|
import startOfDay from 'date-fns/startOfDay'
|
25
29
|
import startOfMonth from 'date-fns/startOfMonth'
|
26
30
|
import subMonths from 'date-fns/subMonths'
|
@@ -28,6 +32,7 @@ import toDate from 'date-fns/toDate'
|
|
28
32
|
import { format } from 'date-fns-tz'
|
29
33
|
|
30
34
|
// lodash
|
35
|
+
import chunk from 'lodash.chunk'
|
31
36
|
import debounce from 'lodash.debounce'
|
32
37
|
import isFunction from 'lodash.isfunction'
|
33
38
|
import noop from 'lodash.noop'
|
@@ -50,6 +55,8 @@ export {
|
|
50
55
|
// date-fns
|
51
56
|
addDays,
|
52
57
|
addMonths,
|
58
|
+
addYears,
|
59
|
+
subYears,
|
53
60
|
compareAsc,
|
54
61
|
endOfDay,
|
55
62
|
endOfMonth,
|
@@ -59,9 +66,11 @@ export {
|
|
59
66
|
getMinutes,
|
60
67
|
getMonth,
|
61
68
|
getSeconds,
|
69
|
+
setYear,
|
62
70
|
getYear,
|
63
71
|
parse,
|
64
72
|
set,
|
73
|
+
setMonth,
|
65
74
|
startOfDay,
|
66
75
|
startOfMonth,
|
67
76
|
subMonths,
|
@@ -69,6 +78,7 @@ export {
|
|
69
78
|
format,
|
70
79
|
|
71
80
|
// lodash
|
81
|
+
chunk,
|
72
82
|
debounce,
|
73
83
|
isFunction,
|
74
84
|
noop,
|
data/src/sass/_beyond.scss
CHANGED
@@ -26,6 +26,7 @@
|
|
26
26
|
@import './components/_checkbox';
|
27
27
|
@import './components/_date-input';
|
28
28
|
@import './components/_date-menu';
|
29
|
+
@import './components/_month-menu';
|
29
30
|
@import './components/_date-time-ranger';
|
30
31
|
@import './components/_datepicker';
|
31
32
|
@import './components/_dropdown';
|
@@ -12,3 +12,23 @@
|
|
12
12
|
z-index: 1;
|
13
13
|
border: 1px solid #e8e8e8;
|
14
14
|
}
|
15
|
+
|
16
|
+
.chart-box {
|
17
|
+
display: flex;
|
18
|
+
flex-wrap: wrap;
|
19
|
+
padding-left: 14px;
|
20
|
+
padding-right: 14px;
|
21
|
+
padding-bottom: 10px;
|
22
|
+
.chart-box-item {
|
23
|
+
cursor: default;
|
24
|
+
font-size: 12px;
|
25
|
+
display: inline-flex;
|
26
|
+
align-items: center;
|
27
|
+
margin-right: 1.4em;
|
28
|
+
.chart-box-square {
|
29
|
+
transform: translateY(1px);
|
30
|
+
@include size(10px);
|
31
|
+
margin-right: .5em;
|
32
|
+
}
|
33
|
+
}
|
34
|
+
}
|
@@ -0,0 +1,70 @@
|
|
1
|
+
.month-menu {
|
2
|
+
display: none;
|
3
|
+
position: absolute;
|
4
|
+
box-shadow: 0 0 0 1px rgba(136, 152, 170, .1),
|
5
|
+
0 15px 35px 0 rgba(49, 49, 93, .1),
|
6
|
+
0 5px 15px 0 rgba(0, 0, 0, .08);
|
7
|
+
background-color: #fff;
|
8
|
+
white-space: nowrap;
|
9
|
+
&.static {
|
10
|
+
display: inline-block;
|
11
|
+
position: static;
|
12
|
+
}
|
13
|
+
.month-menu-content {
|
14
|
+
display: inline-block;
|
15
|
+
position: relative;
|
16
|
+
padding: 0 14px 14px 14px;
|
17
|
+
width: 252px;
|
18
|
+
}
|
19
|
+
.month-menu-caption {
|
20
|
+
display: flex;
|
21
|
+
justify-content: space-between;
|
22
|
+
font-size: 15px;
|
23
|
+
color: #3c4257;
|
24
|
+
text-align: center;
|
25
|
+
height: 50px;
|
26
|
+
line-height: 50px;
|
27
|
+
}
|
28
|
+
.month-menu-caption-btn {
|
29
|
+
border: 0;
|
30
|
+
background-color: transparent;
|
31
|
+
display: block;
|
32
|
+
@include size(50px);
|
33
|
+
|
34
|
+
.icon-chevron-left,
|
35
|
+
.icon-chevron-right {
|
36
|
+
font-size: 12px;
|
37
|
+
}
|
38
|
+
}
|
39
|
+
.month-menu-table {
|
40
|
+
font-size: 14px;
|
41
|
+
width: 100%;
|
42
|
+
margin-top: 2px;
|
43
|
+
th, td {
|
44
|
+
padding: 3px;
|
45
|
+
}
|
46
|
+
td {
|
47
|
+
text-align: center;
|
48
|
+
&.cell {
|
49
|
+
background-color: #f7fafc;
|
50
|
+
cursor: pointer;
|
51
|
+
border-width: 1px;
|
52
|
+
border-style: solid;
|
53
|
+
border-color: #e3e8ee;
|
54
|
+
}
|
55
|
+
&.cell.today {
|
56
|
+
background-color: #fffef4;
|
57
|
+
}
|
58
|
+
&.cell.selected {
|
59
|
+
background-color: #6c8eef;
|
60
|
+
color: #fff;
|
61
|
+
border-color: #6c8eef;
|
62
|
+
}
|
63
|
+
&.cell.selected-ex {
|
64
|
+
background-color: #5469d4;
|
65
|
+
color: #fff;
|
66
|
+
border-color: #5469d4;
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: beyond-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.246
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- kmsheng
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2020-11-
|
12
|
+
date: 2020-11-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sassc
|
@@ -139,7 +139,11 @@ files:
|
|
139
139
|
- src/js/components/LineChart.js
|
140
140
|
- src/js/components/Menu.js
|
141
141
|
- src/js/components/Modal.js
|
142
|
+
- src/js/components/MonthInput.js
|
143
|
+
- src/js/components/MonthMenu.js
|
144
|
+
- src/js/components/Monthpicker.js
|
142
145
|
- src/js/components/Navbar.js
|
146
|
+
- src/js/components/PieChart.js
|
143
147
|
- src/js/components/Radio.js
|
144
148
|
- src/js/components/SearchDropdown.js
|
145
149
|
- src/js/components/Sidebar.js
|
@@ -194,6 +198,7 @@ files:
|
|
194
198
|
- src/js/utils/getKey.js
|
195
199
|
- src/js/utils/index.js
|
196
200
|
- src/js/utils/isDef.js
|
201
|
+
- src/js/utils/isFn.js
|
197
202
|
- src/js/utils/isInt.js
|
198
203
|
- src/js/utils/isStr.js
|
199
204
|
- src/js/utils/isTouchDevice.js
|
@@ -233,6 +238,7 @@ files:
|
|
233
238
|
- src/sass/components/_list.scss
|
234
239
|
- src/sass/components/_mega-menu.scss
|
235
240
|
- src/sass/components/_modal.scss
|
241
|
+
- src/sass/components/_month-menu.scss
|
236
242
|
- src/sass/components/_nav.scss
|
237
243
|
- src/sass/components/_navbar.scss
|
238
244
|
- src/sass/components/_pagination.scss
|