| <!DOCTYPE html> | |
| <!-- | |
| Licensed to the Apache Software Foundation (ASF) under one | |
| or more contributor license agreements. See the NOTICE file | |
| distributed with this work for additional information | |
| regarding copyright ownership. The ASF licenses this file | |
| to you under the Apache License, Version 2.0 (the | |
| "License"); you may not use this file except in compliance | |
| with the License. You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, | |
| software distributed under the License is distributed on an | |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| KIND, either express or implied. See the License for the | |
| specific language governing permissions and limitations | |
| under the License. | |
| --> | |
| <html> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | |
| <script src="lib/simpleRequire.js"></script> | |
| <script src="lib/config.js"></script> | |
| <script src="lib/jquery.min.js"></script> | |
| <script src="lib/facePrint.js"></script> | |
| <script src="lib/testHelper.js"></script> | |
| <script src="lib/draggable.js"></script> | |
| <!-- <script src="ut/lib/canteen.js"></script> --> | |
| <link rel="stylesheet" href="lib/reset.css" /> | |
| </head> | |
| <body> | |
| <style> | |
| </style> | |
| <div id="main_layout"></div> | |
| <div id="main_edge_cases"></div> | |
| <div id="main_self_layout"></div> | |
| <div id="main_dim_data_edge_cases"></div> | |
| <script> | |
| require([ | |
| 'echarts', | |
| ], function (echarts) { | |
| const MatrixClampOption = { | |
| none: 0, | |
| all: 1, | |
| body: 2, | |
| corner: 3, | |
| }; | |
| var LEVEL_SIZE_1 = 15; | |
| var LEVEL_SIZE_2 = 20; | |
| var LEVEL_SIZE_3 = '10%'; | |
| var LEVEL_SIZE_4 = '0%'; | |
| var CELL_SIZE_1 = 30; | |
| var CELL_SIZE_2 = 0; | |
| var BODY_COMMON_COLOR = 'rgba(200, 150, 20, 0.1)'; | |
| var BODY_R2_A2_COLOR = 'rgba(200, 155, 0)'; | |
| var BODY_R1_B2_COLOR = 'rgba(200, 115, 200, 0.3)'; | |
| var X_COMMON_COLOR = 'rgba(22, 188, 212, 0.1)'; | |
| var X_T1_COLOR = 'rgba(12,122,250,0.8)'; | |
| var bodyData = [ | |
| { | |
| coord: ['R2', 'A3'], | |
| mergeCells: true, | |
| }, | |
| { | |
| coord: [['R1', 'S'], 'A'], | |
| itemStyle: { | |
| color: 'rgb(220,240,130)', | |
| } | |
| }, | |
| { | |
| coord: ['R1', ['B4', 'C']], | |
| mergeCells: true, | |
| }, | |
| { | |
| coord: [['R1', 'R2'], ['B2', 'B3']], | |
| itemStyle: { | |
| borderWidth: 4, | |
| borderColor: 'orange', | |
| color: 'red', | |
| }, | |
| mergeCells: true, | |
| }, | |
| { | |
| coord: ['R2', 'A2'], | |
| itemStyle: { | |
| borderWidth: 4, | |
| borderColor: 'blue', | |
| color: BODY_R2_A2_COLOR, | |
| }, | |
| z2: 200, | |
| }, | |
| { | |
| coord: [['R2', 'T'], 'B2'], // Overlap span, should be ignored. | |
| mergeCells: true, | |
| itemStyle: { | |
| borderWidth: 4, | |
| borderColor: 'rgb(200, 152, 222)', | |
| color: BODY_R1_B2_COLOR, | |
| }, | |
| _desc: 'expand to cover all merged cells' | |
| }, | |
| { | |
| coord: ['T', ['A1', 'A31']], // Overlap span, should be ignored. | |
| mergeCells: true, | |
| itemStyle: { | |
| borderColor: 'rgb(123,134,10)', | |
| borderWidth: 3, | |
| color: 'rgb(220,230,170)', | |
| }, | |
| z2: 200, | |
| }, | |
| { | |
| coord: ['R2', 'E'], | |
| value: 'very long long long text', | |
| label: { | |
| color: 'red', | |
| } | |
| }, | |
| { | |
| coord: ['U', null], | |
| coordClamp: true, | |
| itemStyle: { | |
| color: 'rgb(220,230,170)', | |
| }, | |
| }, | |
| { | |
| coord: [NaN, 'F'], | |
| coordClamp: true, | |
| mergeCells: true, | |
| } | |
| ]; | |
| var cornerData = [ | |
| { | |
| coord: [null, -2], | |
| coordClamp: true, | |
| value: 'some', | |
| mergeCells: true, | |
| } | |
| ] | |
| const MATRIX_BACKGROUND_STYLE_MAP = { | |
| do_nothing: { | |
| backgroundStyle: {}, | |
| x: { | |
| itemStyle: {}, | |
| }, | |
| }, | |
| style1: { | |
| backgroundStyle: { | |
| borderWidth: 5, | |
| }, | |
| x: { | |
| itemStyle: { | |
| borderWidth: 2, | |
| color: 'red', | |
| borderColor: 'rgba(11,222,33)' | |
| } | |
| } | |
| }, | |
| style2: { | |
| backgroundStyle: { | |
| borderWidth: 1, | |
| }, | |
| x: { | |
| itemStyle: { | |
| borderWidth: 1, | |
| color: 'none', | |
| borderColor: 'blue' | |
| } | |
| } | |
| }, | |
| }; | |
| // --- state ------ | |
| let _xShowing = true; | |
| let _yShowing = true; | |
| let _convertFromPixelClampOpt = undefined; | |
| let _convertToPointCaseItem = null; | |
| let _matrixBgStyleIndex = 0; | |
| let _textOverflow = 'truncate'; // internal default value. | |
| // ---------------- | |
| var option; | |
| option = { | |
| backgroundColor: '#eee', | |
| tooltip: {}, | |
| title: { | |
| text: '', | |
| right: 'center', | |
| }, | |
| matrix: { | |
| left: 120, | |
| right: '29%', | |
| tooltip: { | |
| show: true, | |
| formatter(params) { | |
| return params.name; | |
| } | |
| }, | |
| x: { | |
| label: { | |
| }, | |
| itemStyle: { | |
| color: X_COMMON_COLOR | |
| }, | |
| levels: [null, {levelSize: LEVEL_SIZE_1}], | |
| data: [ | |
| { | |
| value: 'R', | |
| children: ['R1', {value: 'R2', size: CELL_SIZE_1}] | |
| }, | |
| { | |
| value: 'S' | |
| }, | |
| { | |
| value: 'T', | |
| children: [ | |
| { | |
| value: 'T1', | |
| itemStyle: { | |
| borderWidth: 3, | |
| borderColor: 'rgba(12,12,190)', | |
| color: X_T1_COLOR, | |
| }, | |
| label: { | |
| fontSize: 22, | |
| color: '#fff', | |
| textBorderColor: '#333', | |
| textBorderWidth: 2, | |
| }, | |
| children: ['T11'] | |
| } | |
| ] | |
| }, | |
| { | |
| value: 'long long header text 1', | |
| label: { | |
| color: 'rgb(211,111,0)', | |
| }, | |
| children: [{ | |
| value: 'long long header text 2', | |
| label: { | |
| color: 'rgb(211,81,0)', | |
| } | |
| }] | |
| }, | |
| { | |
| value: 'U', | |
| size: 20, | |
| }, | |
| { | |
| value: 'V', | |
| size: 20, | |
| } | |
| ] | |
| }, | |
| y: { | |
| levelSize: LEVEL_SIZE_2, | |
| levels: [ | |
| null, | |
| {levelSize: LEVEL_SIZE_4}, | |
| null, | |
| null, | |
| {levelSize: LEVEL_SIZE_3} | |
| ], | |
| data: [{ | |
| value: 'LLL', | |
| children: [{ | |
| value: 'LL', | |
| children: [ | |
| { | |
| value: 'A', | |
| children: ['A1', 'A2', { | |
| value: 'A3', | |
| children: ['A31', 'A32'] | |
| }] | |
| }, { | |
| value: 'B', | |
| children: ['B1', 'B2', 'B3', 'B4'] | |
| }, { | |
| value: 'C', | |
| }, { | |
| value: 'D', | |
| size: CELL_SIZE_2, | |
| } | |
| ] | |
| }, { | |
| value: 'E', | |
| }, { | |
| value: 'F', | |
| itemStyle: { | |
| color: '#bbb' | |
| } | |
| }] | |
| }] | |
| }, | |
| body: { | |
| data: bodyData, | |
| label: { | |
| }, | |
| itemStyle: { | |
| color: BODY_COMMON_COLOR | |
| } | |
| }, | |
| corner: { | |
| itemStyle: { | |
| borderWidth: 1, | |
| }, | |
| data: cornerData, | |
| } | |
| }, | |
| graphic: { | |
| elements: [{ | |
| right: 5, | |
| y: 5, | |
| id: 'info_bodyData', | |
| type: 'text', | |
| style: { | |
| text: 'Check body cell merge and style:\n' + testHelper.printObject(bodyData, {lineBreakMaxColumn: 40}), | |
| fontSize: 7, | |
| } | |
| }, { | |
| left: 5, | |
| y: 5, | |
| id: 'info_cornerData', | |
| type: 'text', | |
| style: { | |
| text: 'Check corner cell merge and style:\n' + testHelper.printObject(cornerData, {lineBreakMaxColumn: 40}), | |
| fontSize: 7, | |
| } | |
| }, { | |
| x: 120, | |
| y: 5, | |
| id: 'info2', | |
| type: 'text', | |
| style: { | |
| text: [ | |
| 'Check background: ', | |
| ` BODY_COMMON_COLOR = ${BODY_COMMON_COLOR}`, | |
| ` BODY_R2_A2_COLOR = ${BODY_R2_A2_COLOR}`, | |
| ` BODY_R1_B2_COLOR = ${BODY_R1_B2_COLOR}`, | |
| ` X_COMMON_COLOR = ${X_COMMON_COLOR}`, | |
| ` X_T1_COLOR = ${X_T1_COLOR}`, | |
| ].join('\n'), | |
| fontSize: 7, | |
| } | |
| }] | |
| }, | |
| grid: [{ | |
| id: 'aa', | |
| coordinateSystem: 'matrix', | |
| coord: ['R2', 'B3'], | |
| top: 5, | |
| left: 5, | |
| right: 5, | |
| bottom: 5, | |
| containLabel: true, | |
| }, { | |
| id: 'bb', | |
| coordinateSystem: 'matrix', | |
| coord: ['R1', 'B4'], | |
| top: 5, | |
| left: 5, | |
| right: 5, | |
| bottom: 5, | |
| containLabel: true, | |
| }], | |
| xAxis: [{ | |
| id: 'aa', | |
| gridId: 'aa', | |
| axisLabel: {fontSize: 9} | |
| }, { | |
| id: 'bb', | |
| gridId: 'bb', | |
| data: ['bb1', 'bb2', 'bb3'], | |
| axisLabel: {fontSize: 9} | |
| }], | |
| yAxis: [{ | |
| id: 'aa', | |
| gridId: 'aa', | |
| interval: Infinity, | |
| axisLabel: {fontSize: 9, showMinLabel: true, showMaxLabel: true,}, | |
| }, { | |
| id: 'bb', | |
| gridId: 'bb', | |
| interval: Infinity, | |
| axisLabel: {fontSize: 9, showMinLabel: true, showMaxLabel: true,}, | |
| }], | |
| series: [{ | |
| type: 'scatter', | |
| coordinateSystem: 'matrix', | |
| symbolSize: 30, | |
| data: [ | |
| ['R1', 'A1', 10], ['R2', 'A1', 20], ['R1', 'A2', 30] | |
| ], | |
| label: { | |
| show: true, | |
| formatter: params => { | |
| return params.data[2]; | |
| } | |
| } | |
| }, { | |
| // type: 'effectScatter', | |
| type: 'scatter', | |
| coordinateSystem: 'matrix', | |
| symbolSize: function (val) { | |
| return val[2] / 3; | |
| }, | |
| data: [ | |
| ['R2', 'A2', 40], ['R1', 'A31', 50], ['R2', 'A3', 60] | |
| ], | |
| }, { | |
| type: 'scatter', | |
| name: 'right desc', | |
| silent: true, | |
| coordinateSystem: 'matrix', | |
| symbolSize: 0, | |
| symbolOffset: [0, 10], | |
| label: {show: true, overflow: 'break', minMargin: 15}, | |
| labelLine: {show: true}, | |
| labelLayout: { | |
| x: '73%', | |
| moveOverlap: 'shiftY', | |
| width: 70, | |
| }, | |
| encode: {label: [0, 1, 2]}, | |
| data: [ | |
| ['T1', -2, `x.levels[3].levelSize: ${LEVEL_SIZE_1}`], | |
| ['T11', -1, 'levelSize: average (not specified)'], | |
| ['R2', -1, `size: ${CELL_SIZE_1}`], | |
| ] | |
| }, { | |
| type: 'scatter', | |
| name: 'left desc', | |
| silent: true, | |
| coordinateSystem: 'matrix', | |
| symbolSize: 0, | |
| symbolOffset: [0, 10], | |
| label: {show: true, overflow: 'break', minMargin: 15}, | |
| labelLine: {show: true}, | |
| labelLayout: {x: '1%', width: 110, moveOverlap: 'shiftY'}, | |
| encode: {label: [0, 1, 2]}, | |
| data: [ | |
| [-3, 'A', `y.levelSize: ${LEVEL_SIZE_2}`], | |
| [-2, 'A3', `y.levelSize: ${LEVEL_SIZE_2}`], | |
| [-1, 'A31', `y.levels[4].levelSize: ${LEVEL_SIZE_3}`], | |
| [-1, 'D', `size: ${CELL_SIZE_2}`], | |
| [-4, 'E', `y.levels[2].levelSize: ${LEVEL_SIZE_4}`] | |
| ] | |
| }, | |
| { | |
| type: 'line', | |
| xAxisId: 'aa', | |
| yAxisId: 'aa', | |
| data: [[11, 22], [33, 44], [55, 66]], | |
| }, { | |
| type: 'bar', | |
| xAxisId: 'bb', | |
| yAxisId: 'bb', | |
| data: [987, 583, 671], | |
| }] | |
| }; | |
| var chart = testHelper.create(echarts, 'main_layout', { | |
| title: [ | |
| 'Locator testing.', | |
| 'scatter, cartesian, with Matrix.', | |
| 'cell merging: should display **on the center** of the merged cell.', | |
| 'click on cell to call convertFromPixel - especially on span cell.', | |
| 'click on corner should correct.', | |
| 'tooltip can be displayed for text (consider overflow).', | |
| ], | |
| height: 500, | |
| option: option, | |
| inputsStyle: 'compact', | |
| inputs: [ | |
| { | |
| text: 'matrix.x show:', | |
| type: 'select', | |
| values: [true, false], | |
| onchange() { | |
| _xShowing = this.value; | |
| chart.setOption({ | |
| matrix: { | |
| x: {show: _xShowing}, | |
| }, | |
| }); | |
| updateCaseView(); | |
| } | |
| }, | |
| { | |
| text: 'matrix.y show:', | |
| type: 'select', | |
| values: [true, false], | |
| onchange() { | |
| _yShowing = this.value; | |
| chart.setOption({ | |
| matrix: { | |
| y: {show: _yShowing}, | |
| }, | |
| }); | |
| updateCaseView(); | |
| } | |
| }, | |
| { | |
| text: 'convertFromPixel clamp:', | |
| type: 'select', | |
| options: [ | |
| {value: undefined} | |
| ].concat(Object.keys(MatrixClampOption).map(key => ({ | |
| text: key, | |
| value: MatrixClampOption[key], | |
| }))), | |
| onchange() { | |
| _convertFromPixelClampOpt = this.value; | |
| updateCaseView(); | |
| }, | |
| }, | |
| { | |
| type: 'select', | |
| text: 'text overflow:', | |
| values: ['truncate', 'break', 'none'], | |
| onchange() { | |
| _textOverflow = this.value; | |
| chart.setOption({ | |
| matrix: { | |
| x: {label: {overflow: _textOverflow}}, | |
| y: {label: {overflow: _textOverflow}}, | |
| body: {label: {overflow: _textOverflow}}, | |
| corner: {label: {overflow: _textOverflow}}, | |
| }, | |
| }); | |
| updateCaseView(); | |
| } | |
| }, | |
| { | |
| type: 'select', | |
| text: 'switch style:', | |
| values: Object.keys(MATRIX_BACKGROUND_STYLE_MAP), | |
| onchange() { | |
| const preset = MATRIX_BACKGROUND_STYLE_MAP[this.value]; | |
| chart.setOption({ | |
| matrix: { | |
| backgroundStyle: preset.backgroundStyle, | |
| x: { | |
| itemStyle: preset.x.itemStyle, | |
| } | |
| } | |
| }); | |
| updateCaseView(); | |
| } | |
| }, | |
| { | |
| type: 'select', | |
| text: 'convertToPixel test cases:', | |
| values: [ | |
| 'do_nothing', | |
| ['R2', 'A31'], | |
| ['not_exists', 'A1'], | |
| ['S', Infinity], | |
| [1, 3], | |
| ['R1', 'A'], | |
| ['R1', 'A2'], | |
| ['R1', 'B4'], | |
| ['R1', 'B2'], | |
| ['R1', 'C'], | |
| ['R2', 'B3'], | |
| ], | |
| onchange() { | |
| const caseItem = this.value; | |
| if (caseItem === 'do_nothing') { | |
| return; | |
| } | |
| _convertToPointCaseItem = this.value; | |
| updateCaseView(); | |
| } | |
| }, | |
| ] | |
| }); | |
| function updateCaseView() { | |
| if (!_convertToPointCaseItem) { | |
| return; | |
| } | |
| const result = chart.convertToPixel({matrixIndex: 0}, _convertToPointCaseItem); | |
| updateConvertToPixelResult(result); | |
| } | |
| function updateConvertToPixelResult(result) { | |
| console.log(result); | |
| chart.setOption({ | |
| title: { | |
| text: 'convertToPixel result: ' + testHelper.printObject(result) | |
| }, | |
| graphic: { | |
| elements: [{ | |
| id: 'result', | |
| type: 'circle', | |
| shape: { | |
| cx: result[0], | |
| cy: result[1], | |
| r: 20, | |
| }, | |
| ignore: isNaN(result[0]) || isNaN(result[1]), | |
| z: 1000, | |
| style: { | |
| stroke: 'red', | |
| fill: null, | |
| lineWidth: 5, | |
| opacity: 0.8, | |
| }, | |
| textContent: { | |
| style: { | |
| text: '⬅ convertToPixel result', | |
| fill: 'red', | |
| }, | |
| z: 1000, | |
| }, | |
| textConfig: { | |
| position: 'right' | |
| }, | |
| }] | |
| } | |
| }); | |
| } | |
| if (chart) { | |
| chart.getZr().on('click', function (event) { | |
| const point = [event.offsetX, event.offsetY]; | |
| let opt = null; | |
| if (_convertFromPixelClampOpt != null) { | |
| opt = {clamp: _convertFromPixelClampOpt}; | |
| } | |
| const result = chart.convertFromPixel({matrixIndex: 0}, point, opt); | |
| console.log('point', point, 'result', result); | |
| chart.setOption({ | |
| title: { | |
| text: 'convertFromPixel result: ' + testHelper.printObject(result) | |
| } | |
| }); | |
| }); | |
| } | |
| }); | |
| </script> | |
| <script> | |
| require([ | |
| 'echarts', | |
| ], function (echarts) { | |
| var LEVEL_SIZE_1 = 15; | |
| var LEVEL_SIZE_2 = 20; | |
| var LEVEL_SIZE_3 = '10%'; | |
| var LEVEL_SIZE_4 = '0%'; | |
| var CELL_SIZE_1 = 30; | |
| var CELL_SIZE_2 = 0; | |
| var BODY_COMMON_COLOR = 'rgba(200, 150, 20, 0.1)'; | |
| var BODY_R2_A2_COLOR = 'rgba(200, 155, 0)'; | |
| var BODY_R1_B2_COLOR = 'rgba(200, 115, 200, 0.3)'; | |
| var X_COMMON_COLOR = 'rgba(22, 188, 212, 0.1)'; | |
| var X_T1_COLOR = 'rgba(12,122,250,0.8)'; | |
| var _bodyData = [ | |
| { | |
| coord: ['R2', 'A3'], | |
| mergeCells: true, | |
| value: 'merged', | |
| }, | |
| { | |
| coord: ['R1', ['B4', 'C']], | |
| mergeCells: true, | |
| value: 'merged', | |
| }, | |
| { | |
| coord: [['R1', 'R2'], ['B2', 'B3']], | |
| mergeCells: true, | |
| value: 'merged', | |
| }, | |
| { | |
| coord: ['O', ['B2', 'not_exist']], | |
| coordClamp: true, | |
| mergeCells: true, | |
| value: 'merged', | |
| __expect: 'column O merged' | |
| }, | |
| { | |
| coord: ['T', ['A1', 'A31']], | |
| mergeCells: true, | |
| value: 'merged', | |
| }, | |
| { | |
| coord: ['S', null], | |
| coordClamp: true, | |
| mergeCells: true, | |
| value: 'merged', | |
| __expect: 'column S merged.' | |
| }, | |
| ]; | |
| var _cornerData = [ | |
| { | |
| coord: [[-1, -2], -1], | |
| mergeCells: true, | |
| value: 'merged', | |
| } | |
| ]; | |
| const _xData = [ | |
| { | |
| value: 'R', | |
| children: ['R1', {value: 'R2', size: CELL_SIZE_1}] | |
| }, | |
| { | |
| value: 'S' | |
| }, | |
| { | |
| value: 'T', | |
| children: [ | |
| { | |
| value: 'T1', | |
| children: ['T11'], | |
| } | |
| ] | |
| }, | |
| 'O', | |
| 'P', | |
| ]; | |
| const _yData = [ | |
| { | |
| value: 'A', | |
| children: ['A1', 'A2', { | |
| value: 'A3', | |
| children: ['A31', 'A32'] | |
| }] | |
| }, { | |
| value: 'B', | |
| children: ['B1', 'B2', 'B3', 'B4'] | |
| }, { | |
| value: 'C', | |
| }, { | |
| value: 'D', | |
| } | |
| ]; | |
| const MatrixClampOption = { | |
| none: 0, | |
| all: 1, | |
| body: 2, | |
| corner: 3, | |
| }; | |
| // --- state ------ | |
| let _xShowing = true; | |
| let _yShowing = true; | |
| let _convertToLayoutClampOpt = undefined; | |
| let _ignoreMergeCells = undefined; | |
| let _testCase = null; | |
| // ---------------- | |
| function calcMeta() { | |
| const xMeta = calcOneDim(_xData); | |
| const yMeta = calcOneDim(_yData); | |
| function calcOneDim(xyData) { | |
| let levelCount = 0; | |
| let leafCount = 0; | |
| travel(xyData, 0, 0); | |
| function travel(list, locatorStart, level) { | |
| levelCount = Math.max(levelCount, level); | |
| leafCount = Math.max(leafCount, locatorStart); | |
| if (!list) { | |
| return; | |
| } | |
| list.forEach((item, idx) => { | |
| travel(item.children, locatorStart + idx, level + 1); | |
| }); | |
| } | |
| return {levelCount, leafCount}; | |
| } | |
| const xUnitCount = xMeta.leafCount + (_yShowing ? yMeta.levelCount : 0); | |
| const yUnitCount = yMeta.leafCount + (_xShowing ? xMeta.levelCount : 0); | |
| return {xUnitCount, yUnitCount}; | |
| } | |
| var option; | |
| option = { | |
| backgroundColor: '#eee', | |
| tooltip: {}, | |
| title: { | |
| text: '', | |
| right: 'center', | |
| }, | |
| matrix: [{ | |
| // matrix 0 | |
| right: 10, | |
| bottom: 10, | |
| width: 180, | |
| height: 80, | |
| x: { | |
| data: ['X1', 'X2', 'X3'], | |
| }, | |
| y: { | |
| data: ['Y1', 'Y2', 'Y3', 'Y4'], | |
| }, | |
| body: { | |
| data: [{ | |
| coord: [[0, 2], [1, 2]], | |
| value: 'should be right-bottom', | |
| mergeCells: true, | |
| }] | |
| }, | |
| }, { | |
| // matrix 1 | |
| id: 'main_matrix', | |
| right: 10, | |
| left: 230, | |
| top: 50, | |
| bottom: 120, | |
| tooltip: { | |
| show: true, | |
| formatter(params) { | |
| return params.name; | |
| } | |
| }, | |
| x: { | |
| label: { | |
| }, | |
| itemStyle: { | |
| color: X_COMMON_COLOR | |
| }, | |
| levels: [null, {levelSize: LEVEL_SIZE_1}], | |
| data: _xData | |
| }, | |
| y: { | |
| levelSize: 40, | |
| data: _yData, | |
| }, | |
| body: { | |
| data: _bodyData, | |
| label: { | |
| }, | |
| itemStyle: { | |
| color: BODY_COMMON_COLOR | |
| } | |
| }, | |
| corner: { | |
| data: _cornerData, | |
| itemStyle: { | |
| borderWidth: 1, | |
| }, | |
| } | |
| }], | |
| series: [{ | |
| type: 'scatter', | |
| coordinateSystem: 'matrix', | |
| matrixIndex: 1, | |
| symbolSize: 30, | |
| data: [ | |
| ['R1', 'A1', 10], ['R2', 'A1', 20], ['R1', 'A2', 30] | |
| ], | |
| label: { | |
| show: true, | |
| formatter: params => { | |
| return params.data[2]; | |
| } | |
| } | |
| }], | |
| graphic: { | |
| elements: [{ | |
| left: 5, | |
| y: 5, | |
| id: 'info_bodyData', | |
| type: 'text', | |
| style: { | |
| text: 'Check body cell merge and style:\n' + testHelper.printObject(_bodyData, {lineBreakMaxColumn: 40}), | |
| fontSize: 7, | |
| } | |
| }, { | |
| left: 140, | |
| y: 5, | |
| id: 'info_cornerData', | |
| type: 'text', | |
| style: { | |
| text: 'Check corner cell merge and style:\n' + testHelper.printObject(_cornerData, {lineBreakMaxColumn: 40}), | |
| fontSize: 7, | |
| } | |
| }, { | |
| id: 'result_convertToLayout', | |
| type: 'rect', | |
| shape: {x: 0, y: 0, width: 0, height: 0}, | |
| ignore: true, | |
| silent: true, | |
| style: { | |
| fill: 'rgba(210,20,100,0.3)', | |
| stroke: 'rgba(210,20,100,0.8)', | |
| lineWidth: 3, | |
| } | |
| }, { | |
| id: 'result_assertionFailure', | |
| type: 'text', | |
| ignore: true, | |
| silent: true, | |
| left: 10, | |
| bottom: 10, | |
| style: { | |
| text: 'Some Case Failed', | |
| fill: 'red', | |
| fontSize: 20, | |
| } | |
| }] | |
| }, | |
| }; | |
| var chart = testHelper.create(echarts, 'main_edge_cases', { | |
| title: [ | |
| 'Edge cases.', | |
| 'Test both when **show/hide** matrix.x/y; different **clamp**; **ignoreCellMerge** or not.', | |
| 'drag to resize to test cell border alignment', | |
| '(must not affect by subpixel optimize or rounding error)', | |
| ], | |
| height: 350, | |
| option: option, | |
| inputsStyle: 'compact', | |
| draggable: true, | |
| inputs: [ | |
| { | |
| text: 'matrix.x show:', | |
| type: 'select', | |
| values: [true, false], | |
| onchange() { | |
| _xShowing = this.value; | |
| chart.setOption({ | |
| matrix: { | |
| id: 'main_matrix', | |
| x: {show: _xShowing}, | |
| }, | |
| }); | |
| updateCaseView(); | |
| } | |
| }, | |
| { | |
| text: 'matrix.y show:', | |
| type: 'select', | |
| values: [true, false], | |
| onchange() { | |
| _yShowing = this.value; | |
| chart.setOption({ | |
| matrix: { | |
| id: 'main_matrix', | |
| y: {show: _yShowing}, | |
| }, | |
| }); | |
| updateCaseView(); | |
| } | |
| }, | |
| { | |
| text: 'convertToLayout clamp:', | |
| type: 'select', | |
| options: [ | |
| {value: undefined} | |
| ].concat(Object.keys(MatrixClampOption).map(key => ({ | |
| text: key, | |
| value: MatrixClampOption[key], | |
| }))), | |
| onchange() { | |
| _convertToLayoutClampOpt = this.value; | |
| updateCaseView(); | |
| }, | |
| }, | |
| { | |
| text: 'ignoreMergeCells:', | |
| type: 'select', | |
| values: [undefined, false, true], | |
| onchange() { | |
| _ignoreMergeCells = this.value; | |
| updateCaseView(); | |
| }, | |
| }, | |
| { | |
| type: 'br', | |
| }, | |
| { | |
| type: 'select', | |
| text: 'convertToLayout test cases:', | |
| options: [{value: 'do_nothing'}].concat([ | |
| { | |
| input: [], | |
| expectDefault: { | |
| rectNaN: {x: true, y: true, width: true, height: true}, | |
| matrixXYLocatorRange: [[NaN, NaN], [NaN, NaN]] | |
| } | |
| }, | |
| { | |
| input: ['R2', null], | |
| expectDefault: { | |
| rectNaN: {y: true, height: true}, | |
| matrixXYLocatorRange: [[1, 1], [NaN, NaN]] | |
| } | |
| }, | |
| { | |
| input: [['S', 'O'], NaN], | |
| expectDefault: { | |
| rectNaN: {y: true, height: true}, | |
| matrixXYLocatorRange: [[2, 4], [NaN, NaN]] | |
| } | |
| }, | |
| { | |
| input: [['R'], NaN], | |
| expectDefault: { | |
| rectNaN: {y: true, height: true}, | |
| matrixXYLocatorRange: [[0, 1], [NaN, NaN]] | |
| } | |
| }, | |
| { | |
| input: [NaN, 'A31'], | |
| expectDefault: { | |
| rectNaN: {x: true, width: true}, | |
| matrixXYLocatorRange: [[NaN, NaN], [2, 2]] | |
| } | |
| }, | |
| { | |
| input: [undefined, ['A32', 'B3']], | |
| expectDefault: { | |
| rectNaN: {x: true, width: true}, | |
| matrixXYLocatorRange: [[NaN, NaN], [3, 6]] | |
| } | |
| }, | |
| { | |
| input: [null, 'B'], | |
| expectDefault: { | |
| rectNaN: {x: true, width: true}, | |
| matrixXYLocatorRange: [[NaN, NaN], [4, 7]] | |
| } | |
| }, | |
| { | |
| input: ['S', 'A32'], | |
| expectDefault: { | |
| rectNaN: {}, | |
| matrixXYLocatorRange: [[2, 2], [0, 9]] | |
| } | |
| }, | |
| { | |
| input: ['T', 'B1'], | |
| expectDefault: { | |
| rectNaN: {}, | |
| matrixXYLocatorRange: [[3, 3], [4, 4]] | |
| } | |
| }, | |
| { | |
| input: [[-1, 1], [-1, 2]], | |
| expectDefault: { | |
| rectNaN: {}, | |
| matrixXYLocatorRange: [[-2, 1], [-1, 3]] | |
| } | |
| }, | |
| { | |
| input: ['R', -2], | |
| expectDefault: { | |
| rectNaN: {}, | |
| matrixXYLocatorRange: [[0, 1], [-2, -2]] | |
| } | |
| }, | |
| ].map(item => ({ | |
| text: testHelper.printObject(item.input), | |
| value: item, | |
| }))), | |
| onchange() { | |
| if (this.value === 'do_nothing') { | |
| return; | |
| } | |
| _testCase = this.value; | |
| updateCaseView(); | |
| } // End of onchange | |
| } // End of convertToLayout test cases | |
| ] | |
| }); | |
| function updateCaseView() { | |
| performTest(function (assert) { | |
| if (!_testCase) { | |
| return; | |
| } | |
| const {input, expectDefault} = _testCase; | |
| const shouldBeClampped = !( | |
| _convertToLayoutClampOpt == null || _convertToLayoutClampOpt === MatrixClampOption.none | |
| ); | |
| const isDefaultCase = !shouldBeClampped && !_ignoreMergeCells; | |
| const meta = calcMeta(); | |
| let opt = undefined; | |
| if (_convertToLayoutClampOpt != null) { | |
| opt = opt || {}; | |
| opt.clamp = _convertToLayoutClampOpt; | |
| } | |
| if (_ignoreMergeCells != null) { | |
| opt = opt || {}; | |
| opt.ignoreMergeCells = _ignoreMergeCells; | |
| } | |
| const result = chart.convertToLayout({matrixIndex: 1}, input, opt); | |
| console.log('Call convertToLayout', 'input:', input, 'opt:', opt, 'result:', result); | |
| assert(testHelper.getType(result) === 'object'); | |
| assert(testHelper.getType(result.rect) === 'object'); | |
| assert(testHelper.getType(result.rect.x) === 'number'); | |
| assert(testHelper.getType(result.rect.y) === 'number'); | |
| assert(testHelper.getType(result.rect.width) === 'number'); | |
| assert(testHelper.getType(result.rect.height) === 'number'); | |
| assert(testHelper.getType(result.matrixXYLocatorRange) === 'array'); | |
| assert(testHelper.getType(result.matrixXYLocatorRange[0]) === 'array'); | |
| assert(testHelper.getType(result.matrixXYLocatorRange[1]) === 'array'); | |
| assert(testHelper.getType(result.matrixXYLocatorRange[0][0]) === 'number'); | |
| assert(testHelper.getType(result.matrixXYLocatorRange[0][1]) === 'number'); | |
| assert(testHelper.getType(result.matrixXYLocatorRange[1][0]) === 'number'); | |
| assert(testHelper.getType(result.matrixXYLocatorRange[1][1]) === 'number'); | |
| ['x', 'y', 'width', 'height'].forEach(prop => { | |
| if (isDefaultCase) { | |
| if (expectDefault.rectNaN[prop]) { | |
| assert(eqNaN(result.rect[prop])); | |
| } | |
| else { | |
| assert(isFinite(result.rect[prop])); | |
| } | |
| } | |
| else if (shouldBeClampped) { | |
| assert(isFinite(result.rect[prop])); | |
| } | |
| }); | |
| if (isDefaultCase) { | |
| assert(numEq(expectDefault.matrixXYLocatorRange[0][0], result.matrixXYLocatorRange[0][0])); | |
| assert(numEq(expectDefault.matrixXYLocatorRange[0][1], result.matrixXYLocatorRange[0][1])); | |
| assert(numEq(expectDefault.matrixXYLocatorRange[1][0], result.matrixXYLocatorRange[1][0])); | |
| assert(numEq(expectDefault.matrixXYLocatorRange[1][1], result.matrixXYLocatorRange[1][1])); | |
| } | |
| return result; | |
| }); | |
| function performTest(cb) { | |
| let testFailed = false; | |
| function assert(condition) { | |
| if (!condition) { | |
| testFailed = true; | |
| console.error('assertion failed', new Error()); | |
| } | |
| } | |
| let result; | |
| try { | |
| result = cb(assert); | |
| } | |
| catch (err) { | |
| testFailed = true; | |
| console.error(err); | |
| } | |
| const COVER_SIZE = 10000; // Just a big enough number. | |
| let indicatorShape = {x: 0, y: 0, width: 0, height: 0}; | |
| if (result) { | |
| indicatorShape = {}; | |
| indicatorShape.x = eqNaN(result.rect.x) ? -COVER_SIZE / 2 : result.rect.x; | |
| indicatorShape.y = eqNaN(result.rect.y) ? -COVER_SIZE / 2 : result.rect.y; | |
| indicatorShape.width = eqNaN(result.rect.width) ? COVER_SIZE : result.rect.width; | |
| indicatorShape.height = eqNaN(result.rect.height) ? COVER_SIZE : result.rect.height;; | |
| } | |
| chart.setOption({ | |
| graphic: { | |
| elements: [{ | |
| id: 'result_convertToLayout', | |
| shape: indicatorShape, | |
| ignore: testFailed, | |
| }, { | |
| id: 'result_assertionFailure', | |
| ignore: !testFailed, | |
| }] | |
| }, | |
| }); | |
| } | |
| } | |
| function eqNaN(value) { | |
| return value !== value; | |
| } | |
| function numEq(expect, actual) { | |
| return eqNaN(expect) | |
| ? eqNaN(actual) | |
| : expect === actual; | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> | |