@bashem/rn-charts 0.0.3 → 0.0.5

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.
Files changed (79) hide show
  1. package/README.md +1 -1
  2. package/lib/module/skia/AreaChart/AreaChart.js +60 -51
  3. package/lib/module/skia/AreaChart/AreaChart.js.map +1 -1
  4. package/lib/module/skia/AreaChart/useAreaChart.js +18 -14
  5. package/lib/module/skia/AreaChart/useAreaChart.js.map +1 -1
  6. package/lib/module/skia/BarChart/BarChart.js +156 -69
  7. package/lib/module/skia/BarChart/BarChart.js.map +1 -1
  8. package/lib/module/skia/BarChart/useBarChart.js +53 -41
  9. package/lib/module/skia/BarChart/useBarChart.js.map +1 -1
  10. package/lib/module/skia/Common/HorizontalLabelView.js +121 -0
  11. package/lib/module/skia/Common/HorizontalLabelView.js.map +1 -0
  12. package/lib/module/skia/Common/VerticalLabelView.js +100 -0
  13. package/lib/module/skia/Common/VerticalLabelView.js.map +1 -0
  14. package/lib/module/skia/Common/useComponentLayout.js +13 -0
  15. package/lib/module/skia/Common/useComponentLayout.js.map +1 -0
  16. package/lib/module/skia/HeatMap/DateHeatMap.js +472 -0
  17. package/lib/module/skia/HeatMap/DateHeatMap.js.map +1 -0
  18. package/lib/module/skia/HeatMap/HeatMap.js +121 -33
  19. package/lib/module/skia/HeatMap/HeatMap.js.map +1 -1
  20. package/lib/module/skia/HeatMap/useHeatMap.js +132 -48
  21. package/lib/module/skia/HeatMap/useHeatMap.js.map +1 -1
  22. package/lib/module/skia/PieChart/PieChart.js +21 -17
  23. package/lib/module/skia/PieChart/PieChart.js.map +1 -1
  24. package/lib/module/skia/PieChart/usePieChart.js +241 -30
  25. package/lib/module/skia/PieChart/usePieChart.js.map +1 -1
  26. package/lib/module/skia/Popup.js +7 -5
  27. package/lib/module/skia/Popup.js.map +1 -1
  28. package/lib/module/skia/common.js +4 -41
  29. package/lib/module/skia/common.js.map +1 -1
  30. package/lib/typescript/src/index.d.ts +1 -0
  31. package/lib/typescript/src/index.d.ts.map +1 -1
  32. package/lib/typescript/src/skia/AreaChart/AreaChart.d.ts +15 -3
  33. package/lib/typescript/src/skia/AreaChart/AreaChart.d.ts.map +1 -1
  34. package/lib/typescript/src/skia/AreaChart/useAreaChart.d.ts +13 -14
  35. package/lib/typescript/src/skia/AreaChart/useAreaChart.d.ts.map +1 -1
  36. package/lib/typescript/src/skia/BarChart/BarChart.d.ts +16 -2
  37. package/lib/typescript/src/skia/BarChart/BarChart.d.ts.map +1 -1
  38. package/lib/typescript/src/skia/BarChart/useBarChart.d.ts +17 -5
  39. package/lib/typescript/src/skia/BarChart/useBarChart.d.ts.map +1 -1
  40. package/lib/typescript/src/skia/Common/HorizontalLabelView.d.ts +33 -0
  41. package/lib/typescript/src/skia/Common/HorizontalLabelView.d.ts.map +1 -0
  42. package/lib/typescript/src/skia/Common/VerticalLabelView.d.ts +24 -0
  43. package/lib/typescript/src/skia/Common/VerticalLabelView.d.ts.map +1 -0
  44. package/lib/typescript/src/skia/Common/useComponentLayout.d.ts +4 -0
  45. package/lib/typescript/src/skia/Common/useComponentLayout.d.ts.map +1 -0
  46. package/lib/typescript/src/skia/HeatMap/DateHeatMap.d.ts +1 -0
  47. package/lib/typescript/src/skia/HeatMap/DateHeatMap.d.ts.map +1 -0
  48. package/lib/typescript/src/skia/HeatMap/HeatMap.d.ts +28 -12
  49. package/lib/typescript/src/skia/HeatMap/HeatMap.d.ts.map +1 -1
  50. package/lib/typescript/src/skia/HeatMap/useHeatMap.d.ts +15 -4
  51. package/lib/typescript/src/skia/HeatMap/useHeatMap.d.ts.map +1 -1
  52. package/lib/typescript/src/skia/PieChart/PieChart.d.ts +5 -1
  53. package/lib/typescript/src/skia/PieChart/PieChart.d.ts.map +1 -1
  54. package/lib/typescript/src/skia/PieChart/usePieChart.d.ts +6 -1
  55. package/lib/typescript/src/skia/PieChart/usePieChart.d.ts.map +1 -1
  56. package/lib/typescript/src/skia/Popup.d.ts.map +1 -1
  57. package/lib/typescript/src/skia/common.d.ts +3 -10
  58. package/lib/typescript/src/skia/common.d.ts.map +1 -1
  59. package/package.json +11 -8
  60. package/src/index.tsx +6 -4
  61. package/src/skia/AreaChart/AreaChart.tsx +85 -62
  62. package/src/skia/AreaChart/useAreaChart.ts +25 -26
  63. package/src/skia/BarChart/BarChart.tsx +163 -95
  64. package/src/skia/BarChart/useBarChart.ts +55 -44
  65. package/src/skia/Common/HorizontalLabelView.tsx +153 -0
  66. package/src/skia/Common/VerticalLabelView.tsx +113 -0
  67. package/src/skia/Common/useComponentLayout.ts +14 -0
  68. package/src/skia/HeatMap/DateHeatMap.tsx +470 -0
  69. package/src/skia/HeatMap/HeatMap.tsx +168 -54
  70. package/src/skia/HeatMap/useHeatMap.ts +139 -65
  71. package/src/skia/PieChart/PieChart.tsx +16 -11
  72. package/src/skia/PieChart/usePieChart.ts +316 -66
  73. package/src/skia/Popup.tsx +38 -36
  74. package/src/skia/common.ts +8 -46
  75. package/lib/module/skia/Common/VerticalLabel.js +0 -73
  76. package/lib/module/skia/Common/VerticalLabel.js.map +0 -1
  77. package/lib/typescript/src/skia/Common/VerticalLabel.d.ts +0 -17
  78. package/lib/typescript/src/skia/Common/VerticalLabel.d.ts.map +0 -1
  79. package/src/skia/Common/VerticalLabel.tsx +0 -91
@@ -1,19 +1,29 @@
1
1
  // AreaChart.tsx
2
- import { Canvas, Circle, Group, Path, Text } from '@shopify/react-native-skia';
2
+ import { Canvas, Circle, Group, Path } from '@shopify/react-native-skia';
3
3
  import { type CommonStyle } from '../common';
4
- import VerticalLabel from '../Common/VerticalLabel';
5
4
  import { View } from 'react-native';
6
- import useAreaChart, { type AreaData } from './useAreaChart';
5
+ import useAreaChart from './useAreaChart';
7
6
  import { useState } from 'react';
8
7
  import { lighten } from '../../util/colors';
9
8
  import Popup, { type PopupStyle } from '../Popup';
9
+ import VerticalLabelView, { type VerticalLabelStyle } from "../Common/VerticalLabelView";
10
+ import HorizontalLabelView, { type HorizontalLabelStyle } from "../Common/HorizontalLabelView";
10
11
 
11
- export interface AreaChartStyle extends CommonStyle {
12
+ export interface AreaData {
13
+ values: number[];
14
+ label?: string;
15
+ color?: string;
16
+ }
17
+
18
+ export interface AreaChartStyle extends CommonStyle, VerticalLabelStyle {
12
19
  width: number;
13
20
  height: number;
14
21
  showPoints?: boolean;
15
22
  pointRadius?: number;
16
23
  lightenPointsBy?: number;
24
+ strokeWidth?: number;
25
+ verticalLabelStyle?: VerticalLabelStyle;
26
+ horizontalLabelStyle?: HorizontalLabelStyle;
17
27
  }
18
28
 
19
29
  export interface AreaChartProps {
@@ -21,35 +31,40 @@ export interface AreaChartProps {
21
31
  minValue?: number;
22
32
  maxValue?: number;
23
33
  xLabels?: string[];
34
+ yLabels: number[];
35
+ yLabelView?: (percentage: number, min: number, max: number) => JSX.Element;
36
+ xLabelView?: (label?: string) => JSX.Element;
24
37
  style?: AreaChartStyle;
25
- popupStyle: PopupStyle<{ rowIndex: number; colIndex: number; value: number }>;
38
+ popupStyle: PopupStyle<{ rowIndex: number; colIndex: number; value: number; }>;
26
39
  }
27
40
 
28
- function AreaChart(props: AreaChartProps) {
41
+ function AreaChart({ xLabelView, yLabelView, ...props }: AreaChartProps) {
29
42
  const {
30
43
  minValue,
31
44
  maxValue,
32
45
  canvasHeight,
33
46
  areaCanvasHeight,
34
- labelWidth,
47
+ verticalLabelWidth,
48
+ verticalLabelStrokeWidth,
49
+ yLabels,
50
+ setVerticalLabelWidth,
51
+ setHorizontalLabelHeight,
35
52
  chartWidth,
36
53
  paths,
37
54
  xLabelsData,
38
55
  paddingLeft,
39
56
  paddingTop,
40
57
  paddingHorizontal,
41
- font,
42
58
  touchLine,
43
59
  touchHandler,
44
60
  } = useAreaChart(props);
45
61
  const { style, popupStyle } = props;
46
62
 
47
63
  const [viewOffset, setViewOffset] = useState({ x: 0, y: 0 });
48
- console.log('AreaChart render', { touchLine });
49
64
 
50
65
  return (
51
66
  <View
52
- style={[style, { flexDirection: 'row' }]}
67
+ style={[style, { flexDirection: "column" }]}
53
68
  ref={(view) => {
54
69
  view?.measureInWindow((fx, fy) => {
55
70
  setViewOffset((prev) => {
@@ -61,57 +76,65 @@ function AreaChart(props: AreaChartProps) {
61
76
  });
62
77
  }}
63
78
  >
64
- <VerticalLabel
65
- minValue={minValue}
66
- maxValue={maxValue}
67
- styles={{
68
- height: areaCanvasHeight,
69
- width: labelWidth,
70
- fontSize: style?.fontSize,
71
- }}
72
- labelCount={5}
73
- />
74
-
75
- <Canvas
76
- style={{
77
- width: chartWidth,
78
- height: canvasHeight,
79
- }}
80
- onTouchStart={(event) =>
81
- touchHandler(event.nativeEvent.locationX, event.nativeEvent.locationY)
79
+ <View style={{ flexDirection: "row" }}>
80
+ {yLabelView &&
81
+ <VerticalLabelView
82
+ onLayout={(event) => {
83
+ setVerticalLabelWidth(event.nativeEvent.layout.width);
84
+ }}
85
+ labelPercentages={yLabels}
86
+ styles={{
87
+ height: areaCanvasHeight,
88
+ verticalLabelStyle: props.style?.verticalLabelStyle,
89
+ }}
90
+ >
91
+ {percentage => yLabelView(percentage, minValue, maxValue)}
92
+ </VerticalLabelView>
82
93
  }
83
- >
84
- {paths.map(({ path, points, color }, index) => {
85
- return (
86
- <Group key={index}>
87
- <Path path={path} color={color} />
88
- {style?.showPoints &&
89
- color &&
90
- points.map((points) => (
91
- <Circle
92
- key={`${points.x}-${points.y}`}
93
- cx={points.x}
94
- cy={points.y}
95
- r={style?.pointRadius ?? 3}
96
- color={lighten(color, style?.lightenPointsBy ?? 0.3)}
97
- />
98
- ))}
99
- </Group>
100
- );
101
- })}
102
- {xLabelsData.map(({ label, xPosition }, index) => {
103
- return (
104
- <Text
105
- key={index}
106
- x={xPosition}
107
- y={canvasHeight}
108
- text={label}
109
- font={font}
110
- color={'white'}
111
- />
112
- );
113
- })}
114
- </Canvas>
94
+
95
+ <Canvas
96
+ style={{
97
+ width: chartWidth,
98
+ height: areaCanvasHeight,
99
+ }}
100
+ onTouchStart={(event) =>
101
+ touchHandler(event.nativeEvent.locationX, event.nativeEvent.locationY)
102
+ }
103
+ >
104
+ {paths.map(({ path, points, color }, index) => {
105
+ return (
106
+ <Group key={index}>
107
+ <Path path={path} color={color} />
108
+ {style?.showPoints &&
109
+ color &&
110
+ points.map((points) => (
111
+ <Circle
112
+ key={`${points.x}-${points.y}`}
113
+ cx={points.x}
114
+ cy={points.y}
115
+ r={style?.pointRadius ?? 3}
116
+ color={lighten(color, style?.lightenPointsBy ?? 0.3)}
117
+ />
118
+ ))}
119
+ </Group>
120
+ );
121
+ })}
122
+ </Canvas>
123
+ </View>
124
+ {
125
+ xLabelView &&
126
+ <HorizontalLabelView
127
+ labels={xLabelsData.map(labelData => labelData.label)}
128
+ positions={xLabelsData.map(labelData => labelData.xPosition)}
129
+ style={{
130
+ left: verticalLabelWidth,
131
+ width: chartWidth,
132
+ }}
133
+ onLayout={(event) => setHorizontalLabelHeight(event.nativeEvent.layout.height)}
134
+ >
135
+ {label => xLabelView(label.toString())}
136
+ </HorizontalLabelView>
137
+ }
115
138
  {touchLine && (
116
139
  <Popup
117
140
  popupData={touchLine.y.map((y, index) => ({
@@ -123,11 +146,11 @@ function AreaChart(props: AreaChartProps) {
123
146
  value: touchLine.values[index]!,
124
147
  },
125
148
  }))}
126
- totalWidth={chartWidth + labelWidth + paddingHorizontal}
149
+ totalWidth={chartWidth + verticalLabelWidth + paddingHorizontal}
127
150
  totalHeight={canvasHeight}
128
151
  touchHandler={(x, y) => {
129
152
  console.log('Popup touchHandler', x, y);
130
- touchHandler(x - labelWidth - paddingLeft, y - paddingTop);
153
+ touchHandler(x - verticalLabelWidth - paddingLeft, y - paddingTop);
131
154
  }}
132
155
  viewOffset={viewOffset}
133
156
  popupStyle={popupStyle}
@@ -1,15 +1,9 @@
1
1
  import { Skia, type SkPath } from "@shopify/react-native-skia";
2
2
  import { useMemo, useState } from "react";
3
- import { getCommonStyleFont, getPaddings } from "../common";
4
- import type { AreaChartProps, AreaChartStyle } from "./AreaChart";
3
+ import { getPaddings } from "../common";
4
+ import type { AreaChartProps } from "./AreaChart";
5
5
  import { isDefined } from "../../util/util";
6
6
 
7
- export interface AreaData {
8
- values: number[];
9
- label?: string;
10
- color?: string;
11
- }
12
-
13
7
  interface Point {
14
8
  x: number;
15
9
  y: number;
@@ -23,11 +17,6 @@ export interface PathData {
23
17
  label?: string;
24
18
  }
25
19
 
26
- export interface XLable {
27
- label: string;
28
- xPosition: number;
29
- }
30
-
31
20
  interface TouchLine {
32
21
  col: number;
33
22
  x: number;
@@ -35,12 +24,18 @@ interface TouchLine {
35
24
  values: number[];
36
25
  }
37
26
 
27
+ interface XLabel {
28
+ label: string;
29
+ xPosition: number;
30
+ }
31
+
38
32
  function useAreaChart({
39
33
  data,
40
34
  xLabels,
41
35
  maxValue,
42
36
  minValue,
43
37
  style,
38
+ yLabels,
44
39
  }: AreaChartProps
45
40
  ) {
46
41
 
@@ -54,12 +49,12 @@ function useAreaChart({
54
49
  } = getPaddings(style);
55
50
 
56
51
  const canvasHeight = height - paddingVertical;
57
- const labelWidth = 30;
58
- const chartWidth = width - labelWidth - paddingHorizontal;
59
- const xLabelHeight = xLabels && xLabels.length > 0 ? (style?.fontSize ?? 12) + 5 : 0;
60
- const areaCanvasHeight = canvasHeight - xLabelHeight;
61
-
62
- const { font } = getCommonStyleFont(style);
52
+ const [verticalLabelWidth, setVerticalLabelWidth] = useState(style?.verticalLabelStyle?.width ?? 0);
53
+ const strokeWidth = style?.strokeWidth ?? 2
54
+ const verticalLabelStrokeWidth = style?.verticalLabelStyle?.strokeWidth ?? strokeWidth
55
+ const chartWidth = width - verticalLabelWidth - paddingHorizontal;
56
+ const [horizontalLabelHeight, setHorizontalLabelHeight] = useState(20)
57
+ const areaCanvasHeight = canvasHeight - horizontalLabelHeight;
63
58
 
64
59
  const { maxValueCalculated, minValueCalculated } = useMemo(() => {
65
60
  if (isDefined(maxValue) && isDefined(minValue)) {
@@ -97,7 +92,7 @@ function useAreaChart({
97
92
  const xPos = i * stepX;
98
93
  const yPos = Math.max(0, areaCanvasHeight - ((y - minValueCalculated) / (maxValueCalculated - minValueCalculated)) * areaCanvasHeight);
99
94
 
100
- points.push({ x: xPos, y: yPos });
95
+ points.push({x: xPos, y: yPos });
101
96
  values.push(y);
102
97
  p.lineTo(xPos, yPos);
103
98
  });
@@ -117,7 +112,7 @@ function useAreaChart({
117
112
  return pathData;
118
113
  }, [data, chartWidth, maxValueCalculated, minValueCalculated]);
119
114
 
120
- const xLabelsData: XLable[] = useMemo(() => {
115
+ const xLabelsData: XLabel[] = useMemo(() => {
121
116
  if (!xLabels || xLabels.length === 0) {
122
117
  return [];
123
118
  }
@@ -126,7 +121,7 @@ function useAreaChart({
126
121
  const labels = xLabels.map((label, i) => {
127
122
  return {
128
123
  label,
129
- xPosition: i * stepX + font.getSize(),
124
+ xPosition: i * stepX,
130
125
  };
131
126
  });
132
127
  return labels;
@@ -152,7 +147,7 @@ function useAreaChart({
152
147
 
153
148
  setTouchLine({
154
149
  col: xIndex,
155
- x: xIndex * stepX,
150
+ x: xIndex * stepX + verticalLabelWidth,
156
151
  y: yValues,
157
152
  values
158
153
  });
@@ -166,12 +161,16 @@ function useAreaChart({
166
161
  paddingTop,
167
162
  paddingHorizontal,
168
163
  areaCanvasHeight,
169
- labelWidth,
164
+ strokeWidth,
165
+ verticalLabelStrokeWidth,
166
+ yLabels,
167
+ verticalLabelWidth,
168
+ setVerticalLabelWidth,
170
169
  maxValue: maxValueCalculated,
171
170
  minValue: minValueCalculated,
172
171
  xLabelsData,
173
- xLabelHeight,
174
- font,
172
+ horizontalLabelHeight,
173
+ setHorizontalLabelHeight,
175
174
  touchHandler,
176
175
  touchLine
177
176
  };
@@ -1,16 +1,19 @@
1
- import { Fragment, useState } from 'react';
1
+ import React, { useMemo, useRef, useState } from 'react';
2
2
  import { View } from 'react-native';
3
3
  import {
4
4
  GestureDetector,
5
5
  Gesture,
6
6
  GestureHandlerRootView,
7
+ ScrollView,
7
8
  } from 'react-native-gesture-handler';
9
+ import { Canvas, Rect, vec, type SkHostRect, LinearGradient, Group, rect as SKRect, type Transforms3d } from '@shopify/react-native-skia';
8
10
 
9
- import { Canvas, Rect, Text, vec, Line } from '@shopify/react-native-skia';
10
11
  import { type CommonStyle } from '../common';
11
12
  import useBarChart from './useBarChart';
12
- import VerticalLabel from '../Common/VerticalLabel';
13
13
  import Popup, { type PopupStyle } from '../Popup';
14
+ import VerticalLabelView, { type VerticalLabelStyle } from "../Common/VerticalLabelView";
15
+ import HorizontalLabelView, { type HorizontalLabelStyle } from "../Common/HorizontalLabelView";
16
+ import { useDerivedValue } from "react-native-reanimated";
14
17
 
15
18
  export interface StackValue {
16
19
  value: number;
@@ -30,22 +33,32 @@ export interface BarChartStyle extends CommonStyle {
30
33
  barSpacing?: number;
31
34
  firstBarLeadingSpacing?: number;
32
35
  lastBarTrailingSpacing?: number;
36
+ verticalLabelStyle?: VerticalLabelStyle;
37
+ horizontalLabelStyle?: HorizontalLabelStyle;
33
38
  }
34
39
 
35
40
  export interface BarChartProps {
36
41
  data: BarData[];
37
- colors?: Record<string, string>;
42
+ colors?: Record<string, string | string[]>;
43
+ yLabels: number[];
44
+ yLabelView?: (percentage: number, min: number, max: number) => React.JSX.Element;
45
+ yLabelSkiaView?: (percentage: number, yPosition: number) => React.JSX.Element | undefined;
46
+ xLabelView?: (label?: string) => React.JSX.Element;
47
+ onSelectBarView?: (stackValue: StackValue, xLabel?: string) => React.JSX.Element | undefined;
48
+ barSkiaView?: (rect: SkHostRect, stackValue: StackValue, xLabel?: string) => React.JSX.Element | undefined;
49
+ onSelectBarSkiaView?: (rect: SkHostRect, stackValue: StackValue, xLabel?: string) => React.JSX.Element | undefined;
38
50
  maxValue?: number;
39
51
  minValue?: number;
52
+ overscanRatio?: number;
40
53
  popupStyle?: PopupStyle<StackValue>;
41
54
  style?: BarChartStyle;
42
55
  }
43
56
 
44
- function BarChart(props: BarChartProps) {
57
+ function BarChart({ xLabelView, yLabelView, yLabelSkiaView, barSkiaView, onSelectBarSkiaView, onSelectBarView, ...props }: BarChartProps) {
45
58
  const {
46
59
  maxValueCalculated,
47
60
  minValueCalculated,
48
- canvasHeight,
61
+ yLabels,
49
62
  canvasWidth,
50
63
  paddingRight,
51
64
  paddingLeft,
@@ -53,34 +66,54 @@ function BarChart(props: BarChartProps) {
53
66
  paddingTop,
54
67
  rectangles,
55
68
  verticalLabelWidth,
69
+ setVerticalLabelWidth,
56
70
  chartHeight,
57
- strokeWidth,
58
71
  tooltip,
59
- bottomLabelHeight,
60
- font,
72
+ setBottomLabelHeight,
61
73
  onScroll,
62
74
  touchHandler,
63
75
  totalHeight,
64
76
  totalWidth,
77
+ horizontalStrokeWidth,
78
+ startX,
79
+ offset
65
80
  } = useBarChart(props);
66
81
 
67
- const dragGesture = Gesture.Pan()
68
- .runOnJS(true)
82
+ const panGestureRef = useRef(Gesture.Pan());
83
+
84
+ const panGesture = Gesture.Pan()
69
85
  .onChange((event) => {
70
86
  onScroll(-event.changeX);
87
+ })
88
+ .withRef(panGestureRef);
89
+
90
+ const tapGesture = Gesture.Tap()
91
+ .runOnJS(true)
92
+ .onStart((event) => {
93
+ touchHandler(event.x, event.y);
71
94
  });
72
95
 
73
96
  const [viewOffset, setViewOffset] = useState({ x: 0, y: 0 });
97
+ const canvasGestures = Gesture.Exclusive(panGesture, tapGesture);
98
+ const onSelectBarViewMemo = useMemo(() => {
99
+ if (tooltip === undefined) { return undefined; }
100
+ return onSelectBarView?.(tooltip.data, tooltip.xLabel);
101
+ }, [tooltip]);
102
+ const onSelectBarSkiaViewMemo = useMemo(() => {
103
+ if (tooltip === undefined) { return undefined; }
104
+ return onSelectBarSkiaView?.(tooltip.rect, tooltip.data, tooltip.xLabel);
105
+ }, [tooltip]);
106
+ const canvasGroupTranslate = useDerivedValue<Transforms3d>(() => [{ translateX: -offset.value }], []);
74
107
 
75
108
  return (
76
109
  <GestureHandlerRootView>
77
110
  <View
78
111
  style={{
79
112
  width: totalWidth,
80
- flexDirection: 'row',
113
+ flexDirection: 'column',
81
114
  backgroundColor: props.style?.backgroundColor,
82
- paddingLeft: paddingLeft,
83
- paddingRight: paddingRight,
115
+ paddingStart: paddingLeft,
116
+ paddingEnd: paddingRight,
84
117
  paddingTop: paddingTop,
85
118
  paddingBottom: paddingBottom,
86
119
  }}
@@ -95,95 +128,130 @@ function BarChart(props: BarChartProps) {
95
128
  });
96
129
  }}
97
130
  >
98
- <VerticalLabel
99
- maxValue={maxValueCalculated}
100
- minValue={minValueCalculated}
101
- labelCount={6}
102
- styles={{
103
- width: verticalLabelWidth,
104
- height: chartHeight,
105
- strokeWidth,
106
- }}
107
- />
108
- <GestureDetector gesture={dragGesture}>
109
- <Canvas
131
+ <View style={{ flexDirection: "row", height: chartHeight, padding: 0 }}>
132
+ {
133
+ (yLabelView || yLabelSkiaView) && (<VerticalLabelView
134
+ onLayout={(event) => {
135
+ setVerticalLabelWidth(event.nativeEvent.layout.width);
136
+ }}
137
+ labelPercentages={yLabels}
138
+ styles={{
139
+ height: chartHeight + horizontalStrokeWidth,
140
+ verticalLabelStyle: props.style?.verticalLabelStyle,
141
+ }}
142
+ labelSkiaView={(percentage, yPosition) => yLabelSkiaView?.(percentage, yPosition)}
143
+ >
144
+ {percentage => yLabelView?.(percentage, minValueCalculated, maxValueCalculated)}
145
+ </VerticalLabelView>)
146
+ }
147
+ <ScrollView horizontal={true} simultaneousHandlers={panGestureRef} style={{ padding: 0 }}>
148
+ <GestureDetector gesture={canvasGestures}>
149
+ <Canvas
150
+ style={{
151
+ width: canvasWidth,
152
+ height: chartHeight,
153
+ }}
154
+ >
155
+ <Group transform={canvasGroupTranslate}>
156
+ {rectangles.map((bar, xIndex) => {
157
+ if (bar.bars.length === 0) return null;
158
+ return (
159
+ <Group key={xIndex}>
160
+ {bar.bars.map(({ rect, stackValue }, yIndex) => {
161
+ let skiaView = barSkiaView?.(SKRect(rect.x, rect.y, rect.width, rect.height), stackValue, bar.label);
162
+ if (skiaView !== undefined) { return <Group key={xIndex + "-" + yIndex}>{skiaView}</Group>; }
163
+ let currentData = props.data[xIndex]!.values[yIndex]!;
164
+ let color =
165
+ props?.colors?.[currentData.id ?? currentData.label];
166
+ return (
167
+ <Rect
168
+ key={xIndex + '-' + yIndex}
169
+ x={rect.x}
170
+ y={rect.y}
171
+ width={rect.width}
172
+ height={rect.height}
173
+ color={Array.isArray(color) ? undefined : color}
174
+ >
175
+ {Array.isArray(color) && (
176
+ <LinearGradient
177
+ start={vec(rect.x, rect.y)}
178
+ end={vec(rect.x + rect.width, rect.y + rect.height)}
179
+ colors={color}
180
+ />
181
+ )}
182
+ </Rect>
183
+ );
184
+ })}
185
+ </Group>
186
+ );
187
+ })}
188
+ </Group>
189
+ {onSelectBarSkiaViewMemo}
190
+ </Canvas>
191
+ </GestureDetector>
192
+ </ScrollView>
193
+ </View>
194
+ {
195
+ xLabelView &&
196
+ <HorizontalLabelView
197
+ labels={rectangles.map(bar => bar.label)}
198
+ positions={rectangles.map(bar => bar.x)}
199
+ transform={canvasGroupTranslate}
200
+ xOffset={offset}
110
201
  style={{
202
+ left: verticalLabelWidth,
111
203
  width: canvasWidth,
112
- height: canvasHeight,
113
- paddingRight: 50,
114
- backgroundColor: 'red',
204
+ horizontalLabelStyle: props.style?.horizontalLabelStyle
115
205
  }}
116
- onTouchStart={(event) =>
117
- touchHandler(
118
- event.nativeEvent.locationX,
119
- event.nativeEvent.locationY
120
- )
121
- }
206
+ onLayout={(event) => setBottomLabelHeight(event.nativeEvent.layout.height)}
122
207
  >
123
- {/* X axis */}
124
- <Line
125
- p1={vec(0, chartHeight)}
126
- p2={vec(canvasWidth, chartHeight)}
127
- color="white"
128
- strokeWidth={strokeWidth}
129
- />
130
-
131
- {/* Bars */}
132
-
133
- {rectangles.map((bar, xIndex) => {
134
- if (bar.bars.length === 0) return null;
135
- return (
136
- <Fragment key={xIndex}>
137
- <Text
138
- x={bar.bars[0]!.x}
139
- y={
140
- chartHeight +
141
- font.getSize() +
142
- (bottomLabelHeight - font.getSize()) / 2
143
- }
144
- text={bar.label ?? ''}
145
- color="white"
146
- font={font}
147
- />
148
- {bar.bars.map((item, yIndex) => {
149
- let currentData = props.data[xIndex]!.values[yIndex]!;
150
- let color =
151
- props?.colors?.[currentData.id ?? currentData.label] ||
152
- '#4A90E2';
153
- return (
154
- <Rect
155
- key={xIndex + '-' + yIndex}
156
- x={item.x}
157
- y={item.y}
158
- width={item.width}
159
- height={item.height}
160
- color={color}
161
- />
162
- );
163
- })}
164
- </Fragment>
165
- );
166
- })}
167
- </Canvas>
168
- </GestureDetector>
208
+ {(_index, data) => xLabelView(data)}
209
+ </HorizontalLabelView>
210
+ }
169
211
  {tooltip && (
170
- <Popup
171
- popupData={{
172
- x: tooltip.centerX,
173
- y: tooltip.centerY,
174
- data: tooltip.data,
175
- }}
176
- popupStyle={props.popupStyle}
177
- totalWidth={totalWidth}
178
- totalHeight={totalHeight}
179
- touchHandler={(x, y) =>
180
- touchHandler(x - verticalLabelWidth - paddingLeft, y - paddingTop)
212
+ <>
213
+ {onSelectBarViewMemo &&
214
+ <View
215
+ style={{
216
+ position: "absolute",
217
+ top: tooltip.rect.y + paddingTop,
218
+ left: verticalLabelWidth + paddingLeft + Math.max(0, tooltip.rect.x),
219
+ width: tooltip.rect.width,
220
+ height: tooltip.rect.height,
221
+ overflow: "hidden",
222
+ }}>
223
+ <View
224
+ style={{
225
+ position: "relative",
226
+ top: 0,
227
+ left: -Math.max(0, -tooltip.rect.x),
228
+ width: tooltip.rect.width,
229
+ height: tooltip.rect.height,
230
+ }}
231
+ >
232
+ {onSelectBarViewMemo}
233
+ </View>
234
+ </View>
181
235
  }
182
- viewOffset={viewOffset}
183
- />
236
+ <Popup
237
+ popupData={{
238
+ x: tooltip.centerX,
239
+ y: tooltip.centerY,
240
+ data: tooltip.data,
241
+ }}
242
+ popupStyle={props.popupStyle}
243
+ totalWidth={totalWidth}
244
+ totalHeight={totalHeight}
245
+ touchHandler={(x, y) => {
246
+ touchHandler(x - verticalLabelWidth - paddingLeft, y);
247
+ }}
248
+ onTouchOutside={() => touchHandler(-1, -1)}
249
+ viewOffset={viewOffset}
250
+ />
251
+ </>
184
252
  )}
185
253
  </View>
186
- </GestureHandlerRootView>
254
+ </GestureHandlerRootView >
187
255
  );
188
256
  }
189
257