From a34586cedba92dabb7405d02ef289d47a66fd601 Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Wed, 17 Jul 2019 17:27:37 +0800 Subject: [PATCH 01/33] Add a line to display the zero value hint --- packages/graph/src/layers/AxisLayer.tsx | 38 +++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/packages/graph/src/layers/AxisLayer.tsx b/packages/graph/src/layers/AxisLayer.tsx index 112f214..a180df1 100644 --- a/packages/graph/src/layers/AxisLayer.tsx +++ b/packages/graph/src/layers/AxisLayer.tsx @@ -41,6 +41,9 @@ export interface AxisLayerProps { /** Should show the axis on the bottom or not */ showBottomAxis: boolean; + /** Should show the zero line */ + showZeroLine?: boolean; + /** Data of the chart */ data: object[]; @@ -57,6 +60,20 @@ export interface AxisLayerProps { yAxisScale: AxisScale['scale']; } +const getZeroLineProps = ( + xAxisScale: AxisScale['scale'], + yAxisScale: AxisScale['scale'], +) => { + const yPos = yAxisScale(0); + + return { + x1: 0, + y1: yPos, + x2: xAxisScale.range()[1], + y2: yPos, + }; +}; + const getXtickLabelProps = (styles: { tickFontSize: number, strokeColor: string, @@ -91,6 +108,8 @@ export const AxisLayer: React.SFC = ({ showLeftAxis = true, // it should always show the bottom axis by default showBottomAxis = true, + // it should always show the zero line if its domain crosses zero + showZeroLine = true, data, xAxisScale, yAxisScale, @@ -102,8 +121,26 @@ export const AxisLayer: React.SFC = ({ const xAxisLabel = useMemo(() => getAxisLabel(x), [x]); const yAxisLabel = useMemo(() => getAxisLabel(y), [y]); + const zeroLineProps = useMemo( + () => ( + getZeroLineProps(xAxisScale, yAxisScale) + ), + [xAxisScale, yAxisScale] + ); + + const yDomain = yAxisScale.domain(); + const shouldShowZeroline = showZeroLine && yDomain[0] * yDomain[1] < 0; + return ( <> + {/* Zero value line */} + {shouldShowZeroline && ( + + )} + {/* Y Axis */} {showLeftAxis && ( = ({ // )} /> )} + {/* X Axis */} {showBottomAxis && ( Date: Wed, 17 Jul 2019 17:52:35 +0800 Subject: [PATCH 02/33] Refine the doc of BarChart --- docs/charts/BarChart.mdx | 28 ++++++++++++++++++++-------- packages/chart/src/bar/BarChart.tsx | 2 +- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/docs/charts/BarChart.mdx b/docs/charts/BarChart.mdx index c2f66f7..1b5d6d4 100644 --- a/docs/charts/BarChart.mdx +++ b/docs/charts/BarChart.mdx @@ -35,8 +35,20 @@ const lineData = [
+
+ + +### Linear + Linear (transposed) + + +
+
@@ -47,8 +59,8 @@ const lineData = [
@@ -59,8 +71,8 @@ const lineData = [
@@ -75,7 +87,7 @@ You can use the same properties of multi-series line charts to create stacked ba
- {/* Draw the legned */} + {/* Draw the legend */} Date: Wed, 17 Jul 2019 18:29:59 +0800 Subject: [PATCH 03/33] Add a variable to determine the drawing direction --- packages/chart/src/hooks/useCartesianEncodings.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/chart/src/hooks/useCartesianEncodings.ts b/packages/chart/src/hooks/useCartesianEncodings.ts index bde5990..437710d 100644 --- a/packages/chart/src/hooks/useCartesianEncodings.ts +++ b/packages/chart/src/hooks/useCartesianEncodings.ts @@ -103,6 +103,14 @@ export const useCartesianEncodings = ( [color, sortedData], ); + // check if it is necessary to transpose the drawing basis + const drawFromXAxis = useMemo( + () => { + return x.scale !== 'linear'; + }, + [x, y], + ); + // the scales and configs of the axis based on its encodings const xAxis = useMemo( () => { @@ -182,6 +190,12 @@ export const useCartesianEncodings = ( /** Array of data grouped by fields of colors */ dataGroups, + /** + * Whether the graph should be drawn from the x-axis. + * False if it should be drawn from the y-axis. + */ + drawFromXAxis, + /** * The y-values in the `dataGroups` grouped by projected x values. * - Structure of groupedY: "groupedY":[ { "index of dataGroup": "value" }, ... ] From 79f32221b3360298859054636c2c6a918c573f4f Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Thu, 18 Jul 2019 12:19:41 +0800 Subject: [PATCH 04/33] Fix the way determining the scale type of x --- packages/chart/src/hooks/useCartesianEncodings.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/chart/src/hooks/useCartesianEncodings.ts b/packages/chart/src/hooks/useCartesianEncodings.ts index 437710d..a9c0253 100644 --- a/packages/chart/src/hooks/useCartesianEncodings.ts +++ b/packages/chart/src/hooks/useCartesianEncodings.ts @@ -106,7 +106,7 @@ export const useCartesianEncodings = ( // check if it is necessary to transpose the drawing basis const drawFromXAxis = useMemo( () => { - return x.scale !== 'linear'; + return x.type !== 'quantitative'; }, [x, y], ); From a95d2798d845f2e7b19f119ea663bf0b8521e61f Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Thu, 18 Jul 2019 12:43:27 +0800 Subject: [PATCH 05/33] Move accumulated y calculations into a separate file --- packages/chart/src/bar/BarChart.tsx | 22 ++++----------------- packages/chart/src/utils/getBarPositions.ts | 20 +++++++++++++++++++ 2 files changed, 24 insertions(+), 18 deletions(-) create mode 100644 packages/chart/src/utils/getBarPositions.ts diff --git a/packages/chart/src/bar/BarChart.tsx b/packages/chart/src/bar/BarChart.tsx index 962977a..bcee149 100644 --- a/packages/chart/src/bar/BarChart.tsx +++ b/packages/chart/src/bar/BarChart.tsx @@ -16,6 +16,9 @@ import { ThemeContext, } from '@ichef/transcharts-graph'; +import { + getAccumYCalculator, +} from '../utils/getBarPositions'; import { useChartDimensions } from '../hooks/useChartDimensions'; import { useCartesianEncodings } from '../hooks/useCartesianEncodings'; import { SvgWithAxisFrame } from '../frames/SvgWithAxisFrame'; @@ -150,24 +153,7 @@ export const BarChart = ({ const graphGroup = useMemo( () => { const baseY = linearScale(0); - - // calculate the accumulated y position of certain points - const positiveY = {}; - const nonPositiveY = {}; - const getAccumY = (xPos: number, scaledY: number) => { - if (scaledY >= 0) { - if (!positiveY[xPos]) { - positiveY[xPos] = baseY; - } - positiveY[xPos] -= scaledY; - return positiveY[xPos]; - } - - // scaledY < 0 - const yPos = !nonPositiveY[xPos] ? baseY : nonPositiveY[xPos]; - nonPositiveY[xPos] = yPos - scaledY; - return yPos; - }; + const getAccumY = getAccumYCalculator(baseY); return dataGroups.map( (rows: object[], groupIdx: number) => { diff --git a/packages/chart/src/utils/getBarPositions.ts b/packages/chart/src/utils/getBarPositions.ts new file mode 100644 index 0000000..f953818 --- /dev/null +++ b/packages/chart/src/utils/getBarPositions.ts @@ -0,0 +1,20 @@ +export function getAccumYCalculator(baseY: number) { + // calculate the accumulated y position of certain points + const positiveY = {}; + const nonPositiveY = {}; + + return (xPos: number, scaledY: number) => { + if (scaledY >= 0) { + if (!positiveY[xPos]) { + positiveY[xPos] = baseY; + } + positiveY[xPos] -= scaledY; + return positiveY[xPos]; + } + + // scaledY < 0 + const yPos = !nonPositiveY[xPos] ? baseY : nonPositiveY[xPos]; + nonPositiveY[xPos] = yPos - scaledY; + return yPos; + }; +} From 27094b1534a4b779b676939c91c5e1706d2bc965 Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Thu, 18 Jul 2019 16:01:59 +0800 Subject: [PATCH 06/33] Transpose x and y scales --- packages/chart/src/bar/BarChart.tsx | 27 +++++++++++++++---- .../chart/src/hooks/useCartesianEncodings.ts | 14 ---------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/packages/chart/src/bar/BarChart.tsx b/packages/chart/src/bar/BarChart.tsx index bcee149..db53dab 100644 --- a/packages/chart/src/bar/BarChart.tsx +++ b/packages/chart/src/bar/BarChart.tsx @@ -88,10 +88,27 @@ export const BarChart = ({ } = useChartDimensions(margin); const { width: graphWidth, height: graphHeight } = graphDimension; - const xEncoding: AxisEncoding = { ...x, scale: 'band', scaleConfig: { - paddingInner, - }}; + /** + * Whether the graph should be drawn from the x-axis. + * False if it should be drawn from the y-axis. + */ + const drawFromXAxis = useMemo( + () => { + return x.type !== 'quantitative'; + }, + [x, y], + ); + + const xEncoding: AxisEncoding = { ...x, scale: 'band' }; const yEncoding: AxisEncoding = { ...y, scale: 'linear' }; + if (drawFromXAxis) { + xEncoding.scaleConfig = { paddingInner }; + } else { + xEncoding.scale = 'linear'; + yEncoding.scale = 'band'; + yEncoding.scaleConfig = { paddingInner }; + } + const { dataGroups, scalesConfig, @@ -100,8 +117,8 @@ export const BarChart = ({ } = useCartesianEncodings(graphDimension, theme, data, xEncoding, yEncoding, color); const { clearHovering, hovering, hoveredPoint, setHoveredPosAndIndex } = useHoverState(); - const bandScale = scalesConfig.x.scale as ScaleBand; - const linearScale = scalesConfig.y.scale as ScaleLinear; + const bandScale = scalesConfig[drawFromXAxis ? 'x' : 'y'].scale as ScaleBand; + const linearScale = scalesConfig[drawFromXAxis ? 'y' : 'x'].scale as ScaleLinear; const bandWidth = bandScale.bandwidth(); /** diff --git a/packages/chart/src/hooks/useCartesianEncodings.ts b/packages/chart/src/hooks/useCartesianEncodings.ts index a9c0253..bde5990 100644 --- a/packages/chart/src/hooks/useCartesianEncodings.ts +++ b/packages/chart/src/hooks/useCartesianEncodings.ts @@ -103,14 +103,6 @@ export const useCartesianEncodings = ( [color, sortedData], ); - // check if it is necessary to transpose the drawing basis - const drawFromXAxis = useMemo( - () => { - return x.type !== 'quantitative'; - }, - [x, y], - ); - // the scales and configs of the axis based on its encodings const xAxis = useMemo( () => { @@ -190,12 +182,6 @@ export const useCartesianEncodings = ( /** Array of data grouped by fields of colors */ dataGroups, - /** - * Whether the graph should be drawn from the x-axis. - * False if it should be drawn from the y-axis. - */ - drawFromXAxis, - /** * The y-values in the `dataGroups` grouped by projected x values. * - Structure of groupedY: "groupedY":[ { "index of dataGroup": "value" }, ... ] From 09accaae3b48758d50ec17979458224c5f06a77e Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Thu, 18 Jul 2019 17:44:47 +0800 Subject: [PATCH 07/33] Draw the transposed bars --- docs/charts/BarChart.mdx | 34 +++++++++++++++++ packages/chart/src/bar/BarChart.tsx | 41 +++++++++++++++------ packages/chart/src/utils/getBarChartPos.ts | 41 +++++++++++++++++++++ packages/chart/src/utils/getBarPositions.ts | 20 ---------- 4 files changed, 105 insertions(+), 31 deletions(-) create mode 100644 packages/chart/src/utils/getBarChartPos.ts delete mode 100644 packages/chart/src/utils/getBarPositions.ts diff --git a/docs/charts/BarChart.mdx b/docs/charts/BarChart.mdx index 1b5d6d4..fbb52f1 100644 --- a/docs/charts/BarChart.mdx +++ b/docs/charts/BarChart.mdx @@ -130,6 +130,40 @@ You can use the same properties of multi-series line charts to create stacked ba
+ +### Quantitative color field (transposed) + + +
+ +
+
+ ## Props diff --git a/packages/chart/src/bar/BarChart.tsx b/packages/chart/src/bar/BarChart.tsx index db53dab..977de76 100644 --- a/packages/chart/src/bar/BarChart.tsx +++ b/packages/chart/src/bar/BarChart.tsx @@ -17,8 +17,9 @@ import { } from '@ichef/transcharts-graph'; import { + getAccumXCalculator, getAccumYCalculator, -} from '../utils/getBarPositions'; +} from '../utils/getBarChartPos'; import { useChartDimensions } from '../hooks/useChartDimensions'; import { useCartesianEncodings } from '../hooks/useCartesianEncodings'; import { SvgWithAxisFrame } from '../frames/SvgWithAxisFrame'; @@ -169,26 +170,44 @@ export const BarChart = ({ const graphGroup = useMemo( () => { - const baseY = linearScale(0); - const getAccumY = getAccumYCalculator(baseY); + const baseVal = linearScale(0); + const accumCalculator = drawFromXAxis ? getAccumYCalculator : getAccumXCalculator; + const getAccumVal = accumCalculator(baseVal); return dataGroups.map( (rows: object[], groupIdx: number) => { return rows.map((row: object, rowIdx: number) => { const colorString: string = rowValSelectors.color.getString(rows[0]); - const xPos = rowValSelectors.x.getScaledVal(row); + const scaledX = rowValSelectors.x.getScaledVal(row); const scaledY = rowValSelectors.y.getScaledVal(row); - const height = scaledY >= 0 - ? baseY - scaledY - : baseY - graphHeight - scaledY; + + console.log(row, scaledX) + + let barPos; + if (drawFromXAxis) { + const height = scaledY >= 0 + ? baseVal - scaledY + : baseVal - graphHeight - scaledY; + + barPos = { + x: scaledX, + y: getAccumVal(scaledX, height), + width: bandWidth, + height: Math.abs(height), + }; + } else { + barPos = { + x: getAccumVal(scaledY, baseVal), + y: scaledY, + width: scaledX, + height: bandWidth, + }; + } return ( ); diff --git a/packages/chart/src/utils/getBarChartPos.ts b/packages/chart/src/utils/getBarChartPos.ts new file mode 100644 index 0000000..8485f99 --- /dev/null +++ b/packages/chart/src/utils/getBarChartPos.ts @@ -0,0 +1,41 @@ +export function getAccumXCalculator(baseX: number) { + // calculate the accumulated x position of certain points + const positiveX = {}; + const nonPositiveX = {}; + + return (yPos: number, scaledX: number) => { + if (scaledX < 0) { + if (!nonPositiveX[yPos]) { + nonPositiveX[yPos] = baseX; + } + nonPositiveX[yPos] -= scaledX; + return nonPositiveX[yPos]; + } + + // scaledX >= 0 + const xPos = !positiveX[yPos] ? baseX : positiveX[yPos]; + positiveX[yPos] = xPos + scaledX; + return xPos; + }; +} + +export function getAccumYCalculator(baseY: number) { + // calculate the accumulated y position of certain points + const positiveY = {}; + const nonPositiveY = {}; + + return (xPos: number, scaledY: number) => { + if (scaledY >= 0) { + if (!positiveY[xPos]) { + positiveY[xPos] = baseY; + } + positiveY[xPos] -= scaledY; + return positiveY[xPos]; + } + + // scaledY < 0 + const yPos = !nonPositiveY[xPos] ? baseY : nonPositiveY[xPos]; + nonPositiveY[xPos] = yPos - scaledY; + return yPos; + }; +} diff --git a/packages/chart/src/utils/getBarPositions.ts b/packages/chart/src/utils/getBarPositions.ts deleted file mode 100644 index f953818..0000000 --- a/packages/chart/src/utils/getBarPositions.ts +++ /dev/null @@ -1,20 +0,0 @@ -export function getAccumYCalculator(baseY: number) { - // calculate the accumulated y position of certain points - const positiveY = {}; - const nonPositiveY = {}; - - return (xPos: number, scaledY: number) => { - if (scaledY >= 0) { - if (!positiveY[xPos]) { - positiveY[xPos] = baseY; - } - positiveY[xPos] -= scaledY; - return positiveY[xPos]; - } - - // scaledY < 0 - const yPos = !nonPositiveY[xPos] ? baseY : nonPositiveY[xPos]; - nonPositiveY[xPos] = yPos - scaledY; - return yPos; - }; -} From 78e2df312eba2e96a6ed21175c5ee889988d07bf Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Fri, 19 Jul 2019 11:34:42 +0800 Subject: [PATCH 08/33] Avoid running tslint for comments --- tslint.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tslint.json b/tslint.json index 1cf3ad0..8ea6078 100644 --- a/tslint.json +++ b/tslint.json @@ -61,7 +61,8 @@ { "code": 100, "tabWidth": 2, - "ignoreUrls": true + "ignoreUrls": true, + "comments": false, } ], // ============= from tslint-react ============= From 4252ae827260cb7dbf146a37531135cc7dcd572a Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Fri, 19 Jul 2019 12:01:47 +0800 Subject: [PATCH 09/33] Rename variables related to the tooltip display --- packages/chart/src/bar/BarChart.tsx | 10 +-- packages/chart/src/line/LineChart.tsx | 18 ++--- .../chart/src/utils/getAxisProjectedValues.ts | 66 ++++++++++--------- packages/graph/src/layers/TooltipLayer.tsx | 28 ++++---- 4 files changed, 62 insertions(+), 60 deletions(-) diff --git a/packages/chart/src/bar/BarChart.tsx b/packages/chart/src/bar/BarChart.tsx index 977de76..62a3f52 100644 --- a/packages/chart/src/bar/BarChart.tsx +++ b/packages/chart/src/bar/BarChart.tsx @@ -100,6 +100,7 @@ export const BarChart = ({ [x, y], ); + // assign the scale according to the data type const xEncoding: AxisEncoding = { ...x, scale: 'band' }; const yEncoding: AxisEncoding = { ...y, scale: 'linear' }; if (drawFromXAxis) { @@ -129,9 +130,10 @@ export const BarChart = ({ const getHoveringRectPos = useCallback( (idx: number) => { const paddingVal = bandWidth * paddingInner; + const xPos = idx === 0 ? 0 - : axisProjectedValues[idx].xPos - paddingVal / 2; + : axisProjectedValues[idx].basePos - paddingVal / 2; const width = idx === 0 || idx === data.length - 1 ? bandWidth + paddingVal / 2 : bandWidth + paddingVal; @@ -154,10 +156,6 @@ export const BarChart = ({ @@ -181,8 +179,6 @@ export const BarChart = ({ const scaledX = rowValSelectors.x.getScaledVal(row); const scaledY = rowValSelectors.y.getScaledVal(row); - console.log(row, scaledX) - let barPos; if (drawFromXAxis) { const height = scaledY >= 0 diff --git a/packages/chart/src/line/LineChart.tsx b/packages/chart/src/line/LineChart.tsx index 028e2e1..6ecae6a 100644 --- a/packages/chart/src/line/LineChart.tsx +++ b/packages/chart/src/line/LineChart.tsx @@ -32,7 +32,7 @@ function getXPosByIndex(arr: AxisProjectedValue[], idx: number) { if (idx >= arr.length) { arrIdx = arr.length - 1; } - return arr[arrIdx].xPos; + return arr[arrIdx].basePos; } export type LineChartProps = CommonChartProps; @@ -47,11 +47,11 @@ const HoveringIndicator = ({ hovering, projectedPoints, height }: { return null; } - const circles = projectedPoints.groupedY.map(pointY => ( + const circles = projectedPoints.projectedVals.map(pointY => ( @@ -60,9 +60,9 @@ const HoveringIndicator = ({ hovering, projectedPoints, height }: { return( <> @@ -163,10 +163,10 @@ export const LineChart = ({ () => ( axisProjectedValues.map( (row, idx) => { - const rectX = (row.xPos + getXPosByIndex(axisProjectedValues, idx - 1)) / 2; + const rectX = (row.basePos + getXPosByIndex(axisProjectedValues, idx - 1)) / 2; const rectWidth = ( - (row.xPos + getXPosByIndex(axisProjectedValues, idx + 1)) / 2 + (row.basePos + getXPosByIndex(axisProjectedValues, idx + 1)) / 2 ) - rectX; return ( diff --git a/packages/chart/src/utils/getAxisProjectedValues.ts b/packages/chart/src/utils/getAxisProjectedValues.ts index 4a83ee7..9727d14 100644 --- a/packages/chart/src/utils/getAxisProjectedValues.ts +++ b/packages/chart/src/utils/getAxisProjectedValues.ts @@ -4,50 +4,56 @@ import { } from '@ichef/transcharts-graph'; /** - * Return the y-values in the `dataGroups` grouped by projected x values. - * - Structure of groupedY: "groupedY":[ { "index of dataGroup": "value" }, ... ] + * Return the y-values in the `dataGroups` grouped by projected base values. + * - Structure of projectedVals: "projectedVals":[ { "index of dataGroup": "value" }, ... ] * @example * [{ - * "xPos": 0, - * "xStrVal": "0", - * "groupedY": [{"groupIdx": 0, "yStrVal": 9, "yPos": 18, "color": "#deebf7"}], + * "basePos": 0, + * "baseStrVal": "0", + * "projectedVals": [{"groupIdx": 0, "projectedStrVal": 9, "projectedPos": 18, "color": "#deebf7"}], * }, * { - * "xPos": 109.12812500000001, - * "xStrVal": "2", - * "groupedY": [{"groupIdx": 0, "yStrVal": 3, "yPos": 6, "color": "#deebf7"}, ...], + * "basePos": 109.12812500000001, + * "baseStrVal": "2", + * "projectedVals": [{"groupIdx": 0, "projectedStrVal": 3, "projectedPos": 6, "color": "#deebf7"}, ...], * }] */ export function getAxisProjectedValues( /** Data grouped in `useCartesianEncodings()` */ dataGroups: object[][], - /** Functions to get value on the x-axis */ - xSelector: FieldSelector, + /** + * Functions to get value on the base axis, + * normally x-axis, if the graph has not been transposed. + */ + baseSelector: FieldSelector, - /** Functions to get value on the y-axis */ - ySelector: FieldSelector, + /** + * Functions to get value on the project axis, + * normally y-axis, if the graph has not been transposed. + */ + projectedSelector: FieldSelector, /** Functions to get the formatted color string */ getColorString: (record: any) => string, ) { // project by original values on the axis const projections = {}; - const xPositions = {}; + const basePositions = {}; dataGroups.forEach((group, groupIdx) => { group.forEach((row) => { - const xStrVal = xSelector.getFormattedStringVal(row); - const yStrVal = ySelector.getFormattedStringVal(row); - const xPos = xSelector.getScaledVal(row); - const yPos = ySelector.getScaledVal(row); - if (!projections[xStrVal]) { - projections[xStrVal] = []; - xPositions[xStrVal] = xPos; + const baseStrVal = baseSelector.getFormattedStringVal(row); + const projectedStrVal = projectedSelector.getFormattedStringVal(row); + const basePos = baseSelector.getScaledVal(row); + const projectedPos = projectedSelector.getScaledVal(row); + if (!projections[baseStrVal]) { + projections[baseStrVal] = []; + basePositions[baseStrVal] = basePos; } - projections[xStrVal].push({ + projections[baseStrVal].push({ groupIdx, - yStrVal, - yPos, + projectedStrVal, + projectedPos, color: getColorString(row), }); }); @@ -55,14 +61,14 @@ export function getAxisProjectedValues( // convert the position along the axis, and sort by the converted values const columns = Object.keys(projections).reduce( - (accum, xStrVal: any) => { - const groupedY = projections[xStrVal]; + (accum, baseStrVal: any) => { + const projectedVals = projections[baseStrVal]; // ensure that we always get the correct type, not a string instead - const xPos: number = xPositions[xStrVal] || 0; + const basePos: number = basePositions[baseStrVal] || 0; const column = { - xPos, - xStrVal, - groupedY, + basePos, + baseStrVal, + projectedVals, }; return [...accum, column]; @@ -70,5 +76,5 @@ export function getAxisProjectedValues( [] ); - return columns.sort((a, b) => (a.xPos - b.xPos)); + return columns.sort((a, b) => (a.basePos - b.basePos)); } diff --git a/packages/graph/src/layers/TooltipLayer.tsx b/packages/graph/src/layers/TooltipLayer.tsx index cb02eb9..df6e91e 100644 --- a/packages/graph/src/layers/TooltipLayer.tsx +++ b/packages/graph/src/layers/TooltipLayer.tsx @@ -7,24 +7,24 @@ export interface GroupedY { /** Index of `dataGroups` */ groupIdx: number; - /** Original value on Y */ - yStrVal: number; + /** Original value (normally on y-axis) */ + projectedStrVal: number; - /** Projected position of Y */ - yPos: number; + /** Projected position (normally on y-axis) */ + projectedPos: number; /** Color string of the point */ color: string; } export interface AxisProjectedValue { - /** Projected position of X */ - xPos: number; + /** Projected position of the base axis (normally x-axis) */ + basePos: number; - /** Original value on X */ - xStrVal: number; + /** Original value on the base axis (normally x-axis) */ + baseStrVal: number; /** Corresponding data in `dataGroups` */ - groupedY: GroupedY[]; + projectedVals: GroupedY[]; } export interface TooltipLayerProps { @@ -56,17 +56,17 @@ export const TooltipLayer = ({ graphWidth, graphHeight, margin, - x = axisProjectedValues[hoveredPoint.index].xPos, + x = axisProjectedValues[hoveredPoint.index].basePos, y = hoveredPoint.position.y, xOffset = 0, yOffset = 0, }: TooltipLayerProps) => { const projected = axisProjectedValues[hoveredPoint.index]; - const tooltipItems = projected.groupedY.map(pointY => ( + const tooltipItems = projected.projectedVals.map(pointY => ( )); @@ -81,7 +81,7 @@ export const TooltipLayer = ({ }} show={hovering} > -

{`${projected.xStrVal}`}

+

{`${projected.baseStrVal}`}

{tooltipItems} ); From 7306bfff6272d25624bc77d313c562b74a143c45 Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Fri, 19 Jul 2019 14:39:05 +0800 Subject: [PATCH 10/33] Fix the horizontal hovering tooltips --- packages/chart/src/bar/BarChart.tsx | 25 +++++++++++++-- .../chart/src/hooks/useCartesianEncodings.ts | 32 ++++++++++++------- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/packages/chart/src/bar/BarChart.tsx b/packages/chart/src/bar/BarChart.tsx index 62a3f52..feeaed2 100644 --- a/packages/chart/src/bar/BarChart.tsx +++ b/packages/chart/src/bar/BarChart.tsx @@ -116,7 +116,15 @@ export const BarChart = ({ scalesConfig, rowValSelectors, axisProjectedValues, - } = useCartesianEncodings(graphDimension, theme, data, xEncoding, yEncoding, color); + } = useCartesianEncodings( + graphDimension, + theme, + data, + xEncoding, + yEncoding, + color, + drawFromXAxis, + ); const { clearHovering, hovering, hoveredPoint, setHoveredPosAndIndex } = useHoverState(); const bandScale = scalesConfig[drawFromXAxis ? 'x' : 'y'].scale as ScaleBand; @@ -131,17 +139,28 @@ export const BarChart = ({ (idx: number) => { const paddingVal = bandWidth * paddingInner; - const xPos = idx === 0 + const basePos = idx === 0 ? 0 : axisProjectedValues[idx].basePos - paddingVal / 2; const width = idx === 0 || idx === data.length - 1 ? bandWidth + paddingVal / 2 : bandWidth + paddingVal; + // transposed (horizontal) graph + if (!drawFromXAxis) { + return { + width: graphWidth, + height: width, + x: 0, + y: basePos, + } + } + + // vertical graph return { width, height: graphHeight, - x: xPos, + x: basePos, y: 0, }; }, diff --git a/packages/chart/src/hooks/useCartesianEncodings.ts b/packages/chart/src/hooks/useCartesianEncodings.ts index bde5990..a42e9a8 100644 --- a/packages/chart/src/hooks/useCartesianEncodings.ts +++ b/packages/chart/src/hooks/useCartesianEncodings.ts @@ -75,6 +75,13 @@ export const useCartesianEncodings = ( /** Fields and definitions for colors */ color?: ColorEncoding, + + /** + * Whether the graph is drawn from the x-axis, i.e., vertical graph. + * In a transposed (horizontal) graph, you have to set it as false, + * in order to get the right `axisProjectedValues` value. + */ + drawFromXAxis?: boolean = true, ) => { // get the inner width and height of the graph const { width, height } = graphDimension; @@ -173,6 +180,9 @@ export const useCartesianEncodings = ( const axisProjectedValues: AxisProjectedValue[] = useMemo( () => { + if (!drawFromXAxis) { + return getAxisProjectedValues(dataGroups, ySelector, xSelector, getColorString); + } return getAxisProjectedValues(dataGroups, xSelector, ySelector, getColorString); }, [dataGroups, xSelector, ySelector, getColorString], @@ -185,17 +195,17 @@ export const useCartesianEncodings = ( /** * The y-values in the `dataGroups` grouped by projected x values. * - Structure of groupedY: "groupedY":[ { "index of dataGroup": "value" }, ... ] - * @example - * [{ - * "xPos": 0, - * "xStrVal": "0", - * "groupedY": [{"groupIdx": 0, "yStrVal": 9, "yPos": 18, "color": "#deebf7"}], - * }, - * { - * "xPos": 109.12812500000001, - * "xStrVal": "2", - * "groupedY": [{"groupIdx": 0, "yStrVal": 3, "yPos": 6, "color": "#deebf7"}, ...], - * }] + * @example + * [{ + * "basePos": 0, + * "baseStrVal": "0", + * "projectedVals": [{"groupIdx": 0, "projectedStrVal": 9, "projectedPos": 18, "color": "#deebf7"}], + * }, + * { + * "basePos": 109.12812500000001, + * "baseStrVal": "2", + * "projectedVals": [{"groupIdx": 0, "projectedStrVal": 3, "projectedPos": 6, "color": "#deebf7"}, ...], + * }] */ axisProjectedValues, From 39a882a625f9824c2c7c48dbc3a14e6f8dff17b2 Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Fri, 19 Jul 2019 17:50:14 +0800 Subject: [PATCH 11/33] Fix the grouped graphs --- packages/chart/src/bar/BarChart.tsx | 14 ++++++++++---- packages/chart/src/hooks/useCartesianEncodings.ts | 10 +++++++--- packages/chart/src/utils/getBarChartPos.ts | 2 +- packages/graph/src/utils/getRecordFieldSelector.ts | 2 +- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/packages/chart/src/bar/BarChart.tsx b/packages/chart/src/bar/BarChart.tsx index feeaed2..34299e2 100644 --- a/packages/chart/src/bar/BarChart.tsx +++ b/packages/chart/src/bar/BarChart.tsx @@ -185,6 +185,9 @@ export const BarChart = ({ [axisProjectedValues, graphHeight, bandWidth, getHoveringRectPos] ); + /** + * Draw the bars of the bar chart + */ const graphGroup = useMemo( () => { const baseVal = linearScale(0); @@ -201,8 +204,8 @@ export const BarChart = ({ let barPos; if (drawFromXAxis) { const height = scaledY >= 0 - ? baseVal - scaledY - : baseVal - graphHeight - scaledY; + ? baseVal - scaledY + : baseVal - graphHeight - scaledY; barPos = { x: scaledX, @@ -211,10 +214,13 @@ export const BarChart = ({ height: Math.abs(height), }; } else { + // transposed (horizontal) graph + const diffFromBase = scaledX - baseVal; + barPos = { - x: getAccumVal(scaledY, baseVal), + x: getAccumVal(scaledY, diffFromBase), y: scaledY, - width: scaledX, + width: Math.abs(diffFromBase), height: bandWidth, }; } diff --git a/packages/chart/src/hooks/useCartesianEncodings.ts b/packages/chart/src/hooks/useCartesianEncodings.ts index a42e9a8..b1e0bcc 100644 --- a/packages/chart/src/hooks/useCartesianEncodings.ts +++ b/packages/chart/src/hooks/useCartesianEncodings.ts @@ -81,7 +81,7 @@ export const useCartesianEncodings = ( * In a transposed (horizontal) graph, you have to set it as false, * in order to get the right `axisProjectedValues` value. */ - drawFromXAxis?: boolean = true, + drawFromXAxis: boolean = true, ) => { // get the inner width and height of the graph const { width, height } = graphDimension; @@ -121,7 +121,9 @@ export const useCartesianEncodings = ( // update the domain if the domains of x-y scales is band-linear if (x.scale === 'linear' && y.scale === 'band') { - axisScale.scale.domain(getLinearDomainFromDataGroup(dataGroups, y.field, x.field)); + const domain = getLinearDomainFromDataGroup(dataGroups, y.field, x.field); + axisScale.domain = domain; + axisScale.scale.domain(domain); } return axisScale; }, @@ -137,7 +139,9 @@ export const useCartesianEncodings = ( // update the domain if the domains of x-y scales is linear-band if (x.scale === 'band' && y.scale === 'linear') { - axisScale.scale.domain(getLinearDomainFromDataGroup(dataGroups, x.field, y.field)); + const domain = getLinearDomainFromDataGroup(dataGroups, x.field, y.field); + axisScale.domain = domain; + axisScale.scale.domain(domain); } return axisScale; }, diff --git a/packages/chart/src/utils/getBarChartPos.ts b/packages/chart/src/utils/getBarChartPos.ts index 8485f99..034f43e 100644 --- a/packages/chart/src/utils/getBarChartPos.ts +++ b/packages/chart/src/utils/getBarChartPos.ts @@ -8,7 +8,7 @@ export function getAccumXCalculator(baseX: number) { if (!nonPositiveX[yPos]) { nonPositiveX[yPos] = baseX; } - nonPositiveX[yPos] -= scaledX; + nonPositiveX[yPos] += scaledX; return nonPositiveX[yPos]; } diff --git a/packages/graph/src/utils/getRecordFieldSelector.ts b/packages/graph/src/utils/getRecordFieldSelector.ts index 6e62e36..d4a8a0c 100644 --- a/packages/graph/src/utils/getRecordFieldSelector.ts +++ b/packages/graph/src/utils/getRecordFieldSelector.ts @@ -14,7 +14,7 @@ export function getRecordFieldSelector( const { field, scale, scaleType } = axis; const getValue = getValByScaleType(scaleType); - /** Given a record of data, it returns the orginal value of the specified field */ + /** Given a record of data, it returns the original value of the specified field */ const getOriginalVal = (record: object) => getValue(record[field]); return { From 8504d0f2d05fab5bfa946f49584a35031c552961 Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Fri, 19 Jul 2019 18:15:04 +0800 Subject: [PATCH 12/33] Sort the values of the transposed chart --- packages/chart/src/hooks/useCartesianEncodings.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/chart/src/hooks/useCartesianEncodings.ts b/packages/chart/src/hooks/useCartesianEncodings.ts index b1e0bcc..bea756c 100644 --- a/packages/chart/src/hooks/useCartesianEncodings.ts +++ b/packages/chart/src/hooks/useCartesianEncodings.ts @@ -89,8 +89,9 @@ export const useCartesianEncodings = ( // sort the data const sortedData = useMemo( () => { - const getValue = getValByScaleType(x.scale); - const getOriginalVal = (record: object) => getValue(record[x.field]); + const baseAxis = drawFromXAxis ? x : y; + const getValue = getValByScaleType(baseAxis.scale); + const getOriginalVal = (record: object) => getValue(record[baseAxis.field]); return ( data.sort( From baf004be36c5bc19333ead956eefe09d44f0155a Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Fri, 19 Jul 2019 18:24:43 +0800 Subject: [PATCH 13/33] Refine the comments --- .../chart/src/hooks/useCartesianEncodings.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/chart/src/hooks/useCartesianEncodings.ts b/packages/chart/src/hooks/useCartesianEncodings.ts index bea756c..bf81c63 100644 --- a/packages/chart/src/hooks/useCartesianEncodings.ts +++ b/packages/chart/src/hooks/useCartesianEncodings.ts @@ -202,15 +202,15 @@ export const useCartesianEncodings = ( * - Structure of groupedY: "groupedY":[ { "index of dataGroup": "value" }, ... ] * @example * [{ - * "basePos": 0, - * "baseStrVal": "0", - * "projectedVals": [{"groupIdx": 0, "projectedStrVal": 9, "projectedPos": 18, "color": "#deebf7"}], - * }, - * { - * "basePos": 109.12812500000001, - * "baseStrVal": "2", - * "projectedVals": [{"groupIdx": 0, "projectedStrVal": 3, "projectedPos": 6, "color": "#deebf7"}, ...], - * }] + * "basePos": 0, + * "baseStrVal": "0", + * "projectedVals": [{"groupIdx": 0, "projectedStrVal": 9, "projectedPos": 18, "color": "#deebf7"}], + * }, + * { + * "basePos": 109.12812500000001, + * "baseStrVal": "2", + * "projectedVals": [{"groupIdx": 0, "projectedStrVal": 3, "projectedPos": 6, "color": "#deebf7"}, ...], + * }] */ axisProjectedValues, From 18beee8e649cb82d87831683a82cd8feb5d503bc Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Fri, 19 Jul 2019 18:24:53 +0800 Subject: [PATCH 14/33] Improve the performance of AxisLayer --- packages/graph/src/layers/AxisLayer.tsx | 137 +++++++++++++----------- 1 file changed, 77 insertions(+), 60 deletions(-) diff --git a/packages/graph/src/layers/AxisLayer.tsx b/packages/graph/src/layers/AxisLayer.tsx index a180df1..97b3655 100644 --- a/packages/graph/src/layers/AxisLayer.tsx +++ b/packages/graph/src/layers/AxisLayer.tsx @@ -114,7 +114,6 @@ export const AxisLayer: React.SFC = ({ xAxisScale, yAxisScale, }) => { - const theme = useContext(ThemeContext); const { xAxis: xAxisTheme, yAxis: yAxisTheme } = theme; @@ -128,64 +127,82 @@ export const AxisLayer: React.SFC = ({ [xAxisScale, yAxisScale] ); - const yDomain = yAxisScale.domain(); - const shouldShowZeroline = showZeroLine && yDomain[0] * yDomain[1] < 0; - - return ( - <> - {/* Zero value line */} - {shouldShowZeroline && ( - - )} - - {/* Y Axis */} - {showLeftAxis && ( - ( - // {formattedValue} - // )} - /> - )} - - {/* X Axis */} - {showBottomAxis && ( - - )} - + const axisLayer = useMemo( + () => { + const yDomain = yAxisScale.domain(); + const shouldShowZeroline = showZeroLine && yDomain[0] * yDomain[1] < 0; + + return ( + <> + {/* Zero value line */} + {shouldShowZeroline && ( + + )} + + {/* Y Axis */} + {showLeftAxis && ( + ( + // {formattedValue} + // )} + /> + )} + + {/* X Axis */} + {showBottomAxis && ( + + )} + + ); + }, + [ + width, + height, + x, + y, + showLeftAxis = true, + showBottomAxis = true, + showZeroLine = true, + data, + xAxisScale, + yAxisScale, + ] ); + + return axisLayer; }; From cd1decdb01d6ef46af47fe6f0d158fce63781989 Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Mon, 22 Jul 2019 12:07:43 +0800 Subject: [PATCH 15/33] Fix tslint's config --- tslint.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tslint.json b/tslint.json index 8ea6078..93212e0 100644 --- a/tslint.json +++ b/tslint.json @@ -62,7 +62,7 @@ "code": 100, "tabWidth": 2, "ignoreUrls": true, - "comments": false, + "comments": false } ], // ============= from tslint-react ============= From ad76c46c2c83dc808b56314f1d1e9e7245df2bfd Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Mon, 22 Jul 2019 16:44:10 +0800 Subject: [PATCH 16/33] Fix various errors related to hooks --- packages/chart/src/bar/BarChart.tsx | 4 ++-- packages/graph/src/layers/AxisLayer.tsx | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/chart/src/bar/BarChart.tsx b/packages/chart/src/bar/BarChart.tsx index 34299e2..1bbb8f4 100644 --- a/packages/chart/src/bar/BarChart.tsx +++ b/packages/chart/src/bar/BarChart.tsx @@ -153,7 +153,7 @@ export const BarChart = ({ height: width, x: 0, y: basePos, - } + }; } // vertical graph @@ -164,7 +164,7 @@ export const BarChart = ({ y: 0, }; }, - [bandWidth, paddingInner], + [bandWidth, paddingInner, graphWidth, graphHeight], ); const hoverDetectionComponents = useMemo( diff --git a/packages/graph/src/layers/AxisLayer.tsx b/packages/graph/src/layers/AxisLayer.tsx index 97b3655..e94dde8 100644 --- a/packages/graph/src/layers/AxisLayer.tsx +++ b/packages/graph/src/layers/AxisLayer.tsx @@ -195,9 +195,9 @@ export const AxisLayer: React.SFC = ({ height, x, y, - showLeftAxis = true, - showBottomAxis = true, - showZeroLine = true, + showLeftAxis, + showBottomAxis, + showZeroLine, data, xAxisScale, yAxisScale, From 4fc615886f5b431d751f8beb31750352ec6e30f2 Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Tue, 23 Jul 2019 12:30:08 +0800 Subject: [PATCH 17/33] Refine the position of tooltips Fix the positions of the tooltips --- packages/chart/src/bar/BarChart.tsx | 16 ++++++++++++++-- packages/graph/src/layers/TooltipLayer.tsx | 11 ++++++++--- packages/graph/src/tooltip/Tooltip.tsx | 20 +++++--------------- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/packages/chart/src/bar/BarChart.tsx b/packages/chart/src/bar/BarChart.tsx index 1bbb8f4..1ef0b42 100644 --- a/packages/chart/src/bar/BarChart.tsx +++ b/packages/chart/src/bar/BarChart.tsx @@ -129,7 +129,18 @@ export const BarChart = ({ const bandScale = scalesConfig[drawFromXAxis ? 'x' : 'y'].scale as ScaleBand; const linearScale = scalesConfig[drawFromXAxis ? 'y' : 'x'].scale as ScaleLinear; - const bandWidth = bandScale.bandwidth(); + const bandWidth = useMemo( + () => { + return bandScale.bandwidth(); + }, + [bandScale] + ); + const xOffset = useMemo( + () => { + return drawFromXAxis ? bandWidth / 2 : 0; + }, + [drawFromXAxis, bandWidth] + ); /** * Returns the size and position of the hovering detection rectangle @@ -267,7 +278,8 @@ export const BarChart = ({ graphWidth={graphWidth} graphHeight={graphHeight} margin={margin} - xOffset={bandWidth / 2} + drawFromXAxis={drawFromXAxis} + xOffset={xOffset} /> {/* Draw the legend */} { @@ -74,7 +80,6 @@ export const TooltipLayer = ({ 0.5; const percentX = onRightHalf ? -100 : 0; - const percentY = Math.round(-100 * (position.y / graphHeight)); - const leftOffset = onRightHalf ? -20 : 20; + const percentY = Math.round(-80 * (position.y / graphHeight)); + const xOffset = onRightHalf ? -10 : 10; return { - top: `${graphMargin.top + position.y}px`, - left: `${graphMargin.left + position.x + leftOffset}px`, + top: `${position.y}px`, + left: `${position.x + xOffset}px`, transform: `translate(${percentX}%, ${percentY}%)`, transition: 'all 150ms ease', }; @@ -65,18 +62,12 @@ export const Tooltip: FunctionComponent = ({ show = false, graphWidth, graphHeight, - graphMargin = { - top: 0, - right: 0, - bottom: 0, - left: 0, - }, }) => { if (!position) { return null; } - const tooltipStyle = getTooltipPosition(graphWidth, graphHeight, graphMargin, position); + const tooltipStyle = getTooltipPosition(graphWidth, graphHeight, position); const transition = useTransition(show, null, { from: { opacity: 0 }, @@ -99,5 +90,4 @@ export const Tooltip: FunctionComponent = ({ ))} ); - }; From 1b65803ca9d031a478d4dfa0d7727227ed633101 Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Tue, 23 Jul 2019 14:21:29 +0800 Subject: [PATCH 18/33] Use memoization to improve the performance --- .../chart/src/frames/SvgWithAxisFrame.tsx | 71 ++++++++++++------- 1 file changed, 46 insertions(+), 25 deletions(-) diff --git a/packages/chart/src/frames/SvgWithAxisFrame.tsx b/packages/chart/src/frames/SvgWithAxisFrame.tsx index 5be69e1..011f7de 100644 --- a/packages/chart/src/frames/SvgWithAxisFrame.tsx +++ b/packages/chart/src/frames/SvgWithAxisFrame.tsx @@ -1,4 +1,4 @@ -import React, { useContext } from 'react'; +import React, { useContext, useMemo } from 'react'; import { // from AxisLayer AxisLayer, @@ -97,32 +97,53 @@ const FrameContent = ({ svgOverlay, children, }: FrameContentProps) => { - const { width: outerWidth, height: outerHeight } = outerDimension; - const { width: graphWidth, height: graphHeight } = graphDimension; - const axisLayer = ( - + // memoize the frame to increase the performance when rendering tooltips + const momoizedFrame = useMemo( + () => { + const { width: outerWidth, height: outerHeight } = outerDimension; + const { width: graphWidth, height: graphHeight } = graphDimension; + const axisLayer = ( + + ); + + return ( + <> + + + {axisInBackground ? (<>{axisLayer}{children}) : (<>{children}{axisLayer})} + + + {svgOverlay} + + ); + }, + [ + outerDimension, + graphDimension, + x, + y, + margin, + data, + scalesConfig, + showLeftAxis, + showBottomAxis, + axisInBackground, + svgOverlay, + children, + ] ); - return ( - <> - - - {axisInBackground ? (<>{axisLayer}{children}) : (<>{children}{axisLayer})} - - - {svgOverlay} - - ); + return momoizedFrame; }; FrameContent.defaultProps = defaultProps; From 43d8d1bf6d84e3ac7f6ba06e9e86226e451e1ca8 Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Tue, 23 Jul 2019 14:39:05 +0800 Subject: [PATCH 19/33] Remove the max length checking for the comments --- .../chart/src/hooks/useCartesianEncodings.ts | 22 +++++++++---------- tslint.json | 3 ++- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/packages/chart/src/hooks/useCartesianEncodings.ts b/packages/chart/src/hooks/useCartesianEncodings.ts index bf81c63..3fdb176 100644 --- a/packages/chart/src/hooks/useCartesianEncodings.ts +++ b/packages/chart/src/hooks/useCartesianEncodings.ts @@ -200,17 +200,17 @@ export const useCartesianEncodings = ( /** * The y-values in the `dataGroups` grouped by projected x values. * - Structure of groupedY: "groupedY":[ { "index of dataGroup": "value" }, ... ] - * @example - * [{ - * "basePos": 0, - * "baseStrVal": "0", - * "projectedVals": [{"groupIdx": 0, "projectedStrVal": 9, "projectedPos": 18, "color": "#deebf7"}], - * }, - * { - * "basePos": 109.12812500000001, - * "baseStrVal": "2", - * "projectedVals": [{"groupIdx": 0, "projectedStrVal": 3, "projectedPos": 6, "color": "#deebf7"}, ...], - * }] + * @example + * [{ + * "basePos": 0, + * "baseStrVal": "0", + * "projectedVals": [{"groupIdx": 0, "projectedStrVal": 9, "projectedPos": 18, "color": "#deebf7"}], + * }, + * { + * "basePos": 109.12812500000001, + * "baseStrVal": "2", + * "projectedVals": [{"groupIdx": 0, "projectedStrVal": 3, "projectedPos": 6, "color": "#deebf7"}, ...], + * }] */ axisProjectedValues, diff --git a/tslint.json b/tslint.json index 93212e0..2cbba15 100644 --- a/tslint.json +++ b/tslint.json @@ -56,13 +56,14 @@ ], // ============= from tslint-eslint-rules ============= "object-curly-spacing": [true, "always"], + "max-line-length": [false], "ter-max-len": [ true, { "code": 100, "tabWidth": 2, "ignoreUrls": true, - "comments": false + "ignoreComments": true } ], // ============= from tslint-react ============= From dbf0ee67ece89314f391dbd0b52918d27b234937 Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Tue, 23 Jul 2019 16:19:50 +0800 Subject: [PATCH 20/33] Show the zero value line for the horizontal graph --- packages/chart/src/bar/BarChart.tsx | 1 + .../chart/src/frames/SvgWithAxisFrame.tsx | 6 +++ packages/graph/src/layers/AxisLayer.tsx | 53 ++++++++++++++----- 3 files changed, 47 insertions(+), 13 deletions(-) diff --git a/packages/chart/src/bar/BarChart.tsx b/packages/chart/src/bar/BarChart.tsx index 1ef0b42..3d2d30d 100644 --- a/packages/chart/src/bar/BarChart.tsx +++ b/packages/chart/src/bar/BarChart.tsx @@ -263,6 +263,7 @@ export const BarChart = ({ showBottomAxis={showBottomAxis} x={x} y={y} + drawFromXAxis={drawFromXAxis} // put the axes on top of the bars axisInBackground={false} margin={margin} diff --git a/packages/chart/src/frames/SvgWithAxisFrame.tsx b/packages/chart/src/frames/SvgWithAxisFrame.tsx index 011f7de..4c5f009 100644 --- a/packages/chart/src/frames/SvgWithAxisFrame.tsx +++ b/packages/chart/src/frames/SvgWithAxisFrame.tsx @@ -30,6 +30,9 @@ export interface FrameContentProps { /** Axis encoding of y-axis */ y: AxisEncoding; + /** Whether it is a vertical chart. True for most charts. */ + drawFromXAxis: boolean; + /** Margin between the inner graph area and the outer svg */ margin: Margin; @@ -74,6 +77,7 @@ const defaultProps = { showLeftAxis: true, showBottomAxis: true, axisInBackground: true, + drawFromXAxis: true, }; const Wrapper = styled.div` @@ -88,6 +92,7 @@ const FrameContent = ({ graphDimension, x, y, + drawFromXAxis, margin, data, scalesConfig, @@ -111,6 +116,7 @@ const FrameContent = ({ data={data} x={x} y={y} + drawFromXAxis={drawFromXAxis} xAxisScale={scalesConfig.x.scale} yAxisScale={scalesConfig.y.scale} /> diff --git a/packages/graph/src/layers/AxisLayer.tsx b/packages/graph/src/layers/AxisLayer.tsx index e94dde8..d067e13 100644 --- a/packages/graph/src/layers/AxisLayer.tsx +++ b/packages/graph/src/layers/AxisLayer.tsx @@ -53,6 +53,9 @@ export interface AxisLayerProps { /** Axis encoding of y-axis */ y: AxisEncoding; + /** Whether it is a vertical chart. True for most charts. */ + drawFromXAxis?: boolean; + /** X-axis configurations produced by `getAxisScale` */ xAxisScale: AxisScale['scale']; @@ -63,14 +66,25 @@ export interface AxisLayerProps { const getZeroLineProps = ( xAxisScale: AxisScale['scale'], yAxisScale: AxisScale['scale'], + drawFromXAxis: AxisLayerProps['drawFromXAxis'], ) => { - const yPos = yAxisScale(0); + if (drawFromXAxis) { + const yPos = yAxisScale(0); + return { + x1: 0, + y1: yPos, + x2: xAxisScale.range()[1], + y2: yPos, + }; + } + // horizontal charts + const xPos = xAxisScale(0); return { - x1: 0, - y1: yPos, - x2: xAxisScale.range()[1], - y2: yPos, + x1: xPos, + y1: 0, + x2: xPos, + y2: yAxisScale.range()[0], }; }; @@ -110,6 +124,7 @@ export const AxisLayer: React.SFC = ({ showBottomAxis = true, // it should always show the zero line if its domain crosses zero showZeroLine = true, + drawFromXAxis = true, data, xAxisScale, yAxisScale, @@ -120,22 +135,34 @@ export const AxisLayer: React.SFC = ({ const xAxisLabel = useMemo(() => getAxisLabel(x), [x]); const yAxisLabel = useMemo(() => getAxisLabel(y), [y]); + // props for the zero value assisting const zeroLineProps = useMemo( - () => ( - getZeroLineProps(xAxisScale, yAxisScale) - ), - [xAxisScale, yAxisScale] + () => { + let crossedPosNeg = false; + if (drawFromXAxis) { + const yDomain = yAxisScale.domain(); + crossedPosNeg = yDomain[0] * yDomain[1] < 0; + } else { + const xDomain = xAxisScale.domain(); + crossedPosNeg = xDomain[0] * xDomain[1] < 0; + } + + // if there is no need to draw the zero value line + if (!(showZeroLine && crossedPosNeg)) { + return undefined; + } + + return getZeroLineProps(xAxisScale, yAxisScale, drawFromXAxis); + }, + [xAxisScale, yAxisScale, drawFromXAxis] ); const axisLayer = useMemo( () => { - const yDomain = yAxisScale.domain(); - const shouldShowZeroline = showZeroLine && yDomain[0] * yDomain[1] < 0; - return ( <> {/* Zero value line */} - {shouldShowZeroline && ( + {zeroLineProps && ( Date: Tue, 23 Jul 2019 16:30:32 +0800 Subject: [PATCH 21/33] Disable the checking of unused variables in dev --- config/tsconfig.docz.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/tsconfig.docz.json b/config/tsconfig.docz.json index c593639..0d9c4e5 100644 --- a/config/tsconfig.docz.json +++ b/config/tsconfig.docz.json @@ -1,7 +1,8 @@ { "extends": "./tsconfig.base.json", "compilerOptions": { - "rootDir": "../" + "rootDir": "../", + "noUnusedLocals": false }, "include": [ "../packages/**/*" From 7e312f6b9ea249fd88b2ab0a2b6e86145151df8b Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Tue, 23 Jul 2019 16:36:36 +0800 Subject: [PATCH 22/33] Add some documentations about transposing the x-y axis --- docs/charts/BarChart.mdx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/charts/BarChart.mdx b/docs/charts/BarChart.mdx index fbb52f1..e2ca95e 100644 --- a/docs/charts/BarChart.mdx +++ b/docs/charts/BarChart.mdx @@ -43,6 +43,8 @@ const lineData = [ ### Linear + Linear (transposed) +You can easily transpose the XY axis by just switching the x and y prop of ``. +
`. + +For example, the vertical chart above become the horizontal one in the below by simply switching `x` and `y`. + +This feature is realized by the checkings of the data types of the axis configs of ``. +
Date: Tue, 23 Jul 2019 17:36:53 +0800 Subject: [PATCH 23/33] Fix the comment --- packages/graph/src/layers/AxisLayer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/graph/src/layers/AxisLayer.tsx b/packages/graph/src/layers/AxisLayer.tsx index d067e13..96a750a 100644 --- a/packages/graph/src/layers/AxisLayer.tsx +++ b/packages/graph/src/layers/AxisLayer.tsx @@ -135,7 +135,7 @@ export const AxisLayer: React.SFC = ({ const xAxisLabel = useMemo(() => getAxisLabel(x), [x]); const yAxisLabel = useMemo(() => getAxisLabel(y), [y]); - // props for the zero value assisting + // props for the zero value auxiliary line const zeroLineProps = useMemo( () => { let crossedPosNeg = false; From 231741c56b94606b37a5dd474ae9bf3e57cba5a4 Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Tue, 23 Jul 2019 17:37:08 +0800 Subject: [PATCH 24/33] Refine the tooltip offsets --- packages/graph/src/tooltip/Tooltip.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/graph/src/tooltip/Tooltip.tsx b/packages/graph/src/tooltip/Tooltip.tsx index 7b05f71..eaa7d9f 100644 --- a/packages/graph/src/tooltip/Tooltip.tsx +++ b/packages/graph/src/tooltip/Tooltip.tsx @@ -47,7 +47,7 @@ function getTooltipPosition( const onRightHalf = (position.x / graphWidth) > 0.5; const percentX = onRightHalf ? -100 : 0; const percentY = Math.round(-80 * (position.y / graphHeight)); - const xOffset = onRightHalf ? -10 : 10; + const xOffset = onRightHalf ? -16 : 16; return { top: `${position.y}px`, left: `${position.x + xOffset}px`, From 15ebb6b6d9decca22da8fc8b467d9654ff6b4fe0 Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Tue, 23 Jul 2019 17:39:21 +0800 Subject: [PATCH 25/33] Add CHANGELOG for supporting the horizontal bar charts --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b5e152..dc95df2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `useWorkspaces` in Lerna's config to allow lerna bootstrap to run. (#35) - Add the deployment script to publish the compiled `docz` docs. (#36) - Add `` to display the chart title and chart descriptions. (#39) +- Support drawing the horizontal bar chart. (#40) +- Add a gray auxiliary line at zero-value. (#40) # Changed - Clean compiled files before the docz server started. (#34) @@ -21,6 +23,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Prevent Jest tests from being checked by `ForkTSCheckerWebpackPlugin` of docz when developing. (#35) - Display labels of the fields along with the axes. (#39) - Re-organize the structure of the document, and add the introduction of the project. (#39) +- Disable tslint on the length of the comments. (#40) +- Disable the checking of unused variables on development. (#40) # Fixed - Fix the typing problems raised by `@types/styled-components` and `react-spring`. (#35) From affa5c0618ad85b967947b0b900bd9e0cb758c3f Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Thu, 1 Aug 2019 11:39:30 +0800 Subject: [PATCH 26/33] Fix the keys of tooltip items --- packages/graph/src/layers/TooltipLayer.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/graph/src/layers/TooltipLayer.tsx b/packages/graph/src/layers/TooltipLayer.tsx index 9b24b5e..360d008 100644 --- a/packages/graph/src/layers/TooltipLayer.tsx +++ b/packages/graph/src/layers/TooltipLayer.tsx @@ -68,9 +68,9 @@ export const TooltipLayer = ({ yOffset = 0, }: TooltipLayerProps) => { const projected = axisProjectedValues[hoveredPoint.index]; - const tooltipItems = projected.projectedVals.map(pointY => ( + const tooltipItems = projected.projectedVals.map((pointY, key) => ( From 4d0dfeef56fb951b632ec9bca10143d2ae55ba96 Mon Sep 17 00:00:00 2001 From: garfieldduck Date: Thu, 25 Jul 2019 16:51:38 +0800 Subject: [PATCH 27/33] Avoid the width of images exceed the width of the doc --- doczrc.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doczrc.js b/doczrc.js index d4390dc..bb44763 100644 --- a/doczrc.js +++ b/doczrc.js @@ -43,6 +43,7 @@ export default { 'Graph Hooks', 'Animations', 'Themes', + 'API Reference', ], modifyBundlerConfig, themeConfig: { @@ -60,6 +61,13 @@ export default { theadColor: '#555e6d', }, styles: { + body: css` + font-family: 'Source Sans Pro',helvetica,'PingFang TC','Noto Sans TC','Microsoft JhengHei',sans-serif; + line-height: 1.6; + img { + max-width: 100%; + } + `, playground: css` background: #ffffff; padding: 1rem; From 2ec109c3c7e58048f067bd7b8667f7b9fe7ec1ff Mon Sep 17 00:00:00 2001 From: garfieldduck Date: Thu, 25 Jul 2019 17:47:35 +0800 Subject: [PATCH 28/33] Add documents for calculating the chart dimensions --- docs/api-reference/Overview.mdx | 40 +++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 docs/api-reference/Overview.mdx diff --git a/docs/api-reference/Overview.mdx b/docs/api-reference/Overview.mdx new file mode 100644 index 0000000..1c9fd91 --- /dev/null +++ b/docs/api-reference/Overview.mdx @@ -0,0 +1,40 @@ +--- +name: Making Your Own Charts +route: /api_reference/overview +menu: API Reference +--- + +# Making Your Own Charts + +You can utilize the `@ichef/transcharts-graph` and `@ichef/transcharts-chart` packages to create charts with X and Y axis. + + +### Calculate Chart Dimensions + +The `useChartDimensions` lets you get the `outerDimension` and `graphDimension`. + +By attaching the ref to the outer chart (`chartRef`), the ref to the title box (`titleRef`), the legend (`legendRef`), and the inner margin of the chart, +it calcultates the following dimensions: + +- Full dimension of the chart (`outerDimension`: see the blue text on the graph below) +- Inner dimension of the chart (`graphDimension`: see the orange text on the graph below) + +```js + const { + chartRef, + titleRef, + legendRef, + outerDimension, + graphDimension, + } = useChartDimensions(margin); +``` + +![Transchart_Dimension](https://user-images.githubusercontent.com/1139698/61859951-b64c7880-aefb-11e9-9f5a-f6e4b1929c23.png) + +It calculates the width and height of a component using `useContainerDimension` hook of the graph package. + +### `` + +### Add Tooltips + + From 3f6ba0cd358bb8f5a69639813ed6368337ba9d50 Mon Sep 17 00:00:00 2001 From: garfieldduck Date: Thu, 25 Jul 2019 18:38:38 +0800 Subject: [PATCH 29/33] Add docs about the usage of SvgWithAxisFrame --- docs/api-reference/Overview.mdx | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/api-reference/Overview.mdx b/docs/api-reference/Overview.mdx index 1c9fd91..7236b8d 100644 --- a/docs/api-reference/Overview.mdx +++ b/docs/api-reference/Overview.mdx @@ -16,8 +16,8 @@ The `useChartDimensions` lets you get the `outerDimension` and `graphDimension`. By attaching the ref to the outer chart (`chartRef`), the ref to the title box (`titleRef`), the legend (`legendRef`), and the inner margin of the chart, it calcultates the following dimensions: -- Full dimension of the chart (`outerDimension`: see the blue text on the graph below) -- Inner dimension of the chart (`graphDimension`: see the orange text on the graph below) +- Full dimension of the chart: `outerDimension` (see the blue text on the graph below) +- Inner dimension of the chart: `graphDimension` (see the orange text on the graph below) ```js const { @@ -33,7 +33,22 @@ it calcultates the following dimensions: It calculates the width and height of a component using `useContainerDimension` hook of the graph package. -### `` + +### SvgWithAxisFrame + +`` is the component that draws the following basics components of a chart for you: + +- The title and description of the chart (``) +- The SVG to draw the chart along with the X and Y axes (the axes are drawn using ``). +- The transformed inner SVG element container `` to draw the main SVG components (yello area on the chart above). + +Pass the following props to draw a chart: + +- `children`: the main SVG components like the bars, lines, or dots to be drawn on the transformed inner SVG element container `` (yello area on the chart above). +- `svgOverlay`: the non-SVG components like the tooltip and legend. + +You may refer to the source code of `` or `` as an example. + ### Add Tooltips From f21fd4a9f2ec8994d96596d3eab27a2214317b68 Mon Sep 17 00:00:00 2001 From: garfieldduck Date: Fri, 26 Jul 2019 15:09:25 +0800 Subject: [PATCH 30/33] Add docs for the hovering tooltips --- docs/api-reference/Overview.mdx | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/api-reference/Overview.mdx b/docs/api-reference/Overview.mdx index 7236b8d..c32a546 100644 --- a/docs/api-reference/Overview.mdx +++ b/docs/api-reference/Overview.mdx @@ -9,7 +9,7 @@ menu: API Reference You can utilize the `@ichef/transcharts-graph` and `@ichef/transcharts-chart` packages to create charts with X and Y axis. -### Calculate Chart Dimensions +## Calculate Chart Dimensions The `useChartDimensions` lets you get the `outerDimension` and `graphDimension`. @@ -34,7 +34,7 @@ it calcultates the following dimensions: It calculates the width and height of a component using `useContainerDimension` hook of the graph package. -### SvgWithAxisFrame +## SvgWithAxisFrame `` is the component that draws the following basics components of a chart for you: @@ -50,6 +50,21 @@ Pass the following props to draw a chart: You may refer to the source code of `` or `` as an example. -### Add Tooltips +## Add Tooltips/Hovering Effects +![Tooltip_transchart](https://user-images.githubusercontent.com/1139698/61932715-aa71bc80-afb6-11e9-9606-4e71acecfff7.png) +To detect the mouse and touch events, you can add a `` component +in which you can put `hoverDetectionComponents` which are an array of transparent svg elements to be attached with the mouse and touch events. + +`` detects the X and Y position and the index of the `hoverDetectionComponents` array are being hovered, +and sets such information using the passed in prop `setHoveredPosAndIndex(...)`. +It also calls the passed in `clearHovering()` to clear the hovering index when users hover/touch out of the regions of `hoverDetectionComponents`. + +The `setHoveredPosAndIndex(...)` and `clearHovering()` can be gotten from `useHoverState` hook +which also lets you get `hovering` (whether users are hovering/touching the `hoverDetectionComponents`) +and `hoveredPoint` (the index of `hoverDetectionComponents` and the X and Y position). + +You can use `hovering` and `hoverDetectionComponents` to create visual hovering effect or add tooltips. + +To draw the tooltip, there is `` to help you create it with ease. From 12976115a6119ed9ddd139e4fb797a95f1d4eade Mon Sep 17 00:00:00 2001 From: garfieldduck Date: Fri, 26 Jul 2019 18:18:53 +0800 Subject: [PATCH 31/33] Add basic docs for the data encodings --- docs/chart-settings/DataEncodings.mdx | 92 +++++++++++++++++++++++++++ docs/sampleData/drinkData.js | 11 ++++ 2 files changed, 103 insertions(+) create mode 100644 docs/chart-settings/DataEncodings.mdx create mode 100644 docs/sampleData/drinkData.js diff --git a/docs/chart-settings/DataEncodings.mdx b/docs/chart-settings/DataEncodings.mdx new file mode 100644 index 0000000..87cd706 --- /dev/null +++ b/docs/chart-settings/DataEncodings.mdx @@ -0,0 +1,92 @@ +--- +name: Data Encodings +route: /chart_settings/data_encodings +menu: Chart Settings +--- + +import { Playground, Props } from 'docz' +import { BarChart } from '@ichef/transcharts-chart' +import drinkData from '../sampleData/drinkData'; + +# Data Encodings + +The data encodings let you select data field to be drawn in an axis or as a dimension of color. + +```ts +Encoding { + field: string; + type: 'nominal' | 'ordinal' | 'quantitative' | 'temporal'; +} +``` + +You must specify the data type of the encoding, +and different charts will select the d3 scale functions best-suited for drawing the chart. + +### Data Types + +- **Nominal**: The categorical data, such as names or blood types. +- **Ordinal**: Data with meaningful sorted order, such as the degree of satisfaction. +- **Quantitative**: Numerical data. +- **Temporal**: Datetime data. + + +## How different charts deal with data encodings? + +### Bar Chart + +`` takes the types of the encodings of X and Y axis to determine whether it is a vertical or a horizontal chart. +If the encoding data type of X-axis is not `quantitative`, it will draw the default vertical bar chart; +otherwise, it draws the horizontal bar chart. + +The data assigned to the axis with `quantitative` will be converted to the `linear` scale of d3, +while the other will be converted as the `band` scale. + +#### Vertical Chart + +```js + +``` + +
+ +
+ + +#### Horizontal Chart + +```js + +``` + +
+ +
+ + + + +## useCartesianEncodings diff --git a/docs/sampleData/drinkData.js b/docs/sampleData/drinkData.js new file mode 100644 index 0000000..954fd32 --- /dev/null +++ b/docs/sampleData/drinkData.js @@ -0,0 +1,11 @@ +const drinkData = [ + { restaurant: 'Cafe', type: 'Beer', sales: 100 }, + { restaurant: 'Tea Time', type: 'Black Tea', sales: 300 }, + { restaurant: 'Bistro', type: 'Black Tea', sales: 500 }, + { restaurant: 'Cafe', type: 'Wine', sales: 100 }, + { restaurant: 'Tea Time', type: 'Wine', sales: 200 }, + { restaurant: 'Tea Time', type: 'Beer', sales: 150 }, + { restaurant: 'Bistro', type: 'Wine', sales: 700 }, +]; + +export default drinkData; From 33587c7f0709724dfe6a69240c155916d648256e Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Mon, 29 Jul 2019 15:50:55 +0800 Subject: [PATCH 32/33] Complete the doc for useCartesianEncodings --- docs/api-reference/Overview.mdx | 215 +++++++++++++++++- docs/chart-settings/DataEncodings.mdx | 3 - .../chart/src/hooks/useCartesianEncodings.ts | 2 +- 3 files changed, 213 insertions(+), 7 deletions(-) diff --git a/docs/api-reference/Overview.mdx b/docs/api-reference/Overview.mdx index c32a546..abf78b8 100644 --- a/docs/api-reference/Overview.mdx +++ b/docs/api-reference/Overview.mdx @@ -40,11 +40,11 @@ It calculates the width and height of a component using `useContainerDimension` - The title and description of the chart (``) - The SVG to draw the chart along with the X and Y axes (the axes are drawn using ``). -- The transformed inner SVG element container `` to draw the main SVG components (yello area on the chart above). +- The transformed inner SVG element container `` to draw the main SVG components (yellow area on the chart above). Pass the following props to draw a chart: -- `children`: the main SVG components like the bars, lines, or dots to be drawn on the transformed inner SVG element container `` (yello area on the chart above). +- `children`: the main SVG components like the bars, lines, or dots to be drawn on the transformed inner SVG element container `` (yellow area on the chart above). - `svgOverlay`: the non-SVG components like the tooltip and legend. You may refer to the source code of `` or `` as an example. @@ -65,6 +65,215 @@ The `setHoveredPosAndIndex(...)` and `clearHovering()` can be gotten from `useHo which also lets you get `hovering` (whether users are hovering/touching the `hoverDetectionComponents`) and `hoveredPoint` (the index of `hoverDetectionComponents` and the X and Y position). -You can use `hovering` and `hoverDetectionComponents` to create visual hovering effect or add tooltips. +You can use `hovering` and `hoverDetectionComponents` to create the visual hovering effect or add tooltips. To draw the tooltip, there is `` to help you create it with ease. + + +### useCartesianEncodings + +`useCartesianEncodings` is a hook of the `chart` library aimed to isolating the data transformation and computing +shared across most charts with the X and Y axes. + +It groups the data based on the provided color encoding and computes the d3 scale functions +for the X and Y axis along with the color scale. + +It is currently used by `` and ``. + +#### Input of useCartesianEncodings + +- **graphDimension**: Width and height of the inner graph (does not contain axes, legend, etc...) +- **theme**: Theme of the chart, used for the generation of the color scale +- **data**: Array of rows of data +- **x**: Field and data type of x-axis +- **y**: Field and data type of y-axis +- **color?**: Fields and definitions for colors; pass in `undefined` if you are intended to draw single color. +- **drawFromXAxis**: Whether the graph is drawn from the x-axis, i.e., vertical graph. In a transposed (horizontal) graph, you have to set it as false, in order to get the right `axisProjectedValues` value. + +#### Output of useCartesianEncodings + +- **dataGroups**: Array of data grouped by fields of colors. + +Example: + +```json +[ + [ + { + "restaurant": "Cafe", + "type": "Beer", + "sales": 100 + }, + { + "restaurant": "Tea Time", + "type": "Beer", + "sales": 150 + } + ], + [ + { + "restaurant": "Tea Time", + "type": "Black Tea", + "sales": 300 + }, + { + "restaurant": "Bistro", + "type": "Black Tea", + "sales": 500 + } + ], + ... +] +``` + + +- **axisProjectedValues**: The y-values in the `dataGroups` grouped by projected x values. It is useful for displaying the tooltips. + +Example: + +```json +[ + { + "basePos": 0, + "baseStrVal": "Bistro", + "projectedVals": [ + { + "groupIdx": 1, + "projectedStrVal": 500, + "projectedPos": 281.0807291666667, + "color": "#ff7f0e" + }, + { + "groupIdx": 2, + "projectedStrVal": 700, + "projectedPos": 393.51302083333337, + "color": "#2ca02c" + } + ] + }, + { + "basePos": 88.27586206896552, + "baseStrVal": "Tea Time", + "projectedVals": [ + { + "groupIdx": 0, + "projectedStrVal": 150, + "projectedPos": 84.32421875, + "color": "#1f77b4" + }, + { + "groupIdx": 1, + "projectedStrVal": 300, + "projectedPos": 168.6484375, + "color": "#ff7f0e" + }, + { + "groupIdx": 2, + "projectedStrVal": 200, + "projectedPos": 112.43229166666666, + "color": "#2ca02c" + } + ] + }, + ... +] +``` + + +- **scalesConfig**: d3 scale functions and other related configurations computed for various encodings. +It contains keys of objects of the encodings of `x` and `y` axes as well as the `color` (if exists). + + The inner keys of the encodings: + - **field**: Name of the selected column from the data. + - **type**: The data encoding type passed in from the props of the chart (`'nominal' | 'ordinal' | 'quantitative' | 'temporal'`). + - **scaleType**: Converted d3 scaled name which is determined by the chart component. + - **domain**: Calculated domain based on the `scaleType`. + - **range**: Range related to the visual space. + + +Exmaple: + +```json +{ + "x": { + "field": "restaurant", + "range": [ + 0, + 674.734375 + ], + "domain": [ + "Cafe", + "Tea Time", + "Bistro", + "Cafe", + "Tea Time", + "Tea Time", + "Bistro" + ], + "scaleType": "band", + "type": "nominal" + }, + "y": { + "field": "sales", + "range": [ + 256, + 0 + ], + "domain": [ + 0, + 1200 + ], + "scaleType": "linear", + "type": "quantitative" + }, + "color": { + "domain": [ + "Beer", + "Black Tea", + "Black Tea", + "Wine", + "Wine", + "Beer", + "Wine" + ], + "type": "nominal", + "field": "type", + "range": [ + "#1f77b4", + "#ff7f0e", + "#2ca02c", + "#d62728", + "#9467bd", + "#8c564b", + "#e377c2", + "#7f7f7f", + "#bcbd22", + "#17becf" + ], + "scaleType": "ordinal" + } +} +``` + +- **rowValSelectors**: Contains functions to select values from a data row. + + The inner keys of the x and y encodings contains the following: + - **getFormattedStringVal**: Funtion helps you get the string to be displayed on tooltips from a data row. + - **getOriginalVal**: Funtion helps you get the original data from a data row. + - **getScaledVal**: Given a record of data, it returns the mapped value (computed by d3 scale function) of the specified field. + + +Exmaple: + +```json +{ + "color": { + "getString": function, + }, + "x": { + "getFormattedStringVal": function, + "getOriginalVal": function, + "getScaledVal" function + } +} +``` diff --git a/docs/chart-settings/DataEncodings.mdx b/docs/chart-settings/DataEncodings.mdx index 87cd706..7b54820 100644 --- a/docs/chart-settings/DataEncodings.mdx +++ b/docs/chart-settings/DataEncodings.mdx @@ -87,6 +87,3 @@ while the other will be converted as the `band` scale.
- - -## useCartesianEncodings diff --git a/packages/chart/src/hooks/useCartesianEncodings.ts b/packages/chart/src/hooks/useCartesianEncodings.ts index 3fdb176..76cc66a 100644 --- a/packages/chart/src/hooks/useCartesianEncodings.ts +++ b/packages/chart/src/hooks/useCartesianEncodings.ts @@ -61,7 +61,7 @@ export const useCartesianEncodings = ( /** Width and height of the inner graph (does not contain axes, legend, etc...) */ graphDimension: GraphDimension, - /** Theme of the chart */ + /** Theme of the chart, used for the generation of the color scale */ theme: Theme, /** Array of rows of data */ From 54642ae557810349c5715ac22bc59e9ff1d90b34 Mon Sep 17 00:00:00 2001 From: HsunPei Wang Date: Mon, 29 Jul 2019 16:24:51 +0800 Subject: [PATCH 33/33] Add CHANGELOG for the docs --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc95df2..8293160 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `` to display the chart title and chart descriptions. (#39) - Support drawing the horizontal bar chart. (#40) - Add a gray auxiliary line at zero-value. (#40) +- Add docs for building custom charts. (#41) # Changed - Clean compiled files before the docz server started. (#34)