-
Notifications
You must be signed in to change notification settings - Fork 37
/
DomainScale.ts
129 lines (117 loc) · 3.28 KB
/
DomainScale.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*!
* Copyright (c) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project.
*/
import {
ScaleCreationContext,
Scales,
ScaleBuilder,
} from '@chart-parts/interfaces'
import get from 'lodash/get'
export type DomainCreator<Domain> = (args: ScaleCreationContext) => Domain
export abstract class DomainScale<Domain> implements ScaleBuilder {
protected bindDomainValue?: string
protected domainValue?: DomainCreator<Domain>
protected nameValue?: string
/**
* Sets the name of the scale
* @param value The name of the scale
*/
public name(value?: string): this {
this.nameValue = value
return this
}
/**
* Sets the domain of the scale
* @param arg The domain argument
*/
public domain(arg?: string | DomainCreator<Domain> | Domain): this {
if (typeof arg === 'function') {
this.domainValue = arg as DomainCreator<Domain>
} else if (Array.isArray(arg)) {
this.domainValue = () => arg as Domain
} else if (arg !== undefined && typeof arg === 'string') {
this.bindDomainValue = arg as string
} else {
this.domainValue = undefined
this.bindDomainValue = undefined
}
return this
}
public build = (arg: ScaleCreationContext) => {
if (!this.nameValue) {
throw new Error('scale name must be defined')
}
return this.createScale(arg)
}
protected abstract createScale(args: ScaleCreationContext): Scales
/**
* Gets the default domain to use
*/
protected get defaultDomain(): Domain {
// the default will be the unit domain
return [0, 1] as any as Domain
}
protected processDomainValues(values: any[]): Domain {
return values as any as Domain
}
protected getDomain(args: ScaleCreationContext): Domain {
if (this.domainValue) {
return this.domainValue(args)
} else if (!this.tableBind && !this.fieldBind) {
// If there's no value and no binding, use the default
return this.defaultDomain
} else {
return this.getDomainFromTableBinding(args)
}
}
private getDomainFromTableBinding(args: ScaleCreationContext): Domain {
const table = this.tableBind
const field = this.fieldBind
if (!table || !field) {
throw new Error(
'Domain scale domain bind must have a table and field accessor name. The expected format is <table>.<field>',
)
}
const data = args.data[table]
if (!data) {
throw new Error(`DomainScale could not find source table ${table}`)
}
const domainValues = data.map((d: any) => get(d, field))
const result = this.processDomainValues(domainValues)
return result
}
protected get bindDomainArray(): string[] {
const bindDomain = this.bindDomainValue
if (!bindDomain) {
throw new Error('Either bindDomain or domain must be set')
}
return typeof bindDomain === 'string'
? [bindDomain]
: (bindDomain as string[])
}
private get tableBind(): string | undefined {
const bind = this.bindDomainValue
if (!bind) {
return undefined
}
const splitIndex = bind.indexOf('.')
if (splitIndex === -1) {
return undefined
}
const tableName = bind.slice(0, splitIndex)
return tableName
}
private get fieldBind() {
const bind = this.bindDomainValue
if (!bind) {
return undefined
}
const splitIndex = bind.indexOf('.')
if (splitIndex === -1) {
return undefined
}
const filedName = bind.slice(splitIndex + 1)
return filedName
}
}