100pah commented on PR #19807: URL: https://github.com/apache/echarts/pull/19807#issuecomment-2923293327
During the CR of this PR, I found that there are features can be added or enhanced to make a more comprehensive coordinate system definition and implementation. Therefore I made a implement in https://github.com/apache/echarts/pull/21005 , and seek to merge to this PR. And all the comments I suggested in this CR has been fixed in that new PR. #21005 made these changes: ## Support declaratively layout other coorSys/components/series based on matrix and calendar Some abstraction has been make based on calendar and matrix - they are similar and represent a kind of coord sys that can convert data value to a "container(rect)", rather than only a "point". Therefore, all of the other components can be layout on matrix/calendar. including: - coord sys components, such as, grid/polar/geo/graph/parallel/singleAxis/... - non-coordSys components, such as, legend/title/dataZoom/visualMap/toolbox/... - series, such as, pie/funnel/map/radar - PENDING/TOOD: other more series, such as tree/treemap/...? The effect is: Previously we also made case that layout cartesian or pie on calendar, but that cases relies on `chart.convertToPixel` - not a declarative way and complicated. This new PR introduced the uniform declarative way to do that: ```ts option: { matrix: {...}, grid: { coordinateSystem: 'matrix', coord: ['X2', 'Y6'], // coord on matrix. }, } ``` That is, the option `coordinateSystem` and `coord` (newly introduced) can be used universally to any components/series. Additionally, there are some complicated case in `series.graph`/`series.map`: They can use a coord sys to lay out both each item in `series.data` or lay out the overall bounding rect. To distinguish the usage of the declared coord sys, the new PR introduce a new option `coordinateSystemUsage`: ```ts option: { matrix: {...}, graph: { coordinateSystem: 'matrix', /** * - "data": Use it as "dataCoordSys", each data item is laid out based on a coord sys. * - "box": Use it as "boxCoordSys", the overall bounding rect or anchor point is calculated based on a coord sys. * e.g., * grid rect (cartesian rect) is calculate based on matrix/calendar coord sys; * pie center is calculated based on calendar/cartesian; * * The default value (if not declared in option `coordinateSystemUsage`): * For series, be "data", since this is the most case and backward compatible. * For non-series components, be "box", since "data" is not applicable. */ coordinateSystemUsage: 'box', coord: ['X2', 'Y6'], // coord on matrix. }, } ``` In most cases, `coordinateSystemUsage` do not need to specified, since there is no ambiguity about the usage of a coord sys. It's worth noting that this new PR only supports `matrix` and `calendar` to be a "box layout base" to other coord sys, but do not support such as layout `cartesian2d` on `geo` declaratively, and do not recursive dependencies, such as, layout a `matrix` on another `matrix`. They can be implemented thearetically, but it requires some more complicated logic, see the comment in `src/core/CoordinateSystem.ts` for details. Along with this feature, a new echarts API `chart.convertToLayout` is introduced, providing the ability to return layout info (currently, `rect` or `contentRect`), rather than previously `chart.convertToPixel` can only return a point. And in custom series, a new renderItem param API `api.layout` is added corresponding to `chart.convertToLayout`, just as the previous custom series API `api.coord` corresponds to `chart.convertToPixel`. Regarding the implementation, previously almost all of the components can be uniformly layout by option `left/right/top/bottom/width/height`, and internally uniformly handled by `getLayoutRect` in `src/layout.ts`. This new impl adds a new uniform method `createBoxLayoutReference` to layout them based on the canvas or the declared coord sys. ## Support matrix col/row size option Column/row size need to be able to specified. The effect: ```ts option = { matrix: { x: { data: [ // The width of a specific column {value: 'A', size: 123}, ], // level size for all levels (x header rows). levelSize: 55 // level size for a specific level (a x header row). levels: [{levelSize: 10}], }, y: { data: [ // The height of a specific row {value: 'M', size: 123}, ], // level size for all levels (y header columns). levelSize: 123 // level size for a specific level (a y header column). levels: [null, null, {levelSize: 32}], } } } ``` ## Support matrix `mergeCells` Cell merge is commonly used in table or spreadsheet. See the effect: The `matrix.x/y` has a tree hierarchy and naturally has cell span. The new PR preserve that definition and still do not allow specifying random cell merging. But in body and corner, the new PR introduce the cell merging definitions: ```ts option = { matrix: { x: { data: ['X5', 'X6', 'X7'] }, y: { data: ['Y90', 'Y91', 'Y92'] }, data: { data: [ // Merge the rect defined by x range 'X5', 'X6' and y range 'Y90' {coord: [['X5', 'X6'], 'Y90'], mergeCells: true}, // Merge the entire row {coord: [null, 'Y92'], mergeCells: true}, ] } } }; ``` ## Support "corner" (top-left area) It's might be a challenge that how to design the option for users to customize the corner. I think the corner can be defined as the same way as "body", that is, the corner can also be composed by cells, and share the `mergeCells` and style options formatter. See the effect: In the new PR, corner can be located by a pair of negative integers. See "locator of matrix" below. ## Clarify the locator of matrix Suport locate a cell (either in body or in corner or in header(x/y dimension)). Basically, a locator and is defined by `matrix.x/y.data`, and can be a string (such as, 'X1', 'Y1', ) or `OrdinalNumber`(i.e, -2, -1, 0, 1, 2, 3, ...) Below is the details. TL;DR, The rule is applied uniformly (such as, in `matrix.dataToPoint` and `matrix.dataToLayout` and `xxxComponent.coord`) Suppose the matrix.x/y dimensions (header) are defined as: ```ts matrix: { x: [{ value: 'Xa0', children: ['Xb0', 'Xb1'] }, 'Xa1'], y: [{ value: 'Ya0', children: ['Yb0', 'Yb1'] }], } ``` ----------------------------------------- | | | Xa0 | | |-------+-------+---------------| Xa1 | |cornerQ|cornerP| Xb0 | Xb1 | | |-------+-------+-------+-------+-------- | | Yb0 | bodyR | bodyS | | | Ya0 |-------+-------+-------+-------| | | Yb1 | | bodyT | |---------------|------------------------ "Locator number" (`MatrixXYLocator`): The term `locator` refers to a integer number to locate cells on x or y direction. Use the top-left corner of the body as the orgin point (0, 0), the non-negative locator indicates the right/bottom of the origin point; the negative locator indicates the left/top of the origin point. "Ordinal number" (`OrdinalNumber`): This term follows the same meaning as that in category axis of cartesian. They are non-negative integer, designating each string `matrix.x.data[i].value`/`matrix.y.data[i].value`. 'Xb0', 'Xb2', 'Xa1', 'Xa0' are assigned with the ordinal numbers 0, 1, 2, 3. For every leaf dimension cell, `OrdinalNumber` and `MatrixXYLocator` is the same. A cell or pixel point or rect can be determined/located by a pair of `MatrixCoordValueOption`. See also `MatrixBodyCornerCellOption['coord']`. - The body cell `bodyS` above can be located by: - `coord: [1, 0]` (`MatrixXYLocator` or `OrdinalNumber`, which is a non-negative integer) - `coord: ['Xb1', 'Yb0']` - `coord: ['Xb1', 0]` (mix them) - The corner cell `cornerQ` above can be located by: - `coord: [-2, -1]` (negative `MatrixXYLocator`) - But it is NOT supported to use `coord: ['Y1_0', 'X1_0']` (XY transposed form) here. It's mathematically sound, but may introduce confusion and unnecessary complexity (consider the 'Xa1' case), and corner locating is not frequently used. - `mergeCells`: Body cells or corner cells can be merged, such as "bodyT" above, an input - The merging can be defined by: `matrix.data[i]: {coord: [['Xb1', 'Xa1'], 'Yb0'], mergeCells: true}`. - Input `['Xa1', 'Yb1']` to `dataToPoint` will get a point in the center of "bodyT". - Input `['Xa1', 'Yb1']` to `dataToLayout` will get a rect of the "bodyT". - If inputing a non-leaf dimension cell to locate, such as `['Xa0', 'Yb0']`, - it returns only according to the center of the dimension cells, regardless of the body span. (therefore, the result can be on the boundary of two body cells.) And the oridinal number assigned to 'Xa0' is 3, thus input `[3, 'Yb0']` get the some result. - The dimension (header) cell can be located by negative `MatrixXYLocator`. For example: - The center of the node 'Ya0' can be located by `[-2, 'Ya0']`. ## Fix and refactor the matrix style options Considered their inheritance and z-order and flexibility. Considering the flexibility of the style configuration, the style related options are sort to: ```ts option = { matrix: { x: { // Two levels of inheritance itemStyle and label. itemStyle: {...}, label: {...}, // Padding for the inner content (label / series / other coord sys). padding?: number | number[]; cursor?: string; // By default, auto decide whether to be silent, considering tooltip. silent?: boolean | NullUndefined; // Used when style conflict - especially for thick border style. z2?: number; dividerLineStyle: {...} // Special for the divider line. data: [ {value: ..., itemStyle: {...}, label: {...}, padding, cursor, silent, z2}, {value: ..., itemStyle: {...}, label: {...}, padding, cursor, silent, z2}, ], }, y: { /* The same as x */}, body: { /* The same as x */}, corner: { /* The same as x */}, backgroundStyle: {...} // Special for the overall background. } } ``` ## Support that auto collect matrix dimension data from series This behaves the same with category axis, that is: ```ts option = { matrix: {} // no x y defined, dataset: { source: [ ['2021-02-01', 'amount', 1212, 'file', 2321, 'Q', 1412], ['2021-02-02', 'amount', 7181, 'file', 2114, 'Q', 1402], ['2021-02-03', 'amount', 2763, 'file', 4212, 'Q', 8172], ['2021-02-04', 'amount', 6122, 'file', 2942, 'Q', 6121], ['2021-02-05', 'amount', 4221, 'file', 3411, 'Q', 1987], ['2021-02-06', 'amount', 7221, 'file', 5121, 'Q', 1303], ] }, series: [{ type: 'scatter', coordinateSystem: 'matrix', encode: {x: 1, y: 0, label: 2}, }, { type: 'scatter', coordinateSystem: 'matrix', symbol: 'rect', encode: {x: 3, y: 0, label: 4}, }, { type: 'scatter', coordinateSystem: 'matrix', encode: {x: 5, y: 0, label: 6}, }], }; ``` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
