beyond-rails 0.0.240 → 0.0.246
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/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
|