From cbc8cd17faf8d0578bf2afb3aaf95b0b9f90e7a9 Mon Sep 17 00:00:00 2001 From: MiniPear Date: Mon, 12 Jun 2023 11:27:38 +0800 Subject: [PATCH 1/2] feat(static-mark): add axisX and axisY --- .../snapshots/static/alphabetIntervalAxis.png | Bin 0 -> 17891 bytes .../snapshots/static/mockAxisX.png | Bin 0 -> 1646 bytes .../snapshots/static/mockAxisXY.png | Bin 0 -> 8091 bytes .../snapshots/static/mockAxisXYPolar.png | Bin 0 -> 24715 bytes .../snapshots/static/mockAxisY.png | Bin 0 -> 3088 bytes .../plots/static/alphabet-interval-axis.ts | 46 +++++++++++++++ __tests__/plots/static/index.ts | 5 ++ __tests__/plots/static/mock-axisX.ts | 17 ++++++ __tests__/plots/static/mock-axisXY-polar.ts | 37 ++++++++++++ __tests__/plots/static/mock-axisXY.ts | 33 +++++++++++ __tests__/plots/static/mock-axisY.ts | 24 ++++++++ __tests__/unit/api/chart.spec.ts | 6 ++ __tests__/unit/api/mark.spec.ts | 33 +++++++++++ src/api/mark/index.ts | 6 ++ src/api/mark/mark.ts | 32 ++++++++++- src/api/mark/types.ts | 9 ++- src/component/axis.ts | 25 ++++---- src/composition/mark.ts | 11 ++-- src/runtime/component.ts | 19 +++--- src/runtime/plot.ts | 54 +++++++++++++----- src/runtime/scale.ts | 51 ++++++++++++++++- src/runtime/types/options.ts | 2 +- 22 files changed, 368 insertions(+), 42 deletions(-) create mode 100644 __tests__/integration/snapshots/static/alphabetIntervalAxis.png create mode 100644 __tests__/integration/snapshots/static/mockAxisX.png create mode 100644 __tests__/integration/snapshots/static/mockAxisXY.png create mode 100644 __tests__/integration/snapshots/static/mockAxisXYPolar.png create mode 100644 __tests__/integration/snapshots/static/mockAxisY.png create mode 100644 __tests__/plots/static/alphabet-interval-axis.ts create mode 100644 __tests__/plots/static/mock-axisX.ts create mode 100644 __tests__/plots/static/mock-axisXY-polar.ts create mode 100644 __tests__/plots/static/mock-axisXY.ts create mode 100644 __tests__/plots/static/mock-axisY.ts diff --git a/__tests__/integration/snapshots/static/alphabetIntervalAxis.png b/__tests__/integration/snapshots/static/alphabetIntervalAxis.png new file mode 100644 index 0000000000000000000000000000000000000000..ff4325fb57e81015652d7ffef485e34f629a8362 GIT binary patch literal 17891 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 literal 0 HcmV?d00001 diff --git a/__tests__/integration/snapshots/static/mockAxisXY.png b/__tests__/integration/snapshots/static/mockAxisXY.png new file mode 100644 index 0000000000000000000000000000000000000000..77228545b34a2b9165fb380e1c6e368e19581997 GIT binary patch literal 8091 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 b+fDZAF$mszJ^AN})jhj?cL{eM{_Ot%8!hRN literal 0 HcmV?d00001 diff --git a/__tests__/integration/snapshots/static/mockAxisXYPolar.png b/__tests__/integration/snapshots/static/mockAxisXYPolar.png new file mode 100644 index 0000000000000000000000000000000000000000..2f8c673d354a57278369bfa051cb66545fad2cb5 GIT binary patch literal 24715 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 i && i !== ticks.length - 1, + }, + { + type: 'axisY', + title: 'AxisY', + style: { + labelFontSize: 14, + gridLineWidth: 10, + gridStroke: 'red', + }, + }, + ], + }; +} diff --git a/__tests__/plots/static/mock-axisXY.ts b/__tests__/plots/static/mock-axisXY.ts new file mode 100644 index 0000000000..90c4fda50c --- /dev/null +++ b/__tests__/plots/static/mock-axisXY.ts @@ -0,0 +1,33 @@ +import { G2Spec } from '../../../src'; + +export function mockAxisXY(): G2Spec { + return { + type: 'view', + padding: 'auto', + scale: { + x: { + type: 'linear', + domain: [5, 10], + range: [0, 1], + }, + y: { + type: 'linear', + domain: [5, 10], + range: [0, 1], + }, + }, + children: [ + { type: 'axisX', title: 'AxisX' }, + { + type: 'axisY', + title: 'AxisY', + tickCount: 10, + style: { + labelFontSize: 14, + gridLineWidth: 10, + gridStroke: 'red', + }, + }, + ], + }; +} diff --git a/__tests__/plots/static/mock-axisY.ts b/__tests__/plots/static/mock-axisY.ts new file mode 100644 index 0000000000..af473119d8 --- /dev/null +++ b/__tests__/plots/static/mock-axisY.ts @@ -0,0 +1,24 @@ +import { G2Spec } from '../../../src'; + +export function mockAxisY(): G2Spec { + return { + type: 'axisY', + padding: 10, + paddingLeft: 'auto', + width: 100, + scale: { + y: { + type: 'linear', + domain: [5, 10], + range: [0, 1], + }, + }, + tickCount: 10, + title: 'axisX', + style: { + labelFontSize: 14, + gridLineWidth: 10, + gridStroke: 'red', + }, + }; +} diff --git a/__tests__/unit/api/chart.spec.ts b/__tests__/unit/api/chart.spec.ts index 9a22da52a9..6dd65d533a 100644 --- a/__tests__/unit/api/chart.spec.ts +++ b/__tests__/unit/api/chart.spec.ts @@ -40,6 +40,8 @@ import { Gauge, Density, Heatmap, + AxisX, + AxisY, } from '../../../src/api/mark/mark'; const TEST_OPTIONS = { @@ -166,6 +168,8 @@ describe('Chart', () => { expect(chart.gauge()).toBeInstanceOf(Gauge); expect(chart.density()).toBeInstanceOf(Density); expect(chart.heatmap()).toBeInstanceOf(Heatmap); + expect(chart.axisX()).toBeInstanceOf(AxisX); + expect(chart.axisY()).toBeInstanceOf(AxisY); expect(chart.options().children).toEqual([ { type: 'interval' }, { type: 'rect' }, @@ -196,6 +200,8 @@ describe('Chart', () => { { type: 'gauge' }, { type: 'density' }, { type: 'heatmap' }, + { type: 'axisX' }, + { type: 'axisY' }, ]); }); diff --git a/__tests__/unit/api/mark.spec.ts b/__tests__/unit/api/mark.spec.ts index a2bc94905c..905d593008 100644 --- a/__tests__/unit/api/mark.spec.ts +++ b/__tests__/unit/api/mark.spec.ts @@ -26,6 +26,8 @@ import { Tree, WordCloud, Gauge, + AxisX, + AxisY, } from '../../../src/api/mark/mark'; type Mark = @@ -161,6 +163,25 @@ function getLayoutOptions() { }; } +function setAxisOptions(node: AxisX | AxisY): AxisX | AxisY { + return node + .scale('x', { type: 'linear' }) + .transform({ type: 'hide' }) + .style('gridFill', 'red') + .state('active', { gridFill: 'red' }) + .attr('labelFormatter', '~s'); +} + +function getAxisOptions() { + return { + scale: { x: { type: 'linear' } }, + transform: [{ type: 'hide' }], + style: { gridFill: 'red' }, + state: { active: { gridFill: 'red' } }, + labelFormatter: '~s', + }; +} + describe('mark.get[Instance]()', () => { let view; let interval; @@ -376,4 +397,16 @@ describe('mark.[node]()', () => { expect(node.type).toBe('gauge'); expect(setCompositeOptions(node).value).toEqual(getOptions()); }); + + it('AxisX() should specify options by API', () => { + const node = new AxisX(); + expect(node.type).toBe('axisX'); + expect(setAxisOptions(node).value).toEqual(getAxisOptions()); + }); + + it('AxisY() should specify options by API', () => { + const node = new AxisY(); + expect(node.type).toBe('axisY'); + expect(setAxisOptions(node).value).toEqual(getAxisOptions()); + }); }); diff --git a/src/api/mark/index.ts b/src/api/mark/index.ts index bc5fdfe936..f2882dfc99 100644 --- a/src/api/mark/index.ts +++ b/src/api/mark/index.ts @@ -31,6 +31,8 @@ import { WordCloud, Composite, Gauge, + AxisX, + AxisY, } from './mark'; export interface Mark { @@ -65,6 +67,8 @@ export interface Mark { tree(): Tree; wordCloud(): WordCloud; gauge(): Gauge; + axisX(): AxisX; + axisY(): AxisY; } export { MarkNode } from './base'; @@ -101,4 +105,6 @@ export const mark = { tree: Tree, wordCloud: WordCloud, gauge: Gauge, + axisX: AxisX, + axisY: AxisY, }; diff --git a/src/api/mark/mark.ts b/src/api/mark/mark.ts index 957cad9dcb..fed47fc853 100644 --- a/src/api/mark/mark.ts +++ b/src/api/mark/mark.ts @@ -30,11 +30,12 @@ import { WordCloudMark, CompositeMark, GaugeMark, + AxisComponent, } from '../../spec'; import { NodePropertyDescriptor, defineProps } from '../props'; import { Concrete } from '../types'; import { MarkNode } from './base'; -import { API } from './types'; +import { API, StaticAPI } from './types'; export interface Interval extends API, Interval> { type: 'interval'; @@ -159,6 +160,14 @@ export interface Composite extends API, Composite> { type: 'interval'; } +export interface AxisX extends StaticAPI, AxisX> { + type: 'axisX'; +} + +export interface AxisY extends StaticAPI, AxisY> { + type: 'axisY'; +} + export const props: NodePropertyDescriptor[] = [ { name: 'encode', type: 'object' }, { name: 'scale', type: 'object' }, @@ -177,6 +186,13 @@ export const props: NodePropertyDescriptor[] = [ { name: 'tooltip', type: 'mix' }, ]; +export const axisProps: NodePropertyDescriptor[] = [ + { name: 'scale', type: 'object' }, + { name: 'transform', type: 'array' }, + { name: 'style', type: 'object' }, + { name: 'state', type: 'object' }, +]; + @defineProps(props) export class Composite extends MarkNode { constructor() { @@ -393,3 +409,17 @@ export class Gauge extends MarkNode { super({}, 'gauge'); } } + +@defineProps(axisProps) +export class AxisX extends MarkNode { + constructor() { + super({}, 'axisX'); + } +} + +@defineProps(axisProps) +export class AxisY extends MarkNode { + constructor() { + super({}, 'axisY'); + } +} diff --git a/src/api/mark/types.ts b/src/api/mark/types.ts index 398cf532f3..9ff0a6b749 100644 --- a/src/api/mark/types.ts +++ b/src/api/mark/types.ts @@ -1,5 +1,5 @@ import { ValueAttribute, ObjectAttribute, ArrayAttribute } from '../types'; -import { Mark as MarkProps } from '../../spec'; +import { Mark as MarkProps, AxisComponent } from '../../spec'; export type API = { data: ValueAttribute; @@ -19,3 +19,10 @@ export type API = { layout: ValueAttribute; tooltip: ValueAttribute; }; + +export type StaticAPI = { + scale: ObjectAttribute; + transform: ArrayAttribute; + style: ObjectAttribute; + state: ObjectAttribute; +}; diff --git a/src/component/axis.ts b/src/component/axis.ts index c20df46198..057e220e8f 100644 --- a/src/component/axis.ts +++ b/src/component/axis.ts @@ -2,7 +2,7 @@ import { Coordinate } from '@antv/coord'; import type { DisplayObject } from '@antv/g'; import { Axis as AxisComponent } from '@antv/gui'; import { Linear as LinearScale } from '@antv/scale'; -import { deepMix, has } from '@antv/util'; +import { deepMix, has, omit } from '@antv/util'; import { extent } from 'd3-array'; import { format } from 'd3-format'; import { @@ -402,18 +402,21 @@ const ArcAxisComponent: GCC = (options) => { ); const { axis: axisTheme } = theme; + const finalStyle = adaptor( + deepMix({}, axisTheme, defaultStyle, { + type: 'arc', + data, + titleText: titleContent(title), + grid, + ...rest, + ...important, + }), + ); return new AxisComponent({ - style: adaptor( - deepMix({}, axisTheme, defaultStyle, { - type: 'arc', - data, - titleText: titleContent(title), - grid, - ...rest, - ...important, - }), - ), + // @fixme transform is not valid for arcAxis. + // @ts-ignore + style: omit(finalStyle, ['transform']), }); }; }; diff --git a/src/composition/mark.ts b/src/composition/mark.ts index e3e4c4a8e3..064df51451 100644 --- a/src/composition/mark.ts +++ b/src/composition/mark.ts @@ -4,7 +4,9 @@ import { Mark as MarkComposition } from '../spec'; export type MarkOptions = Omit; // @todo Move this to runtime. -export const Mark: CC = () => { +export const Mark: CC = ({ + static: isStatic = false, +}: any = {}) => { return (options) => { const { width, @@ -33,11 +35,11 @@ export const Mark: CC = () => { y, key, frame, - title, labelTransform, parentKey, clip, viewStyle, + title, ...mark } = options; @@ -64,7 +66,6 @@ export const Mark: CC = () => { component, interaction, frame, - title, labelTransform, margin, marginLeft, @@ -74,7 +75,9 @@ export const Mark: CC = () => { parentKey, clip, style: viewStyle, - marks: [{ ...mark, key: `${key}-0`, data }], + // For axis component, title is the axis title. + ...(!isStatic && { title }), + marks: [{ ...mark, key: `${key}-0`, data, ...(isStatic && { title }) }], }, ]; }; diff --git a/src/runtime/component.ts b/src/runtime/component.ts index 43909eefe6..9c99358209 100644 --- a/src/runtime/component.ts +++ b/src/runtime/component.ts @@ -61,24 +61,25 @@ export function inferComponent( partialOptions: G2View, library: G2Library, ): G2GuideComponentOptions[] { - const { - component: partialComponents = [], - coordinates = [], - title, - theme, - } = partialOptions; + const { coordinates = [], title } = partialOptions; const [, createGuideComponent] = useLibrary< G2GuideComponentOptions, GCC, GuideComponent >('component', library); - const displayedScales = scales.filter(({ guide, name }) => { + const displayedScales = scales.filter(({ guide }) => { if (guide === null) return false; return true; }); + + const components = []; + + // Sliders and scrollbar component. const sliders = inferScrollableComponents(partialOptions, scales, library); - const components = [...partialComponents, ...sliders]; + components.push(...sliders); + + // Title components. if (title) { const { props } = createGuideComponent('title'); const { defaultPosition, defaultOrientation, defaultOrder, defaultSize } = @@ -94,6 +95,7 @@ export function inferComponent( }); } + // Axis and legends. const inferredComponents = inferComponentsType(displayedScales, coordinates); inferredComponents.forEach(([type, relativeScales]) => { @@ -446,7 +448,6 @@ function inferScrollableComponents( .filter((d) => d.slider || d.scrollbar) .flatMap((scale) => { const { slider, scrollbar, name: channelName } = scale; - return [ normalized('slider', channelName, scale, slider), normalized('scrollbar', channelName, scale, scrollbar), diff --git a/src/runtime/plot.ts b/src/runtime/plot.ts index 2be7cf55a0..38a3bd5571 100644 --- a/src/runtime/plot.ts +++ b/src/runtime/plot.ts @@ -33,6 +33,7 @@ import { documentOf, useLibrary } from './library'; import { initializeMark } from './mark'; import { applyScale, + collectScales, inferScale, syncFacetsScales, useRelationScale, @@ -100,6 +101,12 @@ export async function plot( .map((d) => /mark\.(.*)/.exec(d)?.[1]) .filter(defined), ); + const staticMarks = new Set( + Object.keys(library) + .map((d) => /component\.(.*)/.exec(d)?.[1]) + .filter(defined), + ); + const typeOf = (node: G2ViewTree) => { const { type } = node; if (typeof type === 'function') { @@ -108,14 +115,24 @@ export async function plot( const { composite = true } = props; if (composite) return 'mark'; } - return typeof type === 'string' && marks.has(type) ? 'mark' : type; + if (typeof type !== 'string') return type; + if (marks.has(type) || staticMarks.has(type)) return 'mark'; + return type; }; + const isMark = (node: G2ViewTree) => typeOf(node) === 'mark'; const isStandardView = (node: G2ViewTree) => typeOf(node) === 'standardView'; + const isStaticMark = (node: G2ViewTree) => { + const { type } = node; + if (typeof type !== 'string') return false; + if (staticMarks.has(type)) return true; + return false; + }; + const transform = (node: G2ViewTree) => { if (isStandardView(node)) return [node]; const type = typeOf(node); - const composition = useComposition({ type }); + const composition = useComposition({ type, static: isStaticMark(node) }); return composition(node); }; @@ -431,8 +448,14 @@ async function transformMarks( library, ); + const staticMarks = new Set( + Object.keys(library) + .map((d) => /component\.(.*)/.exec(d)?.[1]) + .filter(defined), + ); const { marks } = options; const flattenMarks = []; + const components = []; const discovered = [...marks]; const { width, height } = computeRoughPlotSize(options); const context = { options, width, height }; @@ -443,18 +466,23 @@ async function transformMarks( // Apply data transform to get data. const mark = (await applyTransform(node, library)) as G2Mark; const { type = error('G2Mark type is required.'), key } = mark; - const { props = {} } = createMark(type); - const { composite = true } = props; - if (!composite) flattenMarks.push(mark); + + // For components. + if (staticMarks.has(type as string)) components.push(mark); else { - // Convert composite mark to marks. - const marks = await useMark(mark, context); - const M = Array.isArray(marks) ? marks : [marks]; - discovered.unshift(...M.map((d, i) => ({ ...d, key: `${key}-${i}` }))); + const { props = {} } = createMark(type); + const { composite = true } = props; + if (!composite) flattenMarks.push(mark); + else { + // Convert composite mark to marks. + const marks = await useMark(mark, context); + const M = Array.isArray(marks) ? marks : [marks]; + discovered.unshift(...M.map((d, i) => ({ ...d, key: `${key}-${i}` }))); + } } } - return { ...options, marks: flattenMarks }; + return { ...options, marks: flattenMarks, components }; } async function initializeMarks( @@ -563,10 +591,7 @@ function initializeState( // Infer components and compute layout. const states = Array.from(markState.values()); - const scales = Array.from( - new Set(states.flatMap((d) => d.channels.map((d) => d.scale))), - ); - + const scales = collectScales(states, options); const components = inferComponent( inferComponentScales(Array.from(scales), states, markState), options, @@ -742,6 +767,7 @@ async function plotView( const componentAnimateOptions = animationExtent ? { duration: animationExtent[1] } : false; + // Render components. // @todo renderComponent return ctor and options. const componentsTransitions = selection diff --git a/src/runtime/scale.ts b/src/runtime/scale.ts index ebba65442b..791b8b4b7c 100644 --- a/src/runtime/scale.ts +++ b/src/runtime/scale.ts @@ -1,7 +1,7 @@ import { Linear, createInterpolateValue } from '@antv/scale'; import { extent } from 'd3-array'; import * as d3ScaleChromatic from 'd3-scale-chromatic'; -import { max, upperFirst } from '@antv/util'; +import { deepMix, omit, upperFirst } from '@antv/util'; import { firstOf, lastOf, unique } from '../utils/array'; import { defined, identity, isStrictObject } from '../utils/helper'; import { Primitive, G2Theme, G2MarkState, ChannelGroups } from './types/common'; @@ -11,6 +11,7 @@ import { G2ScaleOptions, G2PaletteOptions, G2Mark, + G2View, } from './types/options'; import { ScaleComponent, @@ -64,6 +65,46 @@ export function applyScale( return scaledValue; } +export function collectScales(states: G2MarkState[], options: G2View) { + const { components = [] } = options; + + const NONE_STATIC_KEYS = ['scale', 'encode', 'axis', 'legend']; + + // From normal marks. + const scales = Array.from( + new Set(states.flatMap((d) => d.channels.map((d) => d.scale))), + ); + + // From static marks. + const nameScale = new Map(scales.map((scale) => [scale.name, scale])); + for (const component of components) { + const channels = inferChannelsForComponent(component); + for (const channel of channels) { + const scale = nameScale.get(channel); + const staticScale = component.scale?.[channel] || {}; + const { independent = false } = staticScale; + + if (scale && !independent) { + // Merged with exist scales if is not independent. + const { guide } = scale; + const guide1 = typeof guide === 'boolean' ? {} : guide; + scale.guide = deepMix({}, guide1, component); + Object.assign(scale, staticScale); + } else { + // Append new scales without exit scales or independent. + const options1 = { + ...staticScale, + expectedDomain: staticScale.domain, + name: channel, + guide: omit(component, NONE_STATIC_KEYS), + }; + scales.push(options1); + } + } + } + return scales; +} + export function useRelation( relations: [any, any][], ): [(scale: Scale) => Scale, (scale: Scale) => Scale] { @@ -135,6 +176,14 @@ export function syncFacetsScales(states: Map[]): void { syncFacetsScaleByChannel(scales, 'y'); } +function inferChannelsForComponent(component) { + const { channels = [], type } = component; + if (channels.length !== 0) return channels; + if (type === 'axisX') return ['x']; + if (type === 'axisY') return ['y']; + return []; +} + function syncFacetsScaleByChannel( scales: G2ScaleOptions[], channel: 'x' | 'y', diff --git a/src/runtime/types/options.ts b/src/runtime/types/options.ts index a0f4c7ff76..17c5d3b20f 100644 --- a/src/runtime/types/options.ts +++ b/src/runtime/types/options.ts @@ -86,7 +86,7 @@ export type G2View = { title?: G2TitleOptions; coordinates?: G2CoordinateOptions[]; coordinate?: Record; - component?: G2GuideComponentOptions[]; + components?: G2GuideComponentOptions[]; interaction?: Record; marks?: G2Mark[]; frame?: boolean; From c1bd41a3d3b025c03b11f3b322455e5dc922385e Mon Sep 17 00:00:00 2001 From: MiniPear Date: Mon, 12 Jun 2023 13:05:17 +0800 Subject: [PATCH 2/2] docs(mark): add axisX and axisY --- .../component/axis/demo/axis-multi.ts | 31 +++++++++++++++++ .../component/axis/demo/axis-polar.ts | 34 +++++++++++++++++++ site/examples/component/axis/demo/axis-x.ts | 20 +++++++++++ site/examples/component/axis/demo/axis-xy.ts | 31 +++++++++++++++++ site/examples/component/axis/demo/meta.json | 32 +++++++++++++++++ 5 files changed, 148 insertions(+) create mode 100644 site/examples/component/axis/demo/axis-multi.ts create mode 100644 site/examples/component/axis/demo/axis-polar.ts create mode 100644 site/examples/component/axis/demo/axis-x.ts create mode 100644 site/examples/component/axis/demo/axis-xy.ts diff --git a/site/examples/component/axis/demo/axis-multi.ts b/site/examples/component/axis/demo/axis-multi.ts new file mode 100644 index 0000000000..a769fc96c1 --- /dev/null +++ b/site/examples/component/axis/demo/axis-multi.ts @@ -0,0 +1,31 @@ +import { Chart } from '@antv/g2'; + +const chart = new Chart({ + container: 'container', + theme: 'classic', + autoFit: true, +}); + +chart + .interval() + .data({ + type: 'fetch', + value: + 'https://gw.alipayobjects.com/os/bmw-prod/fb9db6b7-23a5-4c23-bbef-c54a55fee580.csv', + }) + .encode('x', 'letter') + .encode('y', 'frequency') + .axis('y', { labelFormatter: '.0%' }); + +chart + .axisY() + .attr('position', 'right') + .scale('y', { + type: 'linear', + independent: true, + domain: [0, 10], + range: [1, 0], + }) + .style('grid', false); + +chart.render(); diff --git a/site/examples/component/axis/demo/axis-polar.ts b/site/examples/component/axis/demo/axis-polar.ts new file mode 100644 index 0000000000..cedf16e056 --- /dev/null +++ b/site/examples/component/axis/demo/axis-polar.ts @@ -0,0 +1,34 @@ +import { Chart } from '@antv/g2'; + +const chart = new Chart({ + container: 'container', + theme: 'classic', + padding: 'auto', +}); + +chart + .coordinate({ type: 'polar' }) + .scale('x', { + type: 'linear', + domain: [5, 10], + range: [0, 1], + }) + .scale('y', { + type: 'linear', + domain: [5, 10], + range: [1, 0], + }); + +chart + .axisX() + .attr('title', 'AxisX') + .attr('tickFilter', (_, i, ticks) => i && i !== ticks.length - 1); + +chart + .axisY() + .attr('title', 'AxisY') + .style('labelFontSize', 14) + .style('gridLineWidth', 10) + .style('gridStroke', 'red'); + +chart.render(); diff --git a/site/examples/component/axis/demo/axis-x.ts b/site/examples/component/axis/demo/axis-x.ts new file mode 100644 index 0000000000..6de872ca76 --- /dev/null +++ b/site/examples/component/axis/demo/axis-x.ts @@ -0,0 +1,20 @@ +import { Chart } from '@antv/g2'; + +const chart = new Chart({ + container: 'container', + theme: 'classic', + padding: 'auto', + height: 80, +}); + +chart + .axisX() + .scale('x', { + type: 'linear', + domain: [5, 10], + range: [0, 1], + }) + .attr('tickCount', 10) + .attr('title', 'AxisX'); + +chart.render(); diff --git a/site/examples/component/axis/demo/axis-xy.ts b/site/examples/component/axis/demo/axis-xy.ts new file mode 100644 index 0000000000..cc9759786b --- /dev/null +++ b/site/examples/component/axis/demo/axis-xy.ts @@ -0,0 +1,31 @@ +import { Chart } from '@antv/g2'; + +const chart = new Chart({ + container: 'container', + theme: 'classic', + padding: 'auto', +}); + +chart + .scale('x', { + type: 'linear', + domain: [5, 10], + range: [0, 1], + }) + .scale('y', { + type: 'linear', + domain: [5, 10], + range: [0, 1], + }); + +chart.axisX().attr('title', 'AxisX'); + +chart + .axisY() + .attr('title', 'AxisY') + .attr('tickCount', 10) + .style('labelFontSize', 14) + .style('gridLineWidth', 10) + .style('gridStroke', 'red'); + +chart.render(); diff --git a/site/examples/component/axis/demo/meta.json b/site/examples/component/axis/demo/meta.json index eea3e0b52e..2cbd92e4d2 100644 --- a/site/examples/component/axis/demo/meta.json +++ b/site/examples/component/axis/demo/meta.json @@ -4,6 +4,38 @@ "en": "Category" }, "demos": [ + { + "filename": "axis-x.ts", + "title": { + "zh": "x 方向坐标轴", + "en": "AxisX" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*kcACSYV4r-cAAAAAAAAAAAAADmJ7AQ/original" + }, + { + "filename": "axis-xy.ts", + "title": { + "zh": "x 和 y 方向坐标轴", + "en": "AxisX and AxisY" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*CtPmSYjKyKAAAAAAAAAAAAAADmJ7AQ/original" + }, + { + "filename": "axis-polar.ts", + "title": { + "zh": "极坐标下坐标轴", + "en": "Axis Polar" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*5KPvQoiA0XMAAAAAAAAAAAAADmJ7AQ/original" + }, + { + "filename": "axis-multi.ts", + "title": { + "zh": "多坐标轴", + "en": "Multi Axis" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*aQv5Q7WKx3UAAAAAAAAAAAAADmJ7AQ/original" + }, { "filename": "axis.ts", "title": {