@orbcharts/plugins-basic 3.0.0-alpha.58 → 3.0.0-alpha.59
Sign up to get free protection for your applications and to get access to all the features.
- package/LICENSE +200 -200
- package/package.json +43 -43
- package/src/base/BaseBarStack.ts +778 -778
- package/src/base/BaseBars.ts +764 -764
- package/src/base/BaseBarsTriangle.ts +672 -672
- package/src/base/BaseDots.ts +513 -513
- package/src/base/BaseGroupAxis.ts +558 -558
- package/src/base/BaseLegend.ts +641 -641
- package/src/base/BaseLineAreas.ts +628 -628
- package/src/base/BaseLines.ts +704 -704
- package/src/base/BaseValueAxis.ts +478 -478
- package/src/base/types.ts +2 -2
- package/src/grid/defaults.ts +128 -128
- package/src/grid/gridObservables.ts +541 -541
- package/src/grid/index.ts +15 -15
- package/src/grid/plugins/BarStack.ts +43 -43
- package/src/grid/plugins/Bars.ts +44 -44
- package/src/grid/plugins/BarsPN.ts +41 -41
- package/src/grid/plugins/BarsTriangle.ts +42 -42
- package/src/grid/plugins/Dots.ts +37 -37
- package/src/grid/plugins/GridLegend.ts +59 -59
- package/src/grid/plugins/GroupAux.ts +976 -976
- package/src/grid/plugins/GroupAxis.ts +35 -35
- package/src/grid/plugins/LineAreas.ts +40 -40
- package/src/grid/plugins/Lines.ts +40 -40
- package/src/grid/plugins/ScalingArea.ts +173 -173
- package/src/grid/plugins/ValueAxis.ts +36 -36
- package/src/grid/plugins/ValueStackAxis.ts +38 -38
- package/src/grid/types.ts +123 -123
- package/src/index.ts +9 -9
- package/src/multiGrid/defaults.ts +158 -158
- package/src/multiGrid/index.ts +13 -13
- package/src/multiGrid/multiGridObservables.ts +49 -49
- package/src/multiGrid/plugins/MultiBarStack.ts +78 -78
- package/src/multiGrid/plugins/MultiBars.ts +77 -77
- package/src/multiGrid/plugins/MultiBarsTriangle.ts +77 -77
- package/src/multiGrid/plugins/MultiDots.ts +65 -65
- package/src/multiGrid/plugins/MultiGridLegend.ts +89 -89
- package/src/multiGrid/plugins/MultiGroupAxis.ts +69 -69
- package/src/multiGrid/plugins/MultiLineAreas.ts +77 -77
- package/src/multiGrid/plugins/MultiLines.ts +77 -77
- package/src/multiGrid/plugins/MultiValueAxis.ts +69 -69
- package/src/multiGrid/plugins/MultiValueStackAxis.ts +69 -69
- package/src/multiGrid/plugins/OverlappingValueAxes.ts +167 -167
- package/src/multiGrid/plugins/OverlappingValueStackAxes.ts +168 -168
- package/src/multiGrid/types.ts +72 -72
- package/src/noneData/defaults.ts +102 -102
- package/src/noneData/index.ts +3 -3
- package/src/noneData/plugins/Container.ts +10 -10
- package/src/noneData/plugins/Tooltip.ts +310 -310
- package/src/noneData/types.ts +26 -26
- package/src/series/defaults.ts +144 -144
- package/src/series/index.ts +9 -9
- package/src/series/plugins/Bubbles.ts +545 -545
- package/src/series/plugins/Pie.ts +576 -576
- package/src/series/plugins/PieEventTexts.ts +262 -262
- package/src/series/plugins/PieLabels.ts +304 -304
- package/src/series/plugins/Rose.ts +472 -472
- package/src/series/plugins/RoseLabels.ts +362 -362
- package/src/series/plugins/SeriesLegend.ts +59 -59
- package/src/series/seriesObservables.ts +145 -145
- package/src/series/seriesUtils.ts +51 -51
- package/src/series/types.ts +83 -83
- package/src/tree/defaults.ts +23 -23
- package/src/tree/index.ts +3 -3
- package/src/tree/plugins/TreeLegend.ts +59 -59
- package/src/tree/plugins/TreeMap.ts +305 -305
- package/src/tree/types.ts +23 -23
- package/src/utils/commonUtils.ts +21 -21
- package/src/utils/d3Graphics.ts +124 -124
- package/src/utils/d3Utils.ts +73 -73
- package/src/utils/observables.ts +14 -14
- package/src/utils/orbchartsUtils.ts +100 -100
- package/tsconfig.base.json +13 -13
- package/{tsconfig.json.bak.vite-plugin-tsconfig → tsconfig.json} +7 -7
- package/tsconfig.prod.json +2 -2
- package/vite.config.mjs +40 -40
package/src/utils/commonUtils.ts
CHANGED
@@ -1,22 +1,22 @@
|
|
1
|
-
// 取得文字寬度
|
2
|
-
export function measureTextWidth (text: string, size: number = 10) {
|
3
|
-
const context = document.createElement("canvas").getContext("2d")
|
4
|
-
let width = context?.measureText(text)?.width ?? 0
|
5
|
-
return width * size / 10 // 以10為基準
|
6
|
-
}
|
7
|
-
|
8
|
-
// 取得最小及最大值 - 數字陣列
|
9
|
-
export function getMinAndMax (data: number[]): [number, number] {
|
10
|
-
const defaultMinAndMax: [number, number] = [0, 0] // default
|
11
|
-
if (!data.length) {
|
12
|
-
return defaultMinAndMax
|
13
|
-
}
|
14
|
-
const minAndMax: [number, number] = data.reduce((prev, current) => {
|
15
|
-
// [min, max]
|
16
|
-
return [
|
17
|
-
current < prev[0] ? current : prev[0],
|
18
|
-
current > prev[1] ? current : prev[1]
|
19
|
-
]
|
20
|
-
}, [data[0], data[0]])
|
21
|
-
return minAndMax
|
1
|
+
// 取得文字寬度
|
2
|
+
export function measureTextWidth (text: string, size: number = 10) {
|
3
|
+
const context = document.createElement("canvas").getContext("2d")
|
4
|
+
let width = context?.measureText(text)?.width ?? 0
|
5
|
+
return width * size / 10 // 以10為基準
|
6
|
+
}
|
7
|
+
|
8
|
+
// 取得最小及最大值 - 數字陣列
|
9
|
+
export function getMinAndMax (data: number[]): [number, number] {
|
10
|
+
const defaultMinAndMax: [number, number] = [0, 0] // default
|
11
|
+
if (!data.length) {
|
12
|
+
return defaultMinAndMax
|
13
|
+
}
|
14
|
+
const minAndMax: [number, number] = data.reduce((prev, current) => {
|
15
|
+
// [min, max]
|
16
|
+
return [
|
17
|
+
current < prev[0] ? current : prev[0],
|
18
|
+
current > prev[1] ? current : prev[1]
|
19
|
+
]
|
20
|
+
}, [data[0], data[0]])
|
21
|
+
return minAndMax
|
22
22
|
}
|
package/src/utils/d3Graphics.ts
CHANGED
@@ -1,125 +1,125 @@
|
|
1
|
-
|
2
|
-
type RenderCircleTextParams = {
|
3
|
-
text: string,
|
4
|
-
radius: number,
|
5
|
-
lineHeight: number,
|
6
|
-
isBreakAll: boolean,
|
7
|
-
limit?:number
|
8
|
-
}
|
9
|
-
|
10
|
-
type Line = { width: number; text: string }
|
11
|
-
|
12
|
-
export function renderCircleText (selection: d3.Selection<any, any, any, any>, {
|
13
|
-
text,
|
14
|
-
radius,
|
15
|
-
lineHeight,
|
16
|
-
isBreakAll = false,
|
17
|
-
limit = 0
|
18
|
-
}: RenderCircleTextParams): d3.Selection<SVGTSpanElement, Line, SVGTextElement, any> | undefined {
|
19
|
-
if (selection == null || text == null) {
|
20
|
-
console.error("selection or text is not defined")
|
21
|
-
return
|
22
|
-
}
|
23
|
-
if (radius == null) {
|
24
|
-
const getBox = selection.node().getBBox()
|
25
|
-
radius = getBox.width / 2
|
26
|
-
}
|
27
|
-
|
28
|
-
function getWords (text: string) {
|
29
|
-
let words
|
30
|
-
if (isBreakAll) {
|
31
|
-
words = text.split('')
|
32
|
-
} else {
|
33
|
-
words = text.split(/\s+/g) // To hyphenate: /\s+|(?<=-)/
|
34
|
-
}
|
35
|
-
if (!words[words.length - 1]) words.pop()
|
36
|
-
if (!words[0]) words.shift()
|
37
|
-
return words
|
38
|
-
}
|
39
|
-
|
40
|
-
// 省略文章字數
|
41
|
-
function ellipisText (text:string, limit:number) {
|
42
|
-
if (text && limit) {
|
43
|
-
if (text.length > limit) {
|
44
|
-
text = text.substring(0, limit) + "..."; // 超過字數以"..."取代
|
45
|
-
}
|
46
|
-
}
|
47
|
-
return text;
|
48
|
-
}
|
49
|
-
|
50
|
-
function measureWidth (text: string) {
|
51
|
-
const context = document.createElement("canvas").getContext("2d")
|
52
|
-
// return text => context.measureText(text).width
|
53
|
-
return context?.measureText(text)?.width ?? 0
|
54
|
-
}
|
55
|
-
|
56
|
-
function getTargetWidth (text: string) {
|
57
|
-
const m = measureWidth(text.trim())
|
58
|
-
const result = Math.sqrt(m * lineHeight)
|
59
|
-
return result
|
60
|
-
// return(
|
61
|
-
// Math.sqrt(measureWidth(text.trim()) * lineHeight)
|
62
|
-
// )
|
63
|
-
}
|
64
|
-
|
65
|
-
function getLines (words: string[], targetWidth: number) {
|
66
|
-
let line: Line = { width: 0, text: '' }
|
67
|
-
let lineWidth0 = Infinity
|
68
|
-
const lines: Array<Line> = []
|
69
|
-
let space = " "
|
70
|
-
if (isBreakAll) {
|
71
|
-
space = ""
|
72
|
-
}
|
73
|
-
for (let i = 0, n = words.length; i < n; ++i) {
|
74
|
-
const lineText1 = (line.text ? line.text + space : '') + words[i]
|
75
|
-
const lineWidth1 = measureWidth(lineText1)
|
76
|
-
if ((lineWidth0 + lineWidth1) / 2 < targetWidth) {
|
77
|
-
line.width = lineWidth0 = lineWidth1
|
78
|
-
line.text = lineText1
|
79
|
-
} else {
|
80
|
-
lineWidth0 = measureWidth(words[i])
|
81
|
-
line = {width: lineWidth0, text: words[i]}
|
82
|
-
lines.push(line)
|
83
|
-
}
|
84
|
-
}
|
85
|
-
return lines
|
86
|
-
}
|
87
|
-
|
88
|
-
function getTextRadius (lines: Array<Line>) {
|
89
|
-
let radius = 0
|
90
|
-
for (let i = 0, n = lines.length; i < n; ++i) {
|
91
|
-
const dy: number = (Math.abs(i - n / 2 + 0.5) + 0.5) * lineHeight
|
92
|
-
const dx: number = lines[i].width / 2
|
93
|
-
radius = Math.max(radius, Math.sqrt(dx ** 2 + dy ** 2))
|
94
|
-
}
|
95
|
-
return radius
|
96
|
-
}
|
97
|
-
|
98
|
-
function draw (selection: d3.Selection<any, any, any, any>, text: string) {
|
99
|
-
if(limit > 0) text = ellipisText(text,limit)
|
100
|
-
const words = getWords(text)
|
101
|
-
const targetWidth = getTargetWidth(text)
|
102
|
-
const lines = getLines(words, targetWidth)
|
103
|
-
const textRadius = getTextRadius(lines)
|
104
|
-
|
105
|
-
let t = selection.select<SVGTextElement>("text")
|
106
|
-
if (!t.size()) {
|
107
|
-
t = selection.append("text")
|
108
|
-
}
|
109
|
-
t.attr("transform", `translate(${0},${0}) scale(${radius / textRadius})`)
|
110
|
-
const tspanUpdate = t.selectAll<SVGTSpanElement, Line>("tspan")
|
111
|
-
.data(lines)
|
112
|
-
const tspanEnter = tspanUpdate.enter()
|
113
|
-
.append<SVGTSpanElement>("tspan")
|
114
|
-
.attr("x", 0)
|
115
|
-
.merge(tspanUpdate as d3.Selection<SVGTSpanElement, Line, SVGTextElement, undefined>)
|
116
|
-
.attr("y", (d: Line, i: number) => (i - lines.length / 2 + 0.8) * lineHeight)
|
117
|
-
.text((d: Line) => d.text)
|
118
|
-
tspanUpdate.exit().remove()
|
119
|
-
|
120
|
-
// return selection.node()
|
121
|
-
return tspanUpdate.merge(tspanEnter)
|
122
|
-
}
|
123
|
-
|
124
|
-
return draw(selection, text)
|
1
|
+
|
2
|
+
type RenderCircleTextParams = {
|
3
|
+
text: string,
|
4
|
+
radius: number,
|
5
|
+
lineHeight: number,
|
6
|
+
isBreakAll: boolean,
|
7
|
+
limit?:number
|
8
|
+
}
|
9
|
+
|
10
|
+
type Line = { width: number; text: string }
|
11
|
+
|
12
|
+
export function renderCircleText (selection: d3.Selection<any, any, any, any>, {
|
13
|
+
text,
|
14
|
+
radius,
|
15
|
+
lineHeight,
|
16
|
+
isBreakAll = false,
|
17
|
+
limit = 0
|
18
|
+
}: RenderCircleTextParams): d3.Selection<SVGTSpanElement, Line, SVGTextElement, any> | undefined {
|
19
|
+
if (selection == null || text == null) {
|
20
|
+
console.error("selection or text is not defined")
|
21
|
+
return
|
22
|
+
}
|
23
|
+
if (radius == null) {
|
24
|
+
const getBox = selection.node().getBBox()
|
25
|
+
radius = getBox.width / 2
|
26
|
+
}
|
27
|
+
|
28
|
+
function getWords (text: string) {
|
29
|
+
let words
|
30
|
+
if (isBreakAll) {
|
31
|
+
words = text.split('')
|
32
|
+
} else {
|
33
|
+
words = text.split(/\s+/g) // To hyphenate: /\s+|(?<=-)/
|
34
|
+
}
|
35
|
+
if (!words[words.length - 1]) words.pop()
|
36
|
+
if (!words[0]) words.shift()
|
37
|
+
return words
|
38
|
+
}
|
39
|
+
|
40
|
+
// 省略文章字數
|
41
|
+
function ellipisText (text:string, limit:number) {
|
42
|
+
if (text && limit) {
|
43
|
+
if (text.length > limit) {
|
44
|
+
text = text.substring(0, limit) + "..."; // 超過字數以"..."取代
|
45
|
+
}
|
46
|
+
}
|
47
|
+
return text;
|
48
|
+
}
|
49
|
+
|
50
|
+
function measureWidth (text: string) {
|
51
|
+
const context = document.createElement("canvas").getContext("2d")
|
52
|
+
// return text => context.measureText(text).width
|
53
|
+
return context?.measureText(text)?.width ?? 0
|
54
|
+
}
|
55
|
+
|
56
|
+
function getTargetWidth (text: string) {
|
57
|
+
const m = measureWidth(text.trim())
|
58
|
+
const result = Math.sqrt(m * lineHeight)
|
59
|
+
return result
|
60
|
+
// return(
|
61
|
+
// Math.sqrt(measureWidth(text.trim()) * lineHeight)
|
62
|
+
// )
|
63
|
+
}
|
64
|
+
|
65
|
+
function getLines (words: string[], targetWidth: number) {
|
66
|
+
let line: Line = { width: 0, text: '' }
|
67
|
+
let lineWidth0 = Infinity
|
68
|
+
const lines: Array<Line> = []
|
69
|
+
let space = " "
|
70
|
+
if (isBreakAll) {
|
71
|
+
space = ""
|
72
|
+
}
|
73
|
+
for (let i = 0, n = words.length; i < n; ++i) {
|
74
|
+
const lineText1 = (line.text ? line.text + space : '') + words[i]
|
75
|
+
const lineWidth1 = measureWidth(lineText1)
|
76
|
+
if ((lineWidth0 + lineWidth1) / 2 < targetWidth) {
|
77
|
+
line.width = lineWidth0 = lineWidth1
|
78
|
+
line.text = lineText1
|
79
|
+
} else {
|
80
|
+
lineWidth0 = measureWidth(words[i])
|
81
|
+
line = {width: lineWidth0, text: words[i]}
|
82
|
+
lines.push(line)
|
83
|
+
}
|
84
|
+
}
|
85
|
+
return lines
|
86
|
+
}
|
87
|
+
|
88
|
+
function getTextRadius (lines: Array<Line>) {
|
89
|
+
let radius = 0
|
90
|
+
for (let i = 0, n = lines.length; i < n; ++i) {
|
91
|
+
const dy: number = (Math.abs(i - n / 2 + 0.5) + 0.5) * lineHeight
|
92
|
+
const dx: number = lines[i].width / 2
|
93
|
+
radius = Math.max(radius, Math.sqrt(dx ** 2 + dy ** 2))
|
94
|
+
}
|
95
|
+
return radius
|
96
|
+
}
|
97
|
+
|
98
|
+
function draw (selection: d3.Selection<any, any, any, any>, text: string) {
|
99
|
+
if(limit > 0) text = ellipisText(text,limit)
|
100
|
+
const words = getWords(text)
|
101
|
+
const targetWidth = getTargetWidth(text)
|
102
|
+
const lines = getLines(words, targetWidth)
|
103
|
+
const textRadius = getTextRadius(lines)
|
104
|
+
|
105
|
+
let t = selection.select<SVGTextElement>("text")
|
106
|
+
if (!t.size()) {
|
107
|
+
t = selection.append("text")
|
108
|
+
}
|
109
|
+
t.attr("transform", `translate(${0},${0}) scale(${radius / textRadius})`)
|
110
|
+
const tspanUpdate = t.selectAll<SVGTSpanElement, Line>("tspan")
|
111
|
+
.data(lines)
|
112
|
+
const tspanEnter = tspanUpdate.enter()
|
113
|
+
.append<SVGTSpanElement>("tspan")
|
114
|
+
.attr("x", 0)
|
115
|
+
.merge(tspanUpdate as d3.Selection<SVGTSpanElement, Line, SVGTextElement, undefined>)
|
116
|
+
.attr("y", (d: Line, i: number) => (i - lines.length / 2 + 0.8) * lineHeight)
|
117
|
+
.text((d: Line) => d.text)
|
118
|
+
tspanUpdate.exit().remove()
|
119
|
+
|
120
|
+
// return selection.node()
|
121
|
+
return tspanUpdate.merge(tspanEnter)
|
122
|
+
}
|
123
|
+
|
124
|
+
return draw(selection, text)
|
125
125
|
}
|
package/src/utils/d3Utils.ts
CHANGED
@@ -1,73 +1,73 @@
|
|
1
|
-
import * as d3 from 'd3'
|
2
|
-
|
3
|
-
export function getSvgGElementSize (selection: d3.Selection<SVGGElement, any, any, any>): DOMRect {
|
4
|
-
try {
|
5
|
-
return selection.node()!.getBBox()
|
6
|
-
} catch (e: any) {
|
7
|
-
throw new Error(e)
|
8
|
-
}
|
9
|
-
}
|
10
|
-
|
11
|
-
// 使用字串加入svg
|
12
|
-
export function appendSvg (selection: d3.Selection<any, any, any, any>, svgString: string): void {
|
13
|
-
function parseSvg (svgString: string) {
|
14
|
-
const div = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
|
15
|
-
div.innerHTML= '<svg xmlns="http://www.w3.org/2000/svg">'+ svgString +'</svg>';
|
16
|
-
const frag = document.createDocumentFragment()
|
17
|
-
while (frag && div?.firstChild?.firstChild)
|
18
|
-
frag.appendChild(div.firstChild.firstChild);
|
19
|
-
return frag;
|
20
|
-
}
|
21
|
-
// 刪除現有子節點
|
22
|
-
const node = selection.node()
|
23
|
-
while(node.hasChildNodes())
|
24
|
-
{
|
25
|
-
node.removeChild(node.firstChild);
|
26
|
-
}
|
27
|
-
// 加入dom
|
28
|
-
selection.node().appendChild(parseSvg(svgString))
|
29
|
-
}
|
30
|
-
|
31
|
-
export function getD3TransitionEase (easeName: string) {
|
32
|
-
if (easeName.substring(0, 4) !== 'ease') {
|
33
|
-
return d3.easeCubic
|
34
|
-
}
|
35
|
-
return (d3 as any)[easeName] ?? d3.easeCubic
|
36
|
-
}
|
37
|
-
|
38
|
-
export function makeD3Arc ({ axisWidth, innerRadius, outerRadius, padAngle, cornerRadius }: {
|
39
|
-
axisWidth: number
|
40
|
-
innerRadius: number
|
41
|
-
outerRadius: number
|
42
|
-
padAngle: number
|
43
|
-
cornerRadius: number
|
44
|
-
}): d3.Arc<any, d3.DefaultArcObject> {
|
45
|
-
const arcScale = d3.scaleLinear()
|
46
|
-
.domain([0, 1])
|
47
|
-
.range([0, axisWidth / 2])
|
48
|
-
|
49
|
-
const _outerRadius = arcScale(outerRadius)!
|
50
|
-
|
51
|
-
return d3.arc()
|
52
|
-
.innerRadius(arcScale(innerRadius)!)
|
53
|
-
.outerRadius(_outerRadius)
|
54
|
-
.padAngle(padAngle)
|
55
|
-
.padRadius(_outerRadius)
|
56
|
-
.cornerRadius(cornerRadius)
|
57
|
-
}
|
58
|
-
|
59
|
-
export const parseTickFormatValue = (value: any, tickFormat: string | ((text: d3.NumberValue) => string)) => {
|
60
|
-
if (tickFormat! instanceof Function == true) {
|
61
|
-
return (tickFormat as ((text: d3.NumberValue) => string))(value)
|
62
|
-
}
|
63
|
-
return d3.format(tickFormat as string)!(value)
|
64
|
-
}
|
65
|
-
|
66
|
-
export const parseDateTickFormatValue = (value: any, tickFormat: string | ((text: d3.NumberValue) => string)) => {
|
67
|
-
if (tickFormat! instanceof Function == true) {
|
68
|
-
return (tickFormat as ((text: d3.NumberValue) => string))(value)
|
69
|
-
}
|
70
|
-
return d3.timeFormat(tickFormat as string)!(value)
|
71
|
-
}
|
72
|
-
|
73
|
-
|
1
|
+
import * as d3 from 'd3'
|
2
|
+
|
3
|
+
export function getSvgGElementSize (selection: d3.Selection<SVGGElement, any, any, any>): DOMRect {
|
4
|
+
try {
|
5
|
+
return selection.node()!.getBBox()
|
6
|
+
} catch (e: any) {
|
7
|
+
throw new Error(e)
|
8
|
+
}
|
9
|
+
}
|
10
|
+
|
11
|
+
// 使用字串加入svg
|
12
|
+
export function appendSvg (selection: d3.Selection<any, any, any, any>, svgString: string): void {
|
13
|
+
function parseSvg (svgString: string) {
|
14
|
+
const div = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
|
15
|
+
div.innerHTML= '<svg xmlns="http://www.w3.org/2000/svg">'+ svgString +'</svg>';
|
16
|
+
const frag = document.createDocumentFragment()
|
17
|
+
while (frag && div?.firstChild?.firstChild)
|
18
|
+
frag.appendChild(div.firstChild.firstChild);
|
19
|
+
return frag;
|
20
|
+
}
|
21
|
+
// 刪除現有子節點
|
22
|
+
const node = selection.node()
|
23
|
+
while(node.hasChildNodes())
|
24
|
+
{
|
25
|
+
node.removeChild(node.firstChild);
|
26
|
+
}
|
27
|
+
// 加入dom
|
28
|
+
selection.node().appendChild(parseSvg(svgString))
|
29
|
+
}
|
30
|
+
|
31
|
+
export function getD3TransitionEase (easeName: string) {
|
32
|
+
if (easeName.substring(0, 4) !== 'ease') {
|
33
|
+
return d3.easeCubic
|
34
|
+
}
|
35
|
+
return (d3 as any)[easeName] ?? d3.easeCubic
|
36
|
+
}
|
37
|
+
|
38
|
+
export function makeD3Arc ({ axisWidth, innerRadius, outerRadius, padAngle, cornerRadius }: {
|
39
|
+
axisWidth: number
|
40
|
+
innerRadius: number
|
41
|
+
outerRadius: number
|
42
|
+
padAngle: number
|
43
|
+
cornerRadius: number
|
44
|
+
}): d3.Arc<any, d3.DefaultArcObject> {
|
45
|
+
const arcScale = d3.scaleLinear()
|
46
|
+
.domain([0, 1])
|
47
|
+
.range([0, axisWidth / 2])
|
48
|
+
|
49
|
+
const _outerRadius = arcScale(outerRadius)!
|
50
|
+
|
51
|
+
return d3.arc()
|
52
|
+
.innerRadius(arcScale(innerRadius)!)
|
53
|
+
.outerRadius(_outerRadius)
|
54
|
+
.padAngle(padAngle)
|
55
|
+
.padRadius(_outerRadius)
|
56
|
+
.cornerRadius(cornerRadius)
|
57
|
+
}
|
58
|
+
|
59
|
+
export const parseTickFormatValue = (value: any, tickFormat: string | ((text: d3.NumberValue) => string)) => {
|
60
|
+
if (tickFormat! instanceof Function == true) {
|
61
|
+
return (tickFormat as ((text: d3.NumberValue) => string))(value)
|
62
|
+
}
|
63
|
+
return d3.format(tickFormat as string)!(value)
|
64
|
+
}
|
65
|
+
|
66
|
+
export const parseDateTickFormatValue = (value: any, tickFormat: string | ((text: d3.NumberValue) => string)) => {
|
67
|
+
if (tickFormat! instanceof Function == true) {
|
68
|
+
return (tickFormat as ((text: d3.NumberValue) => string))(value)
|
69
|
+
}
|
70
|
+
return d3.timeFormat(tickFormat as string)!(value)
|
71
|
+
}
|
72
|
+
|
73
|
+
|
package/src/utils/observables.ts
CHANGED
@@ -1,14 +1,14 @@
|
|
1
|
-
import * as d3 from 'd3'
|
2
|
-
import { Observable, merge, distinctUntilChanged, fromEvent } from 'rxjs'
|
3
|
-
|
4
|
-
export function d3EventObservable(selection: d3.Selection<any, any, any, any>, event: any) {
|
5
|
-
// Start with an observable that will never emit
|
6
|
-
let obs = new Observable(() => {});
|
7
|
-
selection.each(function () {
|
8
|
-
// Create observables from each of the elements
|
9
|
-
const events = fromEvent(this as any, event);
|
10
|
-
// Merge the observables into one
|
11
|
-
obs = merge(obs, events);
|
12
|
-
});
|
13
|
-
return obs;
|
14
|
-
}
|
1
|
+
import * as d3 from 'd3'
|
2
|
+
import { Observable, merge, distinctUntilChanged, fromEvent } from 'rxjs'
|
3
|
+
|
4
|
+
export function d3EventObservable(selection: d3.Selection<any, any, any, any>, event: any) {
|
5
|
+
// Start with an observable that will never emit
|
6
|
+
let obs = new Observable(() => {});
|
7
|
+
selection.each(function () {
|
8
|
+
// Create observables from each of the elements
|
9
|
+
const events = fromEvent(this as any, event);
|
10
|
+
// Merge the observables into one
|
11
|
+
obs = merge(obs, events);
|
12
|
+
});
|
13
|
+
return obs;
|
14
|
+
}
|
@@ -1,100 +1,100 @@
|
|
1
|
-
import type {
|
2
|
-
AxisPosition,
|
3
|
-
ColorType,
|
4
|
-
ChartParams,
|
5
|
-
ComputedDatumBase,
|
6
|
-
ComputedDatumSeriesValue,
|
7
|
-
ComputedDatumCategoryValue } from '@orbcharts/core'
|
8
|
-
import { getMinAndMax } from './commonUtils'
|
9
|
-
|
10
|
-
// 取得最小及最大值 - datum格式陣列資料
|
11
|
-
export function getMinAndMaxValue (data: ComputedDatumBase[]): [number, number] {
|
12
|
-
const arr = data
|
13
|
-
.filter(d => d.value != null && d.visible != false)
|
14
|
-
.map(d => d.value as number)
|
15
|
-
return getMinAndMax(arr)
|
16
|
-
}
|
17
|
-
|
18
|
-
// 取得colorType顏色
|
19
|
-
export function getColor (colorType: ColorType, fullChartParams: ChartParams) {
|
20
|
-
const colors = fullChartParams.colors[fullChartParams.colorScheme]
|
21
|
-
// 對應series資料中第1個顏色
|
22
|
-
if (colorType === 'series') {
|
23
|
-
return colors.series[0]
|
24
|
-
}
|
25
|
-
// 對應colorType設定的顏色
|
26
|
-
// return colors[colorType] != null
|
27
|
-
// ? colors[colorType]
|
28
|
-
// : colors.primary
|
29
|
-
return colorType == 'none'
|
30
|
-
? 'none'
|
31
|
-
: colors[colorType] != undefined
|
32
|
-
? colors[colorType]
|
33
|
-
: colors.primary // 如果比對不到
|
34
|
-
}
|
35
|
-
|
36
|
-
export function getSeriesValueColor () {
|
37
|
-
|
38
|
-
}
|
39
|
-
|
40
|
-
export function getCategoryValueColor ({ datum, colorType, fullChartParams }: { datum: ComputedDatumCategoryValue, colorType: ColorType, fullChartParams: ChartParams }) {
|
41
|
-
|
42
|
-
}
|
43
|
-
|
44
|
-
// // 取得Series顏色 @Q@ 待重構完後刪除
|
45
|
-
// export function getSeriesColor (seriesIndex: number, fullChartParams: ChartParams) {
|
46
|
-
// const colorIndex = seriesIndex < fullChartParams.colors[fullChartParams.colorScheme].series.length
|
47
|
-
// ? seriesIndex
|
48
|
-
// : seriesIndex % fullChartParams.colors[fullChartParams.colorScheme].series.length
|
49
|
-
// return fullChartParams.colors[fullChartParams.colorScheme].series[colorIndex]
|
50
|
-
// }
|
51
|
-
|
52
|
-
// 取得Datum顏色 @Q@ 待重構完後刪除
|
53
|
-
export function getDatumColor ({ datum, colorType, fullChartParams }: { datum: ComputedDatumBase, colorType: ColorType, fullChartParams: ChartParams }) {
|
54
|
-
// 對應series資料中的顏色
|
55
|
-
if (colorType === 'series') {
|
56
|
-
if ((datum as unknown as ComputedDatumSeriesValue).color) {
|
57
|
-
return (datum as unknown as ComputedDatumSeriesValue).color
|
58
|
-
} else {
|
59
|
-
// 非series類型的資料則回傳陣列中第1個顏色
|
60
|
-
return fullChartParams.colors[fullChartParams.colorScheme].series[0]
|
61
|
-
}
|
62
|
-
}
|
63
|
-
// 對應colorType設定的顏色
|
64
|
-
return colorType == 'none'
|
65
|
-
? 'none'
|
66
|
-
: fullChartParams.colors[fullChartParams.colorScheme][colorType] != undefined
|
67
|
-
? fullChartParams.colors[fullChartParams.colorScheme][colorType]
|
68
|
-
: fullChartParams.colors[fullChartParams.colorScheme].primary
|
69
|
-
}
|
70
|
-
|
71
|
-
export function getClassName (pluginName: string, elementName: string, modifier?: string) {
|
72
|
-
const modifierText = modifier ? `--${modifier}` : ''
|
73
|
-
return `orbcharts-${pluginName}__${elementName}${modifierText}`
|
74
|
-
}
|
75
|
-
|
76
|
-
export function getUniID (pluginName: string, elementName: string) {
|
77
|
-
const textLength = 5
|
78
|
-
// 英文+數字
|
79
|
-
const randomText: string = Math.random().toString(36).substr(2, textLength)
|
80
|
-
|
81
|
-
return getClassName(pluginName, elementName, randomText)
|
82
|
-
}
|
83
|
-
|
84
|
-
|
85
|
-
export function calcAxesSize ({ xAxisPosition, yAxisPosition, width, height }: {
|
86
|
-
xAxisPosition: AxisPosition
|
87
|
-
yAxisPosition: AxisPosition
|
88
|
-
width: number
|
89
|
-
height: number
|
90
|
-
}) {
|
91
|
-
if ((xAxisPosition === 'bottom' || xAxisPosition === 'top') && (yAxisPosition === 'left' || yAxisPosition === 'right')) {
|
92
|
-
return { width, height }
|
93
|
-
} else if ((xAxisPosition === 'left' || xAxisPosition === 'right') && (yAxisPosition === 'bottom' || yAxisPosition === 'top')) {
|
94
|
-
return {
|
95
|
-
width: height,
|
96
|
-
height: width
|
97
|
-
}
|
98
|
-
}
|
99
|
-
}
|
100
|
-
|
1
|
+
import type {
|
2
|
+
AxisPosition,
|
3
|
+
ColorType,
|
4
|
+
ChartParams,
|
5
|
+
ComputedDatumBase,
|
6
|
+
ComputedDatumSeriesValue,
|
7
|
+
ComputedDatumCategoryValue } from '@orbcharts/core'
|
8
|
+
import { getMinAndMax } from './commonUtils'
|
9
|
+
|
10
|
+
// 取得最小及最大值 - datum格式陣列資料
|
11
|
+
export function getMinAndMaxValue (data: ComputedDatumBase[]): [number, number] {
|
12
|
+
const arr = data
|
13
|
+
.filter(d => d.value != null && d.visible != false)
|
14
|
+
.map(d => d.value as number)
|
15
|
+
return getMinAndMax(arr)
|
16
|
+
}
|
17
|
+
|
18
|
+
// 取得colorType顏色
|
19
|
+
export function getColor (colorType: ColorType, fullChartParams: ChartParams) {
|
20
|
+
const colors = fullChartParams.colors[fullChartParams.colorScheme]
|
21
|
+
// 對應series資料中第1個顏色
|
22
|
+
if (colorType === 'series') {
|
23
|
+
return colors.series[0]
|
24
|
+
}
|
25
|
+
// 對應colorType設定的顏色
|
26
|
+
// return colors[colorType] != null
|
27
|
+
// ? colors[colorType]
|
28
|
+
// : colors.primary
|
29
|
+
return colorType == 'none'
|
30
|
+
? 'none'
|
31
|
+
: colors[colorType] != undefined
|
32
|
+
? colors[colorType]
|
33
|
+
: colors.primary // 如果比對不到
|
34
|
+
}
|
35
|
+
|
36
|
+
export function getSeriesValueColor () {
|
37
|
+
|
38
|
+
}
|
39
|
+
|
40
|
+
export function getCategoryValueColor ({ datum, colorType, fullChartParams }: { datum: ComputedDatumCategoryValue, colorType: ColorType, fullChartParams: ChartParams }) {
|
41
|
+
|
42
|
+
}
|
43
|
+
|
44
|
+
// // 取得Series顏色 @Q@ 待重構完後刪除
|
45
|
+
// export function getSeriesColor (seriesIndex: number, fullChartParams: ChartParams) {
|
46
|
+
// const colorIndex = seriesIndex < fullChartParams.colors[fullChartParams.colorScheme].series.length
|
47
|
+
// ? seriesIndex
|
48
|
+
// : seriesIndex % fullChartParams.colors[fullChartParams.colorScheme].series.length
|
49
|
+
// return fullChartParams.colors[fullChartParams.colorScheme].series[colorIndex]
|
50
|
+
// }
|
51
|
+
|
52
|
+
// 取得Datum顏色 @Q@ 待重構完後刪除
|
53
|
+
export function getDatumColor ({ datum, colorType, fullChartParams }: { datum: ComputedDatumBase, colorType: ColorType, fullChartParams: ChartParams }) {
|
54
|
+
// 對應series資料中的顏色
|
55
|
+
if (colorType === 'series') {
|
56
|
+
if ((datum as unknown as ComputedDatumSeriesValue).color) {
|
57
|
+
return (datum as unknown as ComputedDatumSeriesValue).color
|
58
|
+
} else {
|
59
|
+
// 非series類型的資料則回傳陣列中第1個顏色
|
60
|
+
return fullChartParams.colors[fullChartParams.colorScheme].series[0]
|
61
|
+
}
|
62
|
+
}
|
63
|
+
// 對應colorType設定的顏色
|
64
|
+
return colorType == 'none'
|
65
|
+
? 'none'
|
66
|
+
: fullChartParams.colors[fullChartParams.colorScheme][colorType] != undefined
|
67
|
+
? fullChartParams.colors[fullChartParams.colorScheme][colorType]
|
68
|
+
: fullChartParams.colors[fullChartParams.colorScheme].primary
|
69
|
+
}
|
70
|
+
|
71
|
+
export function getClassName (pluginName: string, elementName: string, modifier?: string) {
|
72
|
+
const modifierText = modifier ? `--${modifier}` : ''
|
73
|
+
return `orbcharts-${pluginName}__${elementName}${modifierText}`
|
74
|
+
}
|
75
|
+
|
76
|
+
export function getUniID (pluginName: string, elementName: string) {
|
77
|
+
const textLength = 5
|
78
|
+
// 英文+數字
|
79
|
+
const randomText: string = Math.random().toString(36).substr(2, textLength)
|
80
|
+
|
81
|
+
return getClassName(pluginName, elementName, randomText)
|
82
|
+
}
|
83
|
+
|
84
|
+
|
85
|
+
export function calcAxesSize ({ xAxisPosition, yAxisPosition, width, height }: {
|
86
|
+
xAxisPosition: AxisPosition
|
87
|
+
yAxisPosition: AxisPosition
|
88
|
+
width: number
|
89
|
+
height: number
|
90
|
+
}) {
|
91
|
+
if ((xAxisPosition === 'bottom' || xAxisPosition === 'top') && (yAxisPosition === 'left' || yAxisPosition === 'right')) {
|
92
|
+
return { width, height }
|
93
|
+
} else if ((xAxisPosition === 'left' || xAxisPosition === 'right') && (yAxisPosition === 'bottom' || yAxisPosition === 'top')) {
|
94
|
+
return {
|
95
|
+
width: height,
|
96
|
+
height: width
|
97
|
+
}
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|