From d09c1740b95d19bdb21ad25d457cfe488327539d Mon Sep 17 00:00:00 2001 From: Runtus <893119806@qq.com> Date: Tue, 7 Nov 2023 22:02:59 +0800 Subject: [PATCH 1/4] docs: finish use-in-framework --- site/docs/manual/extra-topics/color.en.md | 176 ++++++++ .../manual/extra-topics/customization.en.md | 345 +++++++++++++++ .../extra-topics/experimental-spec-api.en.md | 243 +++++++++++ .../extra-topics/migration-from-g2v4.en.md | 409 ++++++++++++++++++ .../extra-topics/use-in-framework.en.md | 214 ++++++++- 5 files changed, 1386 insertions(+), 1 deletion(-) diff --git a/site/docs/manual/extra-topics/color.en.md b/site/docs/manual/extra-topics/color.en.md index 7d32bad19f..059f7bc6ea 100644 --- a/site/docs/manual/extra-topics/color.en.md +++ b/site/docs/manual/extra-topics/color.en.md @@ -2,5 +2,181 @@ title: Color order: 9 --- +Color plays a very important role in visualization. It helps us better understand data, highlight key information, enhance visual appeal and improve readability. Color often serves the following purposes in visualization: + +* **Distinguish data categories**: Distinguish between different data categories. For example, in a bar chart, we can use different colors to represent different product categories to make it easier to identify and compare them. +* **Represents the amount of data**: Indicates the amount of data. For example, in a heat map, we can use shades of color to represent the size of the data, with darker colors representing larger values ​​and lighter colors representing smaller values. +* **Highlight key information**: Highlight key information. For example, in a line chart, we can use bright colors to represent data points of interest to make them easier to find. +* **Enhance visual appeal**: Make the visualization more attractive. Using bright colors and interesting color schemes can make visualizations more lively and interesting. +* **Improve readability**: Improve the readability of visualizations. For example, on a map, we can use different colors to represent different geographical areas to make them easier to identify and understand. + +Set data-independent colors via`mark.style(fill, color)`or`mark.style(stroke, color)`That's it. If you want to set data-driven colors, you can use the following methods to set the colors: + +* coding:`mark.encode` +* style:`mark.style` + +## coding + +pass`mark.encode`The most common way is to set data-driven colors, and configure the final visual display through a color scale. + +* `scale.identity`: Identity mapping +* `scale.range`: Custom color palette +* `scale.palette`: Built-in color palette +* `scale.relations`: Custom mapping relationship + +### Identity + +When the color scale is set to Identity, the color channel data will be drawn into the final visualization as visual data, but the scale will not be generated. + +```js | ob +(() => { + const chart = new G2.Chart(); + + chart + .interval() + .data([ + { genre: 'Sports', sold: 275, color: 'red' }, + { genre: 'Strategy', sold: 115, color: 'blue' }, + { genre: 'Action', sold: 120, color: 'green' }, + { genre: 'Shooter', sold: 350, color: 'red' }, + { genre: 'Other', sold: 150, color: 'black' }, + ]) + .encode('x', 'genre') + .encode('y', 'sold') + .encode('color', 'color') + .scale('color', { type: 'identity' }); // 设置该比例尺为恒等映射 + + chart.render(); + + return chart.getContainer(); +})(); +``` + +### Range + +```js | ob +(() => { + const chart = new G2.Chart(); + + 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') + .encode('color', 'letter') + .axis('y', { labelFormatter: '.0%' }) + .scale('color', { + type: 'ordinal', + range: ['#7593ed', '#95e3b0', '#6c7893', '#e7c450', '#7460eb'], + }); + + chart.render(); + + return chart.getContainer(); +})(); +``` + +### Palette + +In G2, you can set`scale.palette`Go to Specify Swatches. This palette can be discrete: + +```js | ob +(() => { + const chart = new G2.Chart(); + + 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') + .encode('color', 'letter') + .axis('y', { labelFormatter: '.0%' }) + .scale('color', { palette: 'tableau10' }); + + chart.render(); + + return chart.getContainer(); +})(); +``` + +It can also be continuous: + +```js | ob +(() => { + const chart = new G2.Chart({ + + height: 320, + }); + + chart + .cell() + .data({ + type: 'fetch', + value: 'https://assets.antv.antgroup.com/g2/seattle-weather.json', + }) + .transform({ type: 'group', color: 'max' }) + .encode('x', (d) => new Date(d.date).getUTCDate()) + .encode('y', (d) => new Date(d.date).getUTCMonth()) + .encode('color', 'temp_max') + .scale('color', { palette: 'rainbow' }); + + chart.render(); + + return chart.getContainer(); +})(); +``` + +You can refer to this for the current built-in color palette.[palette documentation](/spec/palette)。 + +### Relations + +able to pass`scale.relations`To specify a series of mapping rules, this priority will be higher than the default mapping method from domain to range. For example, for the color channel, this configuration is useful if you want specific values ​​to be mapped to specific colors, or to handle outliers. + +```js +chart.interval().scale('color', { + relations: [ + ['dog', 'red'], // dog is identically mapped to red + [(d) => d === undefined, 'grey'], // If the value is undefined, then it is gray + ], +}); +``` + +## style + +pass`mark.style`To set the color, the color set here is smaller than`encode.color`has a higher priority and no legend will be generated. + +```js | ob +(() => { + const chart = new G2.Chart(); + + 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') + .style('fill', (datum, index, data) => { + const { frequency } = datum; + if (frequency > 0.1) return '#3376cd'; + if (frequency > 0.05) return '#f4bb51'; + return '#b43a29'; + }); + + chart.render(); + + return chart.getContainer(); +})(); +``` diff --git a/site/docs/manual/extra-topics/customization.en.md b/site/docs/manual/extra-topics/customization.en.md index ca6c5a1763..118f57d208 100644 --- a/site/docs/manual/extra-topics/customization.en.md +++ b/site/docs/manual/extra-topics/customization.en.md @@ -2,5 +2,350 @@ title: Customization order: 8 --- +G2 is highly extensible: all visual components can be customized. Here are some common ways to customize visual components. + +## Custom shape (Shape) + +Each mark can have a custom shape, and the shape determines the final display form of the mark. There are three main steps to customizing a shape: + +* Define shape components. +* Register shape. +* Use shapes. + +First let's take a look at how to define shape components. A shape component is a function that accepts the style of the shape*style*and context*context*, returns a drawing function*render*. in*style*is passed`mark.style`the specified processed options,*context*Contains[@antv/g](https://g.antv.antgroup.com/)Create graphics*document*。 + +return*render*The function accepts the control points of the graph*P*, mapping value*value*and default value*defaults*, returns the graph of @antv/g. in*P*is an array composed of a series of canvas coordinates,*value*is passed`mark.encode`The processed value,*defaults*is in topic`theme.mark.shape`the specified value. The definition of a shape component is roughly as follows: + +```js +function ShapeTriangle(style, context) { + const { document } = context; + return (P, value, defaults) => { + return document.createElement('rect', { + //... + }); + }; +} +``` + +The next step is to register the shape by calling`G2.register('shape.${mark}.${shape}', Shape)`to complete the grouping of the shape. in*mark*is the name of the marker,*shape*is the name of the shape,*Shape*Is a defined shape component. For example, register a triangle shape for the Interval tag: + +```js +import { register } from '@antv/g2'; + +register('shape.interval.triangle', ShapeTriangle); +``` + +The last step is to use the shape, which can be passed`mark.encode`specified, or via`mark.style`designation. + +```js +({ + type: 'interval', + encode: { shape: 'triangle' }, + // 或者 + style: { shape: 'triangle' }, +}); +``` + +```js +// API +chart.interval().encode('shape', 'triangle'); + +// 或者 +chart.interval().style('shape', 'triangle'); +``` + +Below is a complete example showing how to customize the shape. + +```js | ob +(() => { + //Define graphic components + function ShapeTriangle(style, context) { + const { document } = context; + return (P, value, defaults) => { + const { color: defaultColor } = defaults; + const [p0, p1, p2, p3] = P; + const pm = [(p0[0] + p1[0]) / 2, p0[1]]; + const { color = defaultColor } = value; + return document.createElement('polygon', { + style: { + ...style, + fill: color, + points: [pm, p2, p3], + }, + }); + }; + } + + //Register the triangle + G2.register('shape.interval.triangle', ShapeTriangle); + + //Initialize chart + const chart = new G2.Chart(); + + chart + .interval() + .data([ + { genre: 'Sports', sold: 275 }, + { genre: 'Strategy', sold: 115 }, + { genre: 'Action', sold: 120 }, + { genre: 'Shooter', sold: 350 }, + { genre: 'Other', sold: 150 }, + ]) + .encode('x', 'genre') + .encode('y', 'sold') + .encode('color', 'genre') + .encode('shape', 'triangle'); // Use this shape + + chart.render(); + + return chart.getContainer(); +})(); +``` + +## Custom tips (Tooltip) + +Sometimes the built-in Tooltip cannot meet the needs. In this case, you can use`mark.interaction.tooltip.render`or`view.interaction.tooltip.render`of*render*Function to render custom prompts. + +Should*render*Function accepts event object*event*and prompt data*tooltipData*, returns a string or DOM object. in*event*yes[@antv/g](https://g.antv.antgroup.com/)the mouse object thrown,*tooltipData*is passed`mark.tooltip`Declared title and items data. If the return value is a string, it will be used as the innerHTML of the tooltip container, otherwise the return value will be mounted. A hint's render function might look like this: + +```js +function render(event, tooltipData) { + const { title, items } = tooltipData; + return `
`; +} +``` + +Here's a simple example: + +```js | ob +(() => { + const chart = new G2.Chart(); + + chart + .interval() + .data({ + type: 'fetch', + value: + 'https://gw.alipayobjects.com/os/bmw-prod/fb9db6b7-23a5-4c23-bbef-c54a55fee580.csv', + }) + .transform([{ type: 'sortX', by: 'y', reverse: true }]) + .encode('x', 'letter') + .encode('y', 'frequency') + .interaction('tooltip', { + // render 回调方法返回一个innerHTML 或者 DOM + render: (event, { title, items }) => `
+

${title}

+ +
`, + }); + + chart.render(); + + return chart.getContainer(); +})(); +``` + +## Custom legend (Legend) + +The built-in legend of G2 is drawn with canvas or svg. If you want to render the legend with HTML, you can customize the legend as follows: + +* Turn off the built-in legend and render the chart. +* Wait for chart rendering to complete and render the HTML legend based on the scale data. +* Add interactions (if needed). + +The first is to turn off the built-in legend while rendering the chart. + +```js +chart.options({ legend: false }); +``` + +Then wait for the chart rendering to complete and call`legendColor`Render HTML legend: + +```js +chart.render().then(legendColor); +``` + +exist`legendColor`Here we first need to draw the legend. In the following example, after drawing the legend, it is added to the front of the canvas: + +```js +function legendColor(chart) { + const node = chart.getContainer(); + const legend = document.createElement('div'); + node.insertBefore(legend, node.childNodes[0]); + + // ... +} +``` + +After drawing the legend, we need to draw the legend items. This data is obtained from the scale of the corresponding channel:`chart.getScale().color`, and obtain the corresponding name and value through the domain and range of scale. + +```js +function legendColor(chart) { + // ... + const scale = chart.getScale().color; + const { domain } = scale.getOptions(); + const items = domain.map(() => {}); + // ... +} +``` + +After drawing the legend items, we should pass each legend item`item.onclick`Add interaction, collect the currently selected value, and add Filter transformation to the chart declaration based on this value, and finally re-render the chart. The final complete implementation is as follows: + +```js | ob +(() => { + // 添加图例 + function legendColor(chart) { + // 创建 Legend 并且挂在图例 + const node = chart.getContainer(); + const legend = document.createElement('div'); + legend.style.display = 'flex'; + node.insertBefore(legend, node.childNodes[0]); + + // 创建并挂载 Items + const { color: scale } = chart.getScale(); + const { domain } = scale.getOptions(); + const items = domain.map((value) => { + const item = document.createElement('div'); + const color = scale.map(value); + item.style.marginLeft = '1em'; + item.innerHTML = ` + + ${value} + `; + return item; + }); + items.forEach((d) => legend.append(d)); + + // 监听事件 + const selectedValues = [...domain]; + const options = chart.options(); + for (let i = 0; i < items.length; i++) { + const item = items[i]; + const value = domain[i]; + item.style.cursor = 'pointer'; + item.onclick = () => { + const index = selectedValues.indexOf(value); + if (index !== -1) { + selectedValues.splice(index, 1); + item.style.opacity = 0.5; + } else { + selectedValues.push(value); + item.style.opacity = 1; + } + changeColor(selectedValues); + }; + } + + // 重新渲染视图 + function changeColor(value) { + const { transform = [] } = options; + const newTransform = [{ type: 'filter', color: { value } }, ...transform]; + chart.options({ + ...options, + transform: newTransform, // 指定新的 transform + scale: { color: { domain } }, + }); + chart.render(); // 重新渲染图表 + } + } + + // 绘制图表 + const container = document.createElement('div'); + + const chart = new G2.Chart({ + + container, + }); + + chart.options({ + type: 'interval', + data: [ + { genre: 'Sports', sold: 275 }, + { genre: 'Strategy', sold: 115 }, + { genre: 'Action', sold: 120 }, + { genre: 'Shooter', sold: 350 }, + { genre: 'Other', sold: 150 }, + ], + encode: { x: 'genre', y: 'sold', color: 'genre' }, + legend: false, + }); + + chart.render().then(legendColor); + + return chart.getContainer(); +})(); +``` + +## Custom drag axis (Slider) + +If you don’t want to use G2’s default coordinate axes, you can follow the following steps to customize the drag axis: + +* Render the slider after rendering. +* Listen to slider events. + +The key first step is to pass`chart.getCoordinate`The obtained coordinate object determines the slider's position and length. The key to the second step is to pass`chart.getScale`Get scale Invert the selected range, finally get the selected data range, and then update the domain of scale. + +```js | ob +(() => { + function sliderX(chart) { + //Create and mount range + const container = chart.getContainer(); + const range = document.createElement('input'); + container.append(range); + + //Set the width and other properties of the range based on coordinate + const coordinate = chart.getCoordinate(); + const { paddingLeft, width } = coordinate.getOptions(); + range.type = 'range'; + range.min = 0; + range.max = width; + range.value = width; + range.style.display = 'block'; + range.style.width = width + 'px'; + range.style.marginLeft = paddingLeft + 'px'; + + // Listen to the change event and obtain the filtered domain through scale + // Update domain and render + const scale = chart.getScaleByChannel('x'); + const options = chart.options(); + range.onchange = (event) => { + const value = event.target.value; + const range = [0, value / width]; + const domain = range.map((d) => scale.invert(d)); + chart.options({ + ...options, + scale: { x: { domain } }, + }); + chart.render(); + }; + } + + // Render chart + const container = document.createElement('div'); + const chart = new G2.Chart({ container }); + + chart.options({ + type: 'line', + data: { + type: 'fetch', + value: + 'https://gw.alipayobjects.com/os/bmw-prod/551d80c6-a6be-4f3c-a82a-abd739e12977.csv', + }, + encode: { x: 'date', y: 'close' }, + }); + + chart.render().then(sliderX); + + return chart.getContainer(); +})(); +``` \ No newline at end of file diff --git a/site/docs/manual/extra-topics/experimental-spec-api.en.md b/site/docs/manual/extra-topics/experimental-spec-api.en.md index f021f4437f..d14aacda3e 100644 --- a/site/docs/manual/extra-topics/experimental-spec-api.en.md +++ b/site/docs/manual/extra-topics/experimental-spec-api.en.md @@ -2,5 +2,248 @@ title: Experimental Spec API order: 1 --- +--- +title: Spec 和 API +order: 2 +--- + +G2 5.0, like version 4.0, provides a set of imperative Functional APIs to declare charts. For example, the simplest bar chart is declared as follows. + +```js | ob +(() => { + //Initialize chart instance + const chart = new G2.Chart(); + + // Declare visualization + chart + .interval() // Create an Interval tag + .data([ + //Bind data + { genre: 'Sports', sold: 275 }, + { genre: 'Strategy', sold: 115 }, + { genre: 'Action', sold: 120 }, + { genre: 'Shooter', sold: 350 }, + { genre: 'Other', sold: 150 }, + ]) + .encode('x', 'genre') // Encode x channel + .encode('y', 'sold'); // Encode y channel + + // Render visualization + chart.render(); + + return chart.getContainer(); +})(); +``` + +In addition to this functional style, G2 5.0 also provides a new API: Spec API. The API declares visualizations through a JavaScript object. + +## start using + +Currently we pass`chart.options(spec)`To declare the visualization, the following example can achieve the same effect as above. + +```js | ob +(() => { + //Initialize chart instance + const chart = new G2.Chart(); + + // Declare visualization + chart.options({ + type: 'interval', // Create an Interval tag + data: [ + //Bind data + { genre: 'Sports', sold: 275 }, + { genre: 'Strategy', sold: 115 }, + { genre: 'Action', sold: 120 }, + { genre: 'Shooter', sold: 350 }, + { genre: 'Other', sold: 150 }, + ], + encode: { + x: 'genre', // encode x channel + y: 'sold', // encode y channel + }, + }); + + // Render visualization + chart.render(); + + return chart.getContainer(); +})(); +``` + +## Compare + +It can be found that the initialization of the chart instance and the final rendering of the two APIs are the same, but the way of declaring visualization in the middle is different. Next, let's take a brief look at the similarities and differences between the two. + +Functional API is implemented based on Spec API: Simply put, each Chart instance has an option. Functional API generates these options through a series of methods, while Spec API directly sets these options. No matter which form of API it is, G2 will directly render the current options in the end, so the ability of the two to declare visualization is completely equivalent. + +In most scenarios, the two are more of a stylistic choice, but there are some differences: + +* **Ease of use**: Spec API is superior in terms of ease of use and is more friendly to beginners or users who do not need to understand G2 in depth. JavaScript objects, which are more structural expressions, are naturally easier to understand than function expressions. And it is often a whole, making it easier to copy, paste and "adjust parameters". +* **flexibility**: Functional API has the advantage of flexibility and is more suitable for functional,[D3](https://github.com/d3/d3)More familiar users. But its flexibility is not reflected in the ability to draw more complex visualizations, but in the fact that the form of declarative visualizations will be more flexible. One advantage is that it is easier to organize concerns. + +For example, if you want the bars in the bar graph above to appear in sequence, you need to add an encode and transform. The first Spec API below looks a little clearer than the second Functional API, but the latter can put animation-related properties (the same focus) together, while the former cannot. + +```js +chart.options({ + type: 'interval', + data, + encode: { + x: 'genre', + y: 'sold', + enterDuration: 1000, + }, + transform: [{ type: 'stackEnter' }], +}); +``` + +```js +chart + .interval() + .data(data) + .encode('x', 'genre') + .encode('y', 'sold') + // These two are related to animation and can be put together. + .encode('enterDuration', 1000) + .transform({ type: 'stackEnter' }); +``` + +## Application scenarios + +Of course, Spec API is not only simple, it also has more application scenarios: + +* **Smart visualization**: Recommendations and error corrections can be made based on Spec. +* **Upper layer encapsulation**: Converting the Options corresponding to Spec will be easier than calling them directly. +* **Low code construction**: You can directly generate a configuration panel based on Spec and build a BI tool. +* **Chart operations**: Spec can also be regarded as a data structure. If it is a data structure, it can perform a series of operations, such as adding pictures, etc. +* **Server-side rendering**: You can directly render the Options corresponding to Spec into images. +* ...... + +Later, G2 will make a series of tools based on this new set of APIs for everyone to use. If you have ideas, you can discuss and participate here.[Build together](https://github.com/antvis/G2/discussions)。 + +## Case + +The following uses some cases to show you how to use Spec API. + +### pie chart + +```js | ob +(() => { + //Initialize chart instance + const chart = new G2.Chart(); + + // Declare visualization + chart.options({ + type: 'interval', + height: 640, + data: { + type: 'fetch', + value: + 'https://gw.alipayobjects.com/os/bmw-prod/79fd9317-d2af-4bc4-90fa-9d07357398fd.csv', + }, + transform: [{ type: 'stackY' }], + coordinate: { type: 'theta' }, + scale: { + color: { palette: 'spectral', offset: (t) => t * 0.8 + 0.1 }, + }, + legend: false, + encode: { y: 'value', color: 'name' }, + style: { stroke: 'white' }, + labels: [ + { + text: 'name', + radius: 0.8, + style: { fontSize: 10, fontWeight: 'bold' }, + }, + { + text: (d, i, data) => (i < data.length - 3 ? d.value : ''), + radius: 0.8, + style: { fontSize: 9, dy: 12 }, + }, + ], + animate: { enter: { type: 'waveIn', duration: 1000 } }, + }); + + // Render visualization + chart.render(); + + return chart.getContainer(); +})(); +``` + +### space composite + +```js | ob +(() => { + // 初始化图表实例 + const chart = new G2.Chart(); + + // 声明可视化 + chart.options({ + type: 'spaceFlex', + width: 900, + data: { + type: 'fetch', + value: 'https://assets.antv.antgroup.com/g2/seattle-weather.json', + }, + direction: 'col', + ratio: [1, 2], + children: [ + { + type: 'interval', + paddingBottom: 0, + paddingRight: 300, + transform: [{ type: 'groupX', y: 'max' }], + axis: { x: false }, + encode: { + x: (d) => new Date(d.date).getUTCDate(), + y: 'temp_max', + color: 'steelblue', + }, + }, + { + type: 'spaceFlex', + ratio: [2, 1], + children: [ + { + type: 'cell', + paddingRight: 0, + paddingBottom: 50, + transform: [{ type: 'group', color: 'max' }], + encode: { + x: (d) => new Date(d.date).getUTCDate(), + y: (d) => new Date(d.date).getUTCMonth(), + color: 'temp_max', + }, + style: { inset: 0.5 }, + axis: { + x: { title: 'Date' }, + y: { title: 'Month' }, + }, + scale: { color: { palette: 'gnBu' } }, + legend: false, + }, + { + type: 'interval', + paddingBottom: 50, + transform: [{ type: 'groupX', y: 'max' }], + coordinate: { transform: [{ type: 'transpose' }] }, + axis: { x: false }, + encode: { + x: (d) => new Date(d.date).getUTCMonth(), + y: 'temp_max', + color: 'steelblue', + }, + }, + ], + }, + ], + }); + + // 渲染可视化 + chart.render(); + + return chart.getContainer(); +})(); +``` diff --git a/site/docs/manual/extra-topics/migration-from-g2v4.en.md b/site/docs/manual/extra-topics/migration-from-g2v4.en.md index 8353404659..31ca1abf0b 100644 --- a/site/docs/manual/extra-topics/migration-from-g2v4.en.md +++ b/site/docs/manual/extra-topics/migration-from-g2v4.en.md @@ -3,4 +3,413 @@ title: G2 5.0 Migration Guide order: 3 --- +> The G2 stack team will continue to maintain the v4 version and release patch version fixes for bugs, but will no longer receive new Feature Requests until the end of 2023. The original v4 official website has been migrated to。 + +This article is intended to help those already familiar with G24.0 understand the differences between versions 4.0 and 5.0. Readers can choose to read the new document directly instead of reading this article from beginning to end. This article will highlight the changes in the APIs corresponding to various concepts between the two versions. + +## Dimension + +4.0's padding and appendPadding are an array, 5.0 splits it and modifies appendPadding to margin. + +```js +// 4.0 +const chart = new Chart({ + width: 600, + height: 400, + padding: [10, 20, 30, 40], + appendPadding: [10, 20, 30, 40], +}); + +// 5.0 +const chart = new Chart({ + width: 600, + height: 400, + paddingLeft: 10, + paddingTop: 20, + paddingRight: 30, + paddingBottom: 40, + marginLeft: 10, + marginTop: 20, + marginRight: 30, + marginBottom: 40, +}); +``` + +## Data + +In 4.0, each view is bound to a piece of data, and the markers (front geometry elements) in the view share a piece of data. In 5.0 all markers in each view can have independent data, and scales are synchronized by default. + +```js +// 4.0 +chart.data(data); +chart.line(); +chart.point(); + +// 5.0 +chart.line().data(data1); +chart.line().data(data2); +``` + +## Encode + +5.0 has the following differences from 4.0 in encoding methods: + +### Declaration method + +4.0 uses top-level APIs such as geometry.position and geometry.color to encode channels. 5.0 uses mark.encode to encode and does not support the \* syntax. + +```js +// 4.0 +chart.interval().position('name*value').color('genre'); + +// 5.0 +chart + .interval() + .encode('x', 'name') + .encode('y', 'value') + .encode('color', 'genre'); +``` + +### callback parameters + +The callback coded in 4.0 will provide the corresponding fields from the original data. Callbacks coded in 5.0 only provide raw data. + +```js +// 4.0 +chart.interval().color('name*value', (name, value) => {}); + +// 5.0 +chart + .interval() + // Need to deconstruct by yourself + .encode('color', ({ name, value }) => {}); +``` + +### callback return value + +4.0 callback returns visual data. 5.0 callbacks return abstract data by default. + +```js +// 4.0 +chart.interval().color('name', (name) => (name > 10 ? 'red' : 'yellow')); + +// 5.0 +chart + .interval() + .encode('color', (d) => (d.name > 10 ? 'high' : 'low')) // 抽象数据 + .scale('color', { range: ['red', 'yellow'] }); // 指定值域 + +// 5.0 +chart + .interval() + .encode('color', (d) => (d.name > 10 ? 'red' : 'yellow')) + .scale('color', { type: 'identity' }); +``` + +### color range + +4.0 declares the color range via the second parameter of geometry.color, 5.0 specifies via scale.color. + +```js +// 4.0 +chart.interval().color('name', ['red', 'blue']); +chart.interval().color('name', '#fff-#000'); + +// 5.0 +chart + .interval() + .encode('color', 'name') // 离散 + .scale('color', { range: ['red', 'blue'] }); + +chart + .interval() + .encode('color', 'name') //连续 + .scale('color', { range: '#fff-#000' }); +``` + +## Timing channel + +4.0 will try to parse the time string, but 5.0 will not try to parse it and needs to be explicitly converted into a Date object. + +```js +const data = [ + { year: '2020-10-01', value: 1 }, + { year: '2022-10-01', value: 2 }, + { year: '2023-10-01', value: 3 }, +]; + +// 4.0 +chart.line().position('year*value'); + +// 5.0 +chart + .line() + .encode('x', (d) => new Date(d.year)) + .encode('y', 'value'); +``` + +## Style + +Style callbacks in 4.0 apply to the entire object. Acts on every attribute in 5.0. + +```js +// 4.0 +chart + .interval() + .style('a*b', (a, b) => + a + b > 10 + ? { stroke: 'red', strokeWidth: 10 } + : { stroke: 'black', strokeWidth: 5 }, + ); + +// 5.0 +chart + .interval() + .style('stroke', ({ a, b }) => (a + b > 10 ? 'red' : 'black')) + .style('strokeWidth', ({ a, b }) => (a + b > 10 ? 10 : 5)); +``` + +## Scale + +5.0 has the following series of differences from 4.0 when using a scale: + +### binding object + +The 4.0 scale is bound to the field, and the 5.0 scale is bound to the channel. + +```js +const data = [ + { genre: 'Sports', sold: 275 }, + { genre: 'Strategy', sold: 115 }, + { genre: 'Action', sold: 120 }, + { genre: 'Shooter', sold: 350 }, + { genre: 'Other', sold: 150 }, +]; + +// 4.0 +chart.data(data); +chart.scale('genre', {}); +chart.interval().color('genre'); + +// 5.0 +chart + .interval() + .data(data) + .encode('color', 'genre') + // 设置 color 通道比例尺 + .scale('color', {}); +``` + +### Attributes + +Some properties of the scale have changed as follows: + +* Domain: values ​​-> domain +* Minimum value of domain: min -> domainMin +* The maximum value of the domain: max -> domainMax + +```js +// 4.0 +chart.scale('genre', { values: ['a', 'b', 'c'] }); + +// 5.0 +chart.scale('color', { domain: ['a', 'b', 'c'] }); +``` + +### discrete scale + +The discrete scales of 4.0 are cat and timeCat. In 5.0, cat becomes band, point and ordinal scales, and timeCat is removed. + +```js +// 4.0 +chart.scale('genre', { type: 'cat' }); + +// 5.0 +chart + .interval() + .encode('x', 'name') + .encode('color', 'name') + //The x channel of interval defaults to band scale + .scale('x', { type: 'band', range: [0.1, 0.9] }) + .scale('color', { type: 'ordinal', range: ['red', 'blue'] }); + +chart + .point() + .encode('x', 'name') + // point scale + .scale('point', {}); +``` + +## Coordinate system + +The 4.0 coordinate system attribute is in cfg, and the coordinate system transformation is specified through actions; the 5.0 coordinate system attribute is tiled, and the coordinate system transformation is declared through transform. + +```js +// 4.0 +chart.coordinate({ + type: 'polar', + cfg: { + radius: 0.85, + }, + actions: [['transpose']], +}); + +// 5.0 +chart.coordinate({ + type: 'polar', + outerRadius: 0.85, + transform: [{ type: 'transpose' }], +}); +``` + +## Label + +4.0 Each element can only declare one tag, and 5.0 each element can declare multiple tags. + +```js +// 4.0 +chart.interval().label('field', (d) => + d > 10 + ? 'red' + : 'blue' + ? { + style: { color: 'red', stroke: 'red' }, + } + : { + style: { color: 'black', stroke: 'black' }, + }, +); + +// 5.0 +chart + .interval() + .label({ + text: 'field', // 指定内容 + style: { + color: d > 10 ? 'red' : 'black', // 设置属性 + stroke: d > 10 ? 'red' : 'black', + }, + }) + .label({ text: (d) => d.value }); +``` + +## Tooltip + +In 4.0, you can customize the prompt information through tooltip.containerTpl, and in 5.0, you can customize the prompt information through the render function. + +```js +// 4.0 +chart.tooltip({ containerTpl: `
` }); + +// 5.0 +chart.interaction('tooltip', { + render: () => `
`, +}); +``` + +## Animation + +There is the appear animation in 4.0, and 5.0 merges it into the enter animation. + +```js +// 4.0 +chart.interval().animate({ + appear: { + animation: 'fade-in', + easing: 'easeQuadIn', + delay: 100, + duration: 600, + }, +}); + +// 5.0 +chart.interval().animate('enter', { + type: 'fadeIn', + easing: 'easeQuadIn', + delay: 100, + duration: 600, +}); +``` + +## Interaction + +4.0 Pass`chart.removeInteraction(name)`Removed interaction, 5.0 passed`chart.interaction(name, false)`Remove interaction. + +```js +// 4.0 +chart.removeInteraction('tooltip'); + +// 5.0 +chart.interaction('tooltip', false); +``` + +## Annotation + +In 4.0, the elements in the diagram are divided into geometry elements (Geometry) and annotations (Annotation). In 5.0, both are annotations (Marks). + +### Declaration method + +In 4.0, annotations are declared through the annotation namespace, and the declaration method in 5.0 is consistent with tags. + +```js +// 4.0 +chart.annotation().line({}); + +// 5.0 +chart.lineX(); +``` + +### Mark specific values + +In 4.0, start and end are used to mark specific values, and in 5.0, transform is used to mark specific values. + +```js +// 4.0 +chart.annotation().line({ + start: ['min', 'mean'], + end: ['max', 'mean'], +}); + +// 5.0 +chart + .lineX() + .encode('y', 'value') + //Select the smallest value of the y channel + .transform({ type: 'selectY', y: 'mean' }); +``` + +## Facet + +4.0 facets are declared through the facet namespace, and 5.0 facets are consistent with tags. + +```js +// 4.0 +chart.facet('rect', { + fields: ['cut', 'clarity'], + eachView(view) { + view + .point() + .position('carat*price') + .color('cut') + .shape('circle') + .style({ fillOpacity: 0.3, stroke: null }) + .size(3); + }, +}); + +// 5.0 +chart + .facetRect() + .encode('x', 'cut') + .encode('y', 'clarity') + .point() + .encode('x', 'carat') + .encode('y', 'price') + .encode('color', 'cut') + .encode('shape', 'point') + .encode('size', 3) + .style('fillOpacity', 0.3) + .style('stroke', null); +``` + diff --git a/site/docs/manual/extra-topics/use-in-framework.en.md b/site/docs/manual/extra-topics/use-in-framework.en.md index 0c34cfbe55..fbe042615d 100644 --- a/site/docs/manual/extra-topics/use-in-framework.en.md +++ b/site/docs/manual/extra-topics/use-in-framework.en.md @@ -3,4 +3,216 @@ title: Use In Framework order: 1 --- - +Here is a brief introduction to how to use G2 in some front-end frameworks. We will use different frameworks to achieve the following update effects of bar chart. + +framework + +Achieving this effect mainly relies on the following two functions. + +```js +// Render bar chart +function renderBarChart(container) { + const chart = new Chart({ + container, + }); + + // Prepare data + const data = [ + { genre: 'Sports', sold: 275 }, + { genre: 'Strategy', sold: 115 }, + { genre: 'Action', sold: 120 }, + { genre: 'Shooter', sold: 350 }, + { genre: 'Other', sold: 150 }, + ]; + + // Declare visualization + chart + .interval() // Create an Interval tag + .data(data) // Bind data + .encode('x', 'genre') // Encode x channel + .encode('y', 'sold') // Encode y channel + .encode('key', 'genre') // Specify key + .animate('update', { duration: 300 }); // Specify the time to update the animation + + // Render visualization + chart.render(); + + return chart; +} +``` + +```js +//Update bar chart data +function updateBarChart(chart) { + // Get Interval Mark + const interval = chart.getNodesByType('interval')[0]; + + // Simulate and update Interval data + const newData = interval.data().map((d) => ({ + ...d, + sold: Math.random() * 400 + 100, + })); + + interval.data(newData); + + // Re-render + chart.render(); +} +``` + +It should be noted here that in the framework, it is not recommended to use the `new Chart({ container: 'id' })` to specify the container. Instead, use the HTML element directly as the container: `new Chart({ container: HTMLContainer })`. This is to prevent problems where different components have the same id and cannot be rendered predictably. + +Next, let's take a look at how to use these two functions in the framework. + +## Vue + +In Vue, the first step is to import the defined `G2Demo` component. + +```html + + + + +``` + +### Options API + +If using [Vue2](https://github.com/vuejs/vue) and [Vue3](https://github.com/vuejs/core) options API, you can define the `G2Demo` component as follows, complete code reference [here](https://codesandbox.io/s/use-g2-5-with-vue-options-api-qzdrr6?file=/src/components/G2Demo.vue)。 + +```html + + + + +``` + +### Composition API + +If you use the composition API of Vue3, the implementation is as follows, complete code reference [here](https://codesandbox.io/s/use-g2-5-with-vue-composition-api-hdwpc6?file=/src/components/G2Demo.vue)。 + +```html + + + +``` + +## React + +In [React](https://github.com/facebook/react), the first step is also to import the defined `G2Demo` component. + +```js +import './styles.css'; +import G2Demo from './components/G2Demo'; + +export default function App() { + return ( +
+ +
+ ); +} +``` + +Next, define the `G2Demo` component, complete code reference [here](https://codesandbox.io/s/use-g2-5-with-react-u05qle?file=/src/components/G2Demo.js)。 + +```js +import { Chart } from '@antv/g2'; +import { useEffect, useRef } from 'react'; + +export default function G2Demo() { + const container = useRef(null); + const chart = useRef(null); + + useEffect(() => { + if (!chart.current) { + chart.current = renderBarChart(container.current); + } + }, []); + + function renderBarChart(container) { + // as above + } + + function updateBarChart(chart) { + // as above + } + + return ( +
+
+ +
+ ); +} +``` + + From 3cc14636b1e5a8b29204bff27d078fe0adf51f1e Mon Sep 17 00:00:00 2001 From: Runtus <893119806@qq.com> Date: Wed, 8 Nov 2023 00:46:03 +0800 Subject: [PATCH 2/4] docs: translate color.zh.md over --- site/docs/manual/extra-topics/color.en.md | 34 +++++++++++------------ 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/site/docs/manual/extra-topics/color.en.md b/site/docs/manual/extra-topics/color.en.md index 059f7bc6ea..60c2ba7375 100644 --- a/site/docs/manual/extra-topics/color.en.md +++ b/site/docs/manual/extra-topics/color.en.md @@ -2,22 +2,22 @@ title: Color order: 9 --- -Color plays a very important role in visualization. It helps us better understand data, highlight key information, enhance visual appeal and improve readability. Color often serves the following purposes in visualization: +Color plays a very important role in visualization. It helps us better understand data, highlight key information, enhance visual appeal and improve readability. And in visualization, color often serves the following purposes: * **Distinguish data categories**: Distinguish between different data categories. For example, in a bar chart, we can use different colors to represent different product categories to make it easier to identify and compare them. -* **Represents the amount of data**: Indicates the amount of data. For example, in a heat map, we can use shades of color to represent the size of the data, with darker colors representing larger values ​​and lighter colors representing smaller values. +* **Represents the amount of data**: Represent the amount of data. For example, in a heat map, we can use shades of color to represent the size of the data, with darker colors representing larger values ​​and lighter colors representing smaller values. * **Highlight key information**: Highlight key information. For example, in a line chart, we can use bright colors to represent data points of interest to make them easier to find. * **Enhance visual appeal**: Make the visualization more attractive. Using bright colors and interesting color schemes can make visualizations more lively and interesting. * **Improve readability**: Improve the readability of visualizations. For example, on a map, we can use different colors to represent different geographical areas to make them easier to identify and understand. -Set data-independent colors via`mark.style(fill, color)`or`mark.style(stroke, color)`That's it. If you want to set data-driven colors, you can use the following methods to set the colors: +Seting data-independent colors via `mark.style(fill, color)` or `mark.style(stroke, color)`. If you want to set data-driven colors, you can use the following methods to set the colors: -* coding:`mark.encode` -* style:`mark.style` +* encode: `mark.encode` +* style: `mark.style` -## coding +## Encode -pass`mark.encode`The most common way is to set data-driven colors, and configure the final visual display through a color scale. +Most common way to set data-driven colors is through `mark.encode`, and configure the final visual display through a color scale. * `scale.identity`: Identity mapping * `scale.range`: Custom color palette @@ -26,7 +26,7 @@ pass`mark.encode`The most common way is to set data-driven colors, and configure ### Identity -When the color scale is set to Identity, the color channel data will be drawn into the final visualization as visual data, but the scale will not be generated. +When setting the color scale to the identity scale, the color channel data will be drawn into the final visualization as visual data, but the scale will not be generated. ```js | ob (() => { @@ -44,7 +44,7 @@ When the color scale is set to Identity, the color channel data will be drawn in .encode('x', 'genre') .encode('y', 'sold') .encode('color', 'color') - .scale('color', { type: 'identity' }); // 设置该比例尺为恒等映射 + .scale('color', { type: 'identity' }); // Setting this scale to identity mapping. chart.render(); @@ -82,7 +82,7 @@ When the color scale is set to Identity, the color channel data will be drawn in ### Palette -In G2, you can set`scale.palette`Go to Specify Swatches. This palette can be discrete: +In G2, you can set `scale.palette` to specify swatches. This palette can be discrete: ```js | ob (() => { @@ -107,7 +107,7 @@ In G2, you can set`scale.palette`Go to Specify Swatches. This palette can be dis })(); ``` -It can also be continuous: +It(palette) can also be continuous: ```js | ob (() => { @@ -134,24 +134,24 @@ It can also be continuous: })(); ``` -You can refer to this for the current built-in color palette.[palette documentation](/spec/palette)。 +You can refer to this for the current built-in color palette. [palette documentation](/spec/palette)。 ### Relations -able to pass`scale.relations`To specify a series of mapping rules, this priority will be higher than the default mapping method from domain to range. For example, for the color channel, this configuration is useful if you want specific values ​​to be mapped to specific colors, or to handle outliers. +Specifying a series of mapping rules through `scale.relations`. This priority will be higher than the default mapping method from domain to range. For example, for the color channel, this configuration is useful if you want specific values ​​to be mapped to specific colors, or to handle outliers. ```js chart.interval().scale('color', { relations: [ ['dog', 'red'], // dog is identically mapped to red - [(d) => d === undefined, 'grey'], // If the value is undefined, then it is gray + [(d) => d === undefined, 'grey'], // If the value is undefined, it is gray ], }); ``` -## style +## Style -pass`mark.style`To set the color, the color set here is smaller than`encode.color`has a higher priority and no legend will be generated. +Setting colors through `mark.style`. The color setting here takes higher priority compared to setting `encode.color` and no legend will be generated. ```js | ob (() => { @@ -179,4 +179,4 @@ pass`mark.style`To set the color, the color set here is smaller than`encode.colo })(); ``` - + From 463879f98f51998bd087d28df4b68c1f392143b7 Mon Sep 17 00:00:00 2001 From: Runtus <893119806@qq.com> Date: Wed, 8 Nov 2023 16:46:37 +0800 Subject: [PATCH 3/4] docs: translate migration, experimental, customization over --- .../manual/extra-topics/customization.en.md | 70 ++++++++-------- .../extra-topics/experimental-spec-api.en.md | 48 +++++------ .../extra-topics/migration-from-g2v4.en.md | 82 +++++++++---------- .../extra-topics/use-in-framework.en.md | 1 - 4 files changed, 95 insertions(+), 106 deletions(-) diff --git a/site/docs/manual/extra-topics/customization.en.md b/site/docs/manual/extra-topics/customization.en.md index 118f57d208..7c7d581da7 100644 --- a/site/docs/manual/extra-topics/customization.en.md +++ b/site/docs/manual/extra-topics/customization.en.md @@ -4,17 +4,17 @@ order: 8 --- G2 is highly extensible: all visual components can be customized. Here are some common ways to customize visual components. -## Custom shape (Shape) +## Custom Shape (Shape) Each mark can have a custom shape, and the shape determines the final display form of the mark. There are three main steps to customizing a shape: * Define shape components. * Register shape. -* Use shapes. +* Use shape. -First let's take a look at how to define shape components. A shape component is a function that accepts the style of the shape*style*and context*context*, returns a drawing function*render*. in*style*is passed`mark.style`the specified processed options,*context*Contains[@antv/g](https://g.antv.antgroup.com/)Create graphics*document*。 +First let's take a look at how to define shape components. A shape component is a function that accepts the style of the shape *style* and context *context* , and the function returns a drawing function *render*. The *style* is the processed options specified through `mark.style`, and *context* contains *document* for creating graphics in [@antv/g](https://g.antv.antgroup.com/). -return*render*The function accepts the control points of the graph*P*, mapping value*value*and default value*defaults*, returns the graph of @antv/g. in*P*is an array composed of a series of canvas coordinates,*value*is passed`mark.encode`The processed value,*defaults*is in topic`theme.mark.shape`the specified value. The definition of a shape component is roughly as follows: +The *render* function accepts the control points of the graph *P*, mapping value *value* and default value *defaults*, returns the graph of @antv/g. *P* is an array composed of a series of canvas coordinates, *value* is the processed value specified through `mark.encode`, *defaults* is the value specified in the theme for `theme.mark.shape`. The definition of a shape component is roughly as follows: ```js function ShapeTriangle(style, context) { @@ -27,7 +27,7 @@ function ShapeTriangle(style, context) { } ``` -The next step is to register the shape by calling`G2.register('shape.${mark}.${shape}', Shape)`to complete the grouping of the shape. in*mark*is the name of the marker,*shape*is the name of the shape,*Shape*Is a defined shape component. For example, register a triangle shape for the Interval tag: +The next step is to register the shape by calling `G2.register('shape.${mark}.${shape}', Shape)` to complete the registering of the shape. *mark* is the name of the marker, *shape* is the name of the shape, *Shape* is a defined shape component. For example, register a triangle shape for the Interval tag: ```js import { register } from '@antv/g2'; @@ -35,13 +35,13 @@ import { register } from '@antv/g2'; register('shape.interval.triangle', ShapeTriangle); ``` -The last step is to use the shape, which can be passed`mark.encode`specified, or via`mark.style`designation. +The last step is to use the shape, which can be passed `mark.encode` specified, or via `mark.style` designation. ```js ({ type: 'interval', encode: { shape: 'triangle' }, - // 或者 + // or style: { shape: 'triangle' }, }); ``` @@ -50,7 +50,7 @@ The last step is to use the shape, which can be passed`mark.encode`specified, or // API chart.interval().encode('shape', 'triangle'); -// 或者 +// or chart.interval().style('shape', 'triangle'); ``` @@ -58,7 +58,7 @@ Below is a complete example showing how to customize the shape. ```js | ob (() => { - //Define graphic components + // Define graphic components function ShapeTriangle(style, context) { const { document } = context; return (P, value, defaults) => { @@ -76,10 +76,10 @@ Below is a complete example showing how to customize the shape. }; } - //Register the triangle + // Register the triangle G2.register('shape.interval.triangle', ShapeTriangle); - //Initialize chart + // Initialize chart const chart = new G2.Chart(); chart @@ -102,11 +102,11 @@ Below is a complete example showing how to customize the shape. })(); ``` -## Custom tips (Tooltip) +## Custom Tips (Tooltip) -Sometimes the built-in Tooltip cannot meet the needs. In this case, you can use`mark.interaction.tooltip.render`or`view.interaction.tooltip.render`of*render*Function to render custom prompts. +Sometimes the built-in Tooltip cannot meet the needs. In this case, you can use *render* function in `mark.interaction.tooltip.render` or `view.interaction.tooltip.render` to render custom prompts. -Should*render*Function accepts event object*event*and prompt data*tooltipData*, returns a string or DOM object. in*event*yes[@antv/g](https://g.antv.antgroup.com/)the mouse object thrown,*tooltipData*is passed`mark.tooltip`Declared title and items data. If the return value is a string, it will be used as the innerHTML of the tooltip container, otherwise the return value will be mounted. A hint's render function might look like this: +This *render* function accepts event object *event* and prompt data *tooltipData*, and returns a string or DOM object. *event* is the mouse object thrown by [@antv/g](https://g.antv.antgroup.com/), *tooltipData* is the title and items data declared through `mark.tooltip`. If the return value is a string, it will be used as the innerHTML of the tooltip container, otherwise the return value will be mounted. A hint's render function might look like this: ```js function render(event, tooltipData) { @@ -132,7 +132,7 @@ Here's a simple example: .encode('x', 'letter') .encode('y', 'frequency') .interaction('tooltip', { - // render 回调方法返回一个innerHTML 或者 DOM + // The method of render callback returns innerHTML or DOM element. render: (event, { title, items }) => `

${title}