@orbcharts/plugins-basic 3.0.0-alpha.24
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.
- package/LICENSE +201 -0
- package/package.json +41 -0
- package/src/grid/defaults.ts +95 -0
- package/src/grid/gridObservables.ts +114 -0
- package/src/grid/index.ts +12 -0
- package/src/grid/plugins/BarStack.ts +661 -0
- package/src/grid/plugins/Bars.ts +604 -0
- package/src/grid/plugins/BarsTriangle.ts +594 -0
- package/src/grid/plugins/Dots.ts +427 -0
- package/src/grid/plugins/GroupArea.ts +636 -0
- package/src/grid/plugins/GroupAxis.ts +363 -0
- package/src/grid/plugins/Lines.ts +528 -0
- package/src/grid/plugins/Ranking.ts +0 -0
- package/src/grid/plugins/RankingAxis.ts +0 -0
- package/src/grid/plugins/ScalingArea.ts +168 -0
- package/src/grid/plugins/ValueAxis.ts +356 -0
- package/src/grid/plugins/ValueStackAxis.ts +372 -0
- package/src/grid/types.ts +102 -0
- package/src/index.ts +7 -0
- package/src/multiGrid/index.ts +0 -0
- package/src/multiGrid/plugins/Diverging.ts +0 -0
- package/src/multiGrid/plugins/DivergingAxes.ts +0 -0
- package/src/multiGrid/plugins/TwoScaleAxes.ts +0 -0
- package/src/multiGrid/plugins/TwoScales.ts +0 -0
- package/src/multiValue/index.ts +0 -0
- package/src/multiValue/plugins/Scatter.ts +0 -0
- package/src/multiValue/plugins/ScatterAxes.ts +0 -0
- package/src/noneData/defaults.ts +47 -0
- package/src/noneData/index.ts +4 -0
- package/src/noneData/plugins/Container.ts +11 -0
- package/src/noneData/plugins/Tooltip.ts +305 -0
- package/src/noneData/types.ts +26 -0
- package/src/relationship/index.ts +0 -0
- package/src/relationship/plugins/Relationship.ts +0 -0
- package/src/series/defaults.ts +82 -0
- package/src/series/index.ts +6 -0
- package/src/series/plugins/Bubbles.ts +553 -0
- package/src/series/plugins/Pie.ts +603 -0
- package/src/series/plugins/PieEventTexts.ts +194 -0
- package/src/series/plugins/PieLabels.ts +289 -0
- package/src/series/plugins/Waffle.ts +0 -0
- package/src/series/seriesUtils.ts +51 -0
- package/src/series/types.ts +53 -0
- package/src/tree/index.ts +0 -0
- package/src/tree/plugins/TreeMap.ts +0 -0
- package/src/utils/commonUtils.ts +22 -0
- package/src/utils/d3Graphics.ts +125 -0
- package/src/utils/d3Utils.ts +73 -0
- package/src/utils/observables.ts +14 -0
- package/src/utils/orbchartsUtils.ts +70 -0
- package/tsconfig.json +14 -0
- package/vite.config.js +45 -0
@@ -0,0 +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)
|
125
|
+
}
|
@@ -0,0 +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
|
+
|
@@ -0,0 +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
|
+
}
|
@@ -0,0 +1,70 @@
|
|
1
|
+
import type { AxisPosition, ColorType, ChartParams, ComputedDatumBase, ComputedDatumSeriesValue } from '@orbcharts/core'
|
2
|
+
import { getMinAndMax } from './commonUtils'
|
3
|
+
|
4
|
+
// 取得最小及最大值 - datum格式陣列資料
|
5
|
+
export function getMinAndMaxValue (data: ComputedDatumBase[]): [number, number] {
|
6
|
+
const arr = data
|
7
|
+
.filter(d => d.value != null && d.visible != false)
|
8
|
+
.map(d => d.value as number)
|
9
|
+
return getMinAndMax(arr)
|
10
|
+
}
|
11
|
+
|
12
|
+
|
13
|
+
export function getColor (colorType: ColorType, fullChartParams: ChartParams) {
|
14
|
+
const colors = fullChartParams.colors[fullChartParams.colorScheme]
|
15
|
+
// 對應series資料中第1個顏色
|
16
|
+
if (colorType === 'series') {
|
17
|
+
return colors.series[0]
|
18
|
+
}
|
19
|
+
// 對應colorType設定的顏色
|
20
|
+
return colors[colorType] != null
|
21
|
+
? colors[colorType]
|
22
|
+
: colors.primary
|
23
|
+
}
|
24
|
+
|
25
|
+
export function getDatumColor ({ datum, colorType, fullChartParams }: { datum: ComputedDatumBase, colorType: ColorType, fullChartParams: ChartParams }) {
|
26
|
+
// 對應series資料中的顏色
|
27
|
+
if (colorType === 'series') {
|
28
|
+
if ((datum as unknown as ComputedDatumSeriesValue).color) {
|
29
|
+
return (datum as unknown as ComputedDatumSeriesValue).color
|
30
|
+
} else {
|
31
|
+
// 非series類型的資料則回傳陣列中第1個顏色
|
32
|
+
return fullChartParams.colors[fullChartParams.colorScheme].series[0]
|
33
|
+
}
|
34
|
+
}
|
35
|
+
// 對應colorType設定的顏色
|
36
|
+
return fullChartParams.colors[fullChartParams.colorScheme][colorType] != null
|
37
|
+
? fullChartParams.colors[fullChartParams.colorScheme][colorType]
|
38
|
+
: fullChartParams.colors[fullChartParams.colorScheme].primary
|
39
|
+
}
|
40
|
+
|
41
|
+
export function getClassName (pluginName: string, elementName: string, modifier?: string) {
|
42
|
+
const modifierText = modifier ? `--${modifier}` : ''
|
43
|
+
return `orbcharts-${pluginName}__${elementName}${modifierText}`
|
44
|
+
}
|
45
|
+
|
46
|
+
export function getUniID (pluginName: string, elementName: string) {
|
47
|
+
const textLength = 5
|
48
|
+
// 英文+數字
|
49
|
+
const randomText: string = Math.random().toString(36).substr(2, textLength)
|
50
|
+
|
51
|
+
return getClassName(pluginName, elementName, randomText)
|
52
|
+
}
|
53
|
+
|
54
|
+
|
55
|
+
export function calcAxesSize ({ xAxisPosition, yAxisPosition, width, height }: {
|
56
|
+
xAxisPosition: AxisPosition
|
57
|
+
yAxisPosition: AxisPosition
|
58
|
+
width: number
|
59
|
+
height: number
|
60
|
+
}) {
|
61
|
+
if ((xAxisPosition === 'bottom' || xAxisPosition === 'top') && (yAxisPosition === 'left' || yAxisPosition === 'right')) {
|
62
|
+
return { width, height }
|
63
|
+
} else if ((xAxisPosition === 'left' || xAxisPosition === 'right') && (yAxisPosition === 'bottom' || yAxisPosition === 'top')) {
|
64
|
+
return {
|
65
|
+
width: height,
|
66
|
+
height: width
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
package/tsconfig.json
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
{
|
2
|
+
"compilerOptions": {
|
3
|
+
"outDir": "./dist/",
|
4
|
+
"sourceMap": true,
|
5
|
+
"noImplicitAny": true,
|
6
|
+
"module": "es6",
|
7
|
+
"target": "es5",
|
8
|
+
"jsx": "react",
|
9
|
+
"allowJs": true,
|
10
|
+
"moduleResolution": "node",
|
11
|
+
"allowSyntheticDefaultImports" : true,
|
12
|
+
"esModuleInterop" : true
|
13
|
+
}
|
14
|
+
}
|
package/vite.config.js
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
// import { fileURLToPath, URL } from 'node:url'
|
2
|
+
|
3
|
+
// import { resolve } from 'path'
|
4
|
+
import { defineConfig } from 'vite'
|
5
|
+
import dts from 'vite-plugin-dts'
|
6
|
+
|
7
|
+
const releaseConfig = {
|
8
|
+
plugins: [
|
9
|
+
dts({
|
10
|
+
insertTypesEntry: true
|
11
|
+
})
|
12
|
+
],
|
13
|
+
compilerOptions: {
|
14
|
+
composite: true
|
15
|
+
},
|
16
|
+
build: {
|
17
|
+
lib: {
|
18
|
+
entry: "src/index.ts",
|
19
|
+
name: 'orbcharts-plugins-basic',
|
20
|
+
formats: ["es", "umd"],
|
21
|
+
fileName: format => `orbcharts-plugins-basic.${format}.js`
|
22
|
+
},
|
23
|
+
// rollupOptions: {
|
24
|
+
// input: {
|
25
|
+
// main: resolve(__dirname, "src/index.ts")
|
26
|
+
// },
|
27
|
+
// external: ['vue'],
|
28
|
+
// output: {
|
29
|
+
// assetFileNames: 'my-library.css',
|
30
|
+
// exports: "named",
|
31
|
+
// globals: {
|
32
|
+
// vue: 'Vue',
|
33
|
+
// },
|
34
|
+
// },
|
35
|
+
// },
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
export default defineConfig(({ command, mode }) => {
|
40
|
+
if (mode === 'release') {
|
41
|
+
return releaseConfig
|
42
|
+
} else {
|
43
|
+
return releaseConfig
|
44
|
+
}
|
45
|
+
})
|