| <!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 style=" |
| height: 1207px; |
| margin: 0; |
| padding: 20px; |
| background: #eee; |
| overflow: hidden; |
| box-sizing: border-box; |
| " |
| > |
| This is a placeholder for y coord matching the visual test due to the visual test migration. |
| <br> |
| Scroll down to check the test case below. |
| <br> |
| ↓ ↓ ↓ |
| </div> |
| |
| <div id="main_self_layout"></div> |
| <div id="main_dim_data_edge_cases"></div> |
| |
| |
| |
| |
| |
| |
| <script> |
| |
| var option; |
| |
| require([ |
| 'echarts' |
| ], function (echarts) { |
| |
| const layoutList = [ |
| { |
| layout: { |
| left: 10, |
| bottom: 10, |
| width: 250, |
| height: 50, |
| }, |
| expect: 'left-bottom', |
| }, |
| { |
| layout: { |
| right: 10, |
| bottom: 10, |
| width: 250, |
| height: 50, |
| }, |
| expect: 'right-bottom' |
| }, |
| { |
| layout: { |
| }, |
| expect: 'default place' |
| }, |
| ]; |
| |
| option = { |
| backgroundColor: '#eee', |
| matrix: [ |
| |
| // Layout test (r/l/t/b/w/h) |
| ...layoutList.map(item => ({ |
| ...item.layout, |
| backgroundStyle: { |
| color: '#ddd' |
| }, |
| x: {show: false, data: ['X1']}, |
| y: {show: false, data: ['Y1']}, |
| body: { |
| label: {fontSize: 10}, |
| data: [{ |
| coord: [0, 0], |
| value: `expect matrix on ${item.expect} due to\nl/r/t/b/w/h settings are:\n` |
| + JSON.stringify(item.layout) |
| }] |
| } |
| })), |
| |
| // z-order test |
| ...[{ |
| matrixLayout: { |
| top: 10, |
| left: 10, |
| width: 300, |
| height: 50, |
| }, |
| borderZ2: undefined, |
| }, { |
| matrixLayout: { |
| top: 'center', |
| left: 10, |
| width: 300, |
| height: 50, |
| }, |
| borderZ2: 500, |
| }].map(({matrixLayout, borderZ2}) => ({ |
| ...matrixLayout, |
| backgroundStyle: { |
| color: 'yellow', |
| borderColor: 'orange', |
| borderWidth: 5, |
| shadowColor: '#111', |
| shadowBlur: 15, |
| }, |
| borderZ2, |
| x: { |
| data: ['X1', 'X2', 'X3'], |
| dividerLineStyle: { |
| color: 'rgb(0,200,200)', |
| width: 5, |
| }, |
| }, |
| y: { |
| data: ['Y1', 'Y2', 'Y3'], |
| dividerLineStyle: { |
| color: 'rgb(100,150,150)', |
| width: 5, |
| }, |
| }, |
| body: { |
| label: { |
| fontSize: 10, |
| }, |
| itemStyle: { |
| borderWidth: 1, |
| borderColor: 'blue' |
| }, |
| data: [{ |
| coord: [0, 0], |
| itemStyle: { |
| borderColor: 'red', |
| borderWidth: 3 |
| }, |
| value: 'red border', |
| }, { |
| coord: [[1, 2], 0], |
| itemStyle: { |
| borderColor: 'green', |
| borderWidth: 3 |
| }, |
| mergeCells: true, |
| value: 'green border', |
| }, { |
| coord: [[1, 2], 2], |
| mergeCells: true, |
| label: { |
| position: 'insideRight' |
| }, |
| value: `borderZ2: ${borderZ2}`, |
| }] |
| }, |
| z: 10 |
| })) |
| ] |
| }; |
| |
| var chart = testHelper.create(echarts, 'main_self_layout', { |
| height: 200, |
| title: [ |
| 'matrix self layout test', |
| 'z-index test' |
| ], |
| option: option, |
| }); |
| }); |
| |
| </script> |
| |
| |
| |
| |
| |
| <script> |
| require([ |
| 'echarts', |
| ], function (echarts) { |
| const MatrixClampOption = { |
| none: 0, |
| all: 1, |
| body: 2, |
| corner: 3, |
| }; |
| |
| function makeMatrixOption({x, y, xLevels, yLevels}, {xShow, yShow}) { |
| return { |
| top: 90, |
| bottom: 100, |
| left: 160, |
| x: { |
| show: !!xShow, |
| data: x, |
| levels: xLevels ? xLevels : undefined, |
| itemStyle: {color: '#111'}, |
| label: {color: '#eee'}, |
| }, |
| y: { |
| show: !!yShow, |
| data: y, |
| levels: yLevels ? yLevels : undefined, |
| itemStyle: {color: '#111'}, |
| label: {color: '#eee'}, |
| }, |
| corner: { |
| itemStyle: {color: '#333'}, |
| label: {color: '#eee'}, |
| } |
| }; |
| } |
| |
| function makeFailedOption(failed) { |
| return { |
| id: 'success_or_fail', |
| type: 'text', |
| ignore: failed == null, |
| style: { |
| text: failed ? 'Case Failed' : 'Case Succeeded', |
| fontSize: 18, |
| fill: failed ? 'red' : 'green', |
| } |
| } |
| } |
| |
| const _matrixXYDataMap = { |
| test_d: { |
| desc: 'Different subtree have duplicated text, expect display the original text', |
| data: { |
| x: [{value: 'a', children: ['o', 'p', 'q']}, {value: 'b', children: ['o', 'p', 'q']}], |
| y: [{value: 'M', children: [new Date(), /a/]}] |
| }, |
| testList: [{ |
| testType: 'convertToLayout', |
| cases: [{ |
| input: ['o', 'Y1'], |
| expect: {matrixXYLocatorRange: [[0, 0], [1, 1]]}, |
| }, { |
| input: [3, 0], |
| expect: {matrixXYLocatorRange: [[3, 3], [0, 0]]}, |
| }, { |
| input: [7, 0], |
| expect: {matrixXYLocatorRange: [[3, 5], [0, 0]]}, |
| }, { |
| input: [7, 0], |
| opt: {clamp: MatrixClampOption.body}, |
| expect: {matrixXYLocatorRange: [[3, 5], [0, 0]]}, |
| }] |
| }] |
| }, |
| test_a: { |
| desc: 'matrix.y.data is empty array, expect no error.', |
| data: { |
| x: ['a', 'X2', null, 'd'], |
| y: [], |
| }, |
| testList: [{ |
| testType: 'convertToLayout', |
| cases: [{ |
| input: ['X2', null], |
| expect: {matrixXYLocatorRange: [[1, 1], [NaN, NaN]]}, |
| }, { |
| input: [null, 0], |
| expect: {matrixXYLocatorRange: [[NaN, NaN], [NaN, NaN]]}, |
| }, { |
| input: [null, null], |
| opt: {clamp: MatrixClampOption.body}, |
| expect: {matrixXYLocatorRange: [[0, 3], [NaN, NaN]]}, |
| }] |
| }] |
| }, |
| test_a2: { |
| desc: 'matrix.x.data is empty array, expect no error.', |
| data: { |
| x: [], |
| y: ['a', 'X2', null, 'd'], |
| }, |
| }, |
| test_b: { |
| desc: '[null] is allowed; number is illegal in matrix.x/y.data and replaced by auto-gen text.', |
| data: { |
| x: [null, null], |
| y: [1, 2, 3], |
| }, |
| testList: [{ |
| testType: 'convertToLayout', |
| cases: [{ |
| input: ['X1', 0], |
| expect: {matrixXYLocatorRange: [[1, 1], [0, 0]]}, |
| }, { |
| input: [-1, -1], |
| expect: {matrixXYLocatorRange: [[-1, -1], [-1, -1]]}, |
| }, { |
| input: [null, null], |
| opt: {clamp: MatrixClampOption.body}, |
| expect: {matrixXYLocatorRange: [[0, 1], [0, 2]]}, |
| }, { |
| input: [null, null], |
| opt: {clamp: MatrixClampOption.corner}, |
| expect: {matrixXYLocatorRange: [[-1, -1], [-1, -1]]}, |
| }, { |
| input: [0, 0], |
| opt: {clamp: MatrixClampOption.corner}, |
| expect: {matrixXYLocatorRange: [[-1, -1], [-1, -1]]}, |
| }] |
| }] |
| }, |
| test_c: { |
| desc: 'No matrix.x/y.data, expect no error', |
| data: { |
| x: [], |
| y: [], |
| }, |
| testList: [{ |
| testType: 'convertToLayout', |
| cases: [{ |
| input: [0, 0], |
| expect: {matrixXYLocatorRange: [[NaN, NaN], [NaN, NaN]]}, |
| }, { |
| input: [null, null], |
| opt: {clamp: MatrixClampOption.body}, |
| expect: {matrixXYLocatorRange: [[NaN, NaN], [NaN, NaN]]}, |
| }] |
| }] |
| }, |
| test_e: { |
| desc: 'All col/row width specified but not touch or overflow the bounary', |
| data: { |
| x: [{value: 'a1', size: 30}, {value: 'a2', size: 30}], |
| y: [{value: 'b1', size: 300}, {value: 'b2', size: 300}], |
| yLevels: [{levelSize: 50}] |
| }, |
| }, |
| test_f: { |
| desc: 'collect all from series.data (has null/NaN/undefined/illegal, expect display)', |
| data: { |
| x: undefined, |
| y: undefined, |
| seriesData: [ |
| ['fruit', undefined, 1223], |
| ['bread', 'good', 323], |
| ['milk', 'good', 142], |
| [null, 'medium', 63], |
| ['bread', 'medium', 91], |
| ['milk', 9999, 45], |
| ['fruit', NaN, 55], |
| ['bread', 'bad', 15], |
| ['milk', 'bad', 53], |
| ], |
| }, |
| }, |
| test_g: { |
| desc: 'no series.data and no matrix.x/y', |
| data: { |
| x: undefined, |
| y: undefined, |
| seriesData: [], |
| }, |
| }, |
| }; |
| |
| let _ctx = { |
| xyData: 'test_d', |
| testResult: null, // {result: unknown, failed: boolean} |
| xShow: true, |
| yShow: true, |
| convertFromPixelOpt: null, |
| }; |
| |
| function updateView() { |
| const option = { |
| matrix: makeMatrixOption(_matrixXYDataMap[_ctx.xyData].data, _ctx), |
| series: { |
| data: _matrixXYDataMap[_ctx.xyData].data.seriesData |
| }, |
| }; |
| chart.setOption(option, {replaceMerge: 'matrix'}); |
| |
| chart.setOption({ |
| graphic: { |
| elements: [{ |
| id: 'convert_result', |
| style: { |
| text: _ctx.testResult ? _ctx.testResult.result : '', |
| } |
| }, { |
| id: 'desc_text', |
| style: { |
| text: '--- expect ---\n' + (_matrixXYDataMap[_ctx.xyData].desc || '') |
| + '\n--- current matrix data ---\n' |
| + testHelper.printObject( |
| { |
| x: { |
| data: _matrixXYDataMap[_ctx.xyData].data.x, |
| levels: _matrixXYDataMap[_ctx.xyData].data.xLevels, |
| }, |
| y: { |
| data: _matrixXYDataMap[_ctx.xyData].data.y, |
| levels: _matrixXYDataMap[_ctx.xyData].data.yLevels, |
| }, |
| }, |
| {lineBreakMaxColumn: 150} |
| ) |
| + '\n--- current series data ---\n' + ( |
| _matrixXYDataMap[_ctx.xyData].data.seriesData |
| ? testHelper.printObject( |
| _matrixXYDataMap[_ctx.xyData].data.seriesData, |
| {lineBreakMaxColumn: 30} |
| ) |
| : 'undefined' |
| ) |
| } |
| }, |
| makeFailedOption(_ctx.testResult ? !!_ctx.testResult.failed : undefined) |
| ] |
| } |
| }); |
| } |
| |
| const option = { |
| tooltip: {}, |
| backgroundColor: '#aee', |
| matrix: makeMatrixOption(_matrixXYDataMap[_ctx.xyData].data, _ctx), |
| series: { |
| type: 'scatter', |
| coordinateSystem: 'matrix', |
| symbolSize: 20, |
| encode: {label: 2}, |
| label: {show: true}, |
| data: _matrixXYDataMap[_ctx.xyData].data.seriesData |
| }, |
| graphic: { |
| elements: [{ |
| bottom: 5, |
| left: 'center', |
| id: 'convert_result', |
| type: 'text', |
| style: { |
| text: '', |
| fill: 'blue', |
| fontSize: 11, |
| }, |
| silent: true |
| }, { |
| left: 5, |
| top: 5, |
| id: 'desc_text', |
| type: 'text', |
| style: { |
| fontSize: 12, |
| fill: '#333', |
| }, |
| silent: true |
| }, { |
| right: 5, |
| top: 5, |
| id: 'success_or_fail', |
| type: 'text', |
| style: { |
| fontSize: 20, |
| fill: 'red', |
| }, |
| silent: true |
| }] |
| } |
| }; |
| |
| var chart = testHelper.create(echarts, 'main_dim_data_edge_cases', { |
| title: [ |
| 'edge case', |
| '**click** on matrix inside and outside to test clamp.' |
| ], |
| option: option, |
| height: 400, |
| inputsStyle: 'compact', |
| inputs: [{ |
| text: 'test cases:', |
| type: 'select', |
| options: Object.keys(_matrixXYDataMap).map(key => { |
| let text = _matrixXYDataMap[key].desc; |
| const MAX_STR = 100; |
| if (text.length > MAX_STR) { |
| text = text.slice(0, MAX_STR) + ' ...'; |
| } |
| return {text: text, value: key}; |
| }), |
| onchange() { |
| const key = this.value; |
| _ctx.xyData = key; |
| _ctx.testResult = null; |
| chart.__testHelper.switchGroup(key); |
| updateView(); |
| } |
| }, { |
| type: 'br', |
| }, { |
| text: 'matrix.x show:', |
| type: 'select', |
| values: [true, false], |
| onchange() { |
| _ctx.xShow = this.value; |
| updateView(); |
| } |
| }, { |
| text: 'matrix.y show:', |
| type: 'select', |
| values: [true, false], |
| onchange() { |
| _ctx.yShow = this.value; |
| updateView(); |
| } |
| }, { |
| text: 'convertFromPixel opt:', |
| type: 'select', |
| options: [ |
| {value: undefined}, |
| {text: 'clamp body', value: {clamp: MatrixClampOption.body}}, |
| {text: 'clamp corner', value: {clamp: MatrixClampOption.corner}}, |
| {text: 'clamp all', value: {clamp: MatrixClampOption.all}}, |
| {text: 'clamp none', value: {clamp: MatrixClampOption.none}}, |
| ], |
| onchange() { |
| _ctx.convertFromPixelOpt = this.value; |
| } |
| }, { |
| type: 'groupset', |
| inputsStyle: 'compact', |
| inputsHeight: 70, |
| groups: Object.keys(_matrixXYDataMap).map(key => { |
| const textList = _matrixXYDataMap[key].testList || []; |
| const inputs = []; |
| textList.forEach(testItem => { |
| if (testItem.testType === 'convertToLayout') { |
| const cases = testItem.cases; |
| cases.forEach(caseItem => { |
| inputs.push({ |
| text: `convertToLayout(${testHelper.printObject(caseItem.input)}, ${testHelper.printObject(caseItem.opt)})`, |
| onclick() { |
| let expect = caseItem.expect; |
| let failed = false; |
| let actual; |
| try { |
| actual = chart.convertToLayout({matrixIndex: 0}, caseItem.input, caseItem.opt); |
| console.log(actual); |
| if (!numEq(expect.matrixXYLocatorRange[0][0], actual.matrixXYLocatorRange[0][0]) |
| || !numEq(expect.matrixXYLocatorRange[0][1], actual.matrixXYLocatorRange[0][1]) |
| || !numEq(expect.matrixXYLocatorRange[1][0], actual.matrixXYLocatorRange[1][0]) |
| || !numEq(expect.matrixXYLocatorRange[1][1], actual.matrixXYLocatorRange[1][1]) |
| ) { |
| failed = true; |
| } |
| } |
| catch (err) { |
| console.error(err); |
| failed = true; |
| } |
| const result = 'convertToLayout result: ' + testHelper.printObject(actual); |
| _ctx.testResult = {result, failed}; |
| updateView(); |
| } |
| }); |
| }); |
| } |
| else { |
| throw new Error('illegal'); |
| } |
| }); |
| |
| return { |
| id: key, |
| text: '[' + key + '] test cases:', |
| inputs, |
| }; |
| }) |
| }] // End of inputs |
| }); |
| |
| if (chart) { |
| updateView(); |
| |
| chart.getZr().on('click', function (event) { |
| const point = [event.offsetX, event.offsetY]; |
| const data = chart.convertFromPixel({matrixIndex: 0}, point, _ctx.convertFromPixelOpt); |
| const layout = chart.convertToLayout({matrixIndex: 0}, data); |
| |
| _ctx.testResult = { |
| result: 'convertFromPixel result: ' + testHelper.printObject(data) + '\n' |
| + 'Then use it convertToLayout result: ' + testHelper.printObject(layout), |
| failed: false |
| }; |
| updateView(); |
| }); |
| } |
| }); |
| |
| function eqNaN(value) { |
| return value !== value; |
| } |
| |
| function numEq(expect, actual) { |
| return eqNaN(expect) |
| ? eqNaN(actual) |
| : expect === actual; |
| } |
| </script> |
| |
| |
| |
| </body> |
| </html> |
| |