DataView.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. /**
  20. * AUTO-GENERATED FILE. DO NOT MODIFY.
  21. */
  22. /*
  23. * Licensed to the Apache Software Foundation (ASF) under one
  24. * or more contributor license agreements. See the NOTICE file
  25. * distributed with this work for additional information
  26. * regarding copyright ownership. The ASF licenses this file
  27. * to you under the Apache License, Version 2.0 (the
  28. * "License"); you may not use this file except in compliance
  29. * with the License. You may obtain a copy of the License at
  30. *
  31. * http://www.apache.org/licenses/LICENSE-2.0
  32. *
  33. * Unless required by applicable law or agreed to in writing,
  34. * software distributed under the License is distributed on an
  35. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  36. * KIND, either express or implied. See the License for the
  37. * specific language governing permissions and limitations
  38. * under the License.
  39. */
  40. import { __extends } from "tslib";
  41. /* global document */
  42. import * as echarts from '../../../core/echarts.js';
  43. import * as zrUtil from 'zrender/lib/core/util.js';
  44. import { ToolboxFeature } from '../featureManager.js';
  45. import { addEventListener } from 'zrender/lib/core/event.js';
  46. import { warn } from '../../../util/log.js';
  47. /* global document */
  48. var BLOCK_SPLITER = new Array(60).join('-');
  49. var ITEM_SPLITER = '\t';
  50. /**
  51. * Group series into two types
  52. * 1. on category axis, like line, bar
  53. * 2. others, like scatter, pie
  54. */
  55. function groupSeries(ecModel) {
  56. var seriesGroupByCategoryAxis = {};
  57. var otherSeries = [];
  58. var meta = [];
  59. ecModel.eachRawSeries(function (seriesModel) {
  60. var coordSys = seriesModel.coordinateSystem;
  61. if (coordSys && (coordSys.type === 'cartesian2d' || coordSys.type === 'polar')) {
  62. // TODO: TYPE Consider polar? Include polar may increase unecessary bundle size.
  63. var baseAxis = coordSys.getBaseAxis();
  64. if (baseAxis.type === 'category') {
  65. var key = baseAxis.dim + '_' + baseAxis.index;
  66. if (!seriesGroupByCategoryAxis[key]) {
  67. seriesGroupByCategoryAxis[key] = {
  68. categoryAxis: baseAxis,
  69. valueAxis: coordSys.getOtherAxis(baseAxis),
  70. series: []
  71. };
  72. meta.push({
  73. axisDim: baseAxis.dim,
  74. axisIndex: baseAxis.index
  75. });
  76. }
  77. seriesGroupByCategoryAxis[key].series.push(seriesModel);
  78. } else {
  79. otherSeries.push(seriesModel);
  80. }
  81. } else {
  82. otherSeries.push(seriesModel);
  83. }
  84. });
  85. return {
  86. seriesGroupByCategoryAxis: seriesGroupByCategoryAxis,
  87. other: otherSeries,
  88. meta: meta
  89. };
  90. }
  91. /**
  92. * Assemble content of series on cateogory axis
  93. * @inner
  94. */
  95. function assembleSeriesWithCategoryAxis(groups) {
  96. var tables = [];
  97. zrUtil.each(groups, function (group, key) {
  98. var categoryAxis = group.categoryAxis;
  99. var valueAxis = group.valueAxis;
  100. var valueAxisDim = valueAxis.dim;
  101. var headers = [' '].concat(zrUtil.map(group.series, function (series) {
  102. return series.name;
  103. }));
  104. // @ts-ignore TODO Polar
  105. var columns = [categoryAxis.model.getCategories()];
  106. zrUtil.each(group.series, function (series) {
  107. var rawData = series.getRawData();
  108. columns.push(series.getRawData().mapArray(rawData.mapDimension(valueAxisDim), function (val) {
  109. return val;
  110. }));
  111. });
  112. // Assemble table content
  113. var lines = [headers.join(ITEM_SPLITER)];
  114. for (var i = 0; i < columns[0].length; i++) {
  115. var items = [];
  116. for (var j = 0; j < columns.length; j++) {
  117. items.push(columns[j][i]);
  118. }
  119. lines.push(items.join(ITEM_SPLITER));
  120. }
  121. tables.push(lines.join('\n'));
  122. });
  123. return tables.join('\n\n' + BLOCK_SPLITER + '\n\n');
  124. }
  125. /**
  126. * Assemble content of other series
  127. */
  128. function assembleOtherSeries(series) {
  129. return zrUtil.map(series, function (series) {
  130. var data = series.getRawData();
  131. var lines = [series.name];
  132. var vals = [];
  133. data.each(data.dimensions, function () {
  134. var argLen = arguments.length;
  135. var dataIndex = arguments[argLen - 1];
  136. var name = data.getName(dataIndex);
  137. for (var i = 0; i < argLen - 1; i++) {
  138. vals[i] = arguments[i];
  139. }
  140. lines.push((name ? name + ITEM_SPLITER : '') + vals.join(ITEM_SPLITER));
  141. });
  142. return lines.join('\n');
  143. }).join('\n\n' + BLOCK_SPLITER + '\n\n');
  144. }
  145. function getContentFromModel(ecModel) {
  146. var result = groupSeries(ecModel);
  147. return {
  148. value: zrUtil.filter([assembleSeriesWithCategoryAxis(result.seriesGroupByCategoryAxis), assembleOtherSeries(result.other)], function (str) {
  149. return !!str.replace(/[\n\t\s]/g, '');
  150. }).join('\n\n' + BLOCK_SPLITER + '\n\n'),
  151. meta: result.meta
  152. };
  153. }
  154. function trim(str) {
  155. return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
  156. }
  157. /**
  158. * If a block is tsv format
  159. */
  160. function isTSVFormat(block) {
  161. // Simple method to find out if a block is tsv format
  162. var firstLine = block.slice(0, block.indexOf('\n'));
  163. if (firstLine.indexOf(ITEM_SPLITER) >= 0) {
  164. return true;
  165. }
  166. }
  167. var itemSplitRegex = new RegExp('[' + ITEM_SPLITER + ']+', 'g');
  168. /**
  169. * @param {string} tsv
  170. * @return {Object}
  171. */
  172. function parseTSVContents(tsv) {
  173. var tsvLines = tsv.split(/\n+/g);
  174. var headers = trim(tsvLines.shift()).split(itemSplitRegex);
  175. var categories = [];
  176. var series = zrUtil.map(headers, function (header) {
  177. return {
  178. name: header,
  179. data: []
  180. };
  181. });
  182. for (var i = 0; i < tsvLines.length; i++) {
  183. var items = trim(tsvLines[i]).split(itemSplitRegex);
  184. categories.push(items.shift());
  185. for (var j = 0; j < items.length; j++) {
  186. series[j] && (series[j].data[i] = items[j]);
  187. }
  188. }
  189. return {
  190. series: series,
  191. categories: categories
  192. };
  193. }
  194. function parseListContents(str) {
  195. var lines = str.split(/\n+/g);
  196. var seriesName = trim(lines.shift());
  197. var data = [];
  198. for (var i = 0; i < lines.length; i++) {
  199. // if line is empty, ignore it.
  200. // there is a case that a user forgot to delete `\n`.
  201. var line = trim(lines[i]);
  202. if (!line) {
  203. continue;
  204. }
  205. var items = line.split(itemSplitRegex);
  206. var name_1 = '';
  207. var value = void 0;
  208. var hasName = false;
  209. if (isNaN(items[0])) {
  210. // First item is name
  211. hasName = true;
  212. name_1 = items[0];
  213. items = items.slice(1);
  214. data[i] = {
  215. name: name_1,
  216. value: []
  217. };
  218. value = data[i].value;
  219. } else {
  220. value = data[i] = [];
  221. }
  222. for (var j = 0; j < items.length; j++) {
  223. value.push(+items[j]);
  224. }
  225. if (value.length === 1) {
  226. hasName ? data[i].value = value[0] : data[i] = value[0];
  227. }
  228. }
  229. return {
  230. name: seriesName,
  231. data: data
  232. };
  233. }
  234. function parseContents(str, blockMetaList) {
  235. var blocks = str.split(new RegExp('\n*' + BLOCK_SPLITER + '\n*', 'g'));
  236. var newOption = {
  237. series: []
  238. };
  239. zrUtil.each(blocks, function (block, idx) {
  240. if (isTSVFormat(block)) {
  241. var result = parseTSVContents(block);
  242. var blockMeta = blockMetaList[idx];
  243. var axisKey = blockMeta.axisDim + 'Axis';
  244. if (blockMeta) {
  245. newOption[axisKey] = newOption[axisKey] || [];
  246. newOption[axisKey][blockMeta.axisIndex] = {
  247. data: result.categories
  248. };
  249. newOption.series = newOption.series.concat(result.series);
  250. }
  251. } else {
  252. var result = parseListContents(block);
  253. newOption.series.push(result);
  254. }
  255. });
  256. return newOption;
  257. }
  258. var DataView = /** @class */function (_super) {
  259. __extends(DataView, _super);
  260. function DataView() {
  261. return _super !== null && _super.apply(this, arguments) || this;
  262. }
  263. DataView.prototype.onclick = function (ecModel, api) {
  264. // FIXME: better way?
  265. setTimeout(function () {
  266. api.dispatchAction({
  267. type: 'hideTip'
  268. });
  269. });
  270. var container = api.getDom();
  271. var model = this.model;
  272. if (this._dom) {
  273. container.removeChild(this._dom);
  274. }
  275. var root = document.createElement('div');
  276. // use padding to avoid 5px whitespace
  277. root.style.cssText = 'position:absolute;top:0;bottom:0;left:0;right:0;padding:5px';
  278. root.style.backgroundColor = model.get('backgroundColor') || '#fff';
  279. // Create elements
  280. var header = document.createElement('h4');
  281. var lang = model.get('lang') || [];
  282. header.innerHTML = lang[0] || model.get('title');
  283. header.style.cssText = 'margin:10px 20px';
  284. header.style.color = model.get('textColor');
  285. var viewMain = document.createElement('div');
  286. var textarea = document.createElement('textarea');
  287. viewMain.style.cssText = 'overflow:auto';
  288. var optionToContent = model.get('optionToContent');
  289. var contentToOption = model.get('contentToOption');
  290. var result = getContentFromModel(ecModel);
  291. if (zrUtil.isFunction(optionToContent)) {
  292. var htmlOrDom = optionToContent(api.getOption());
  293. if (zrUtil.isString(htmlOrDom)) {
  294. viewMain.innerHTML = htmlOrDom;
  295. } else if (zrUtil.isDom(htmlOrDom)) {
  296. viewMain.appendChild(htmlOrDom);
  297. }
  298. } else {
  299. // Use default textarea
  300. textarea.readOnly = model.get('readOnly');
  301. var style = textarea.style;
  302. // eslint-disable-next-line max-len
  303. style.cssText = 'display:block;width:100%;height:100%;font-family:monospace;font-size:14px;line-height:1.6rem;resize:none;box-sizing:border-box;outline:none';
  304. style.color = model.get('textColor');
  305. style.borderColor = model.get('textareaBorderColor');
  306. style.backgroundColor = model.get('textareaColor');
  307. textarea.value = result.value;
  308. viewMain.appendChild(textarea);
  309. }
  310. var blockMetaList = result.meta;
  311. var buttonContainer = document.createElement('div');
  312. buttonContainer.style.cssText = 'position:absolute;bottom:5px;left:0;right:0';
  313. // eslint-disable-next-line max-len
  314. var buttonStyle = 'float:right;margin-right:20px;border:none;cursor:pointer;padding:2px 5px;font-size:12px;border-radius:3px';
  315. var closeButton = document.createElement('div');
  316. var refreshButton = document.createElement('div');
  317. buttonStyle += ';background-color:' + model.get('buttonColor');
  318. buttonStyle += ';color:' + model.get('buttonTextColor');
  319. var self = this;
  320. function close() {
  321. container.removeChild(root);
  322. self._dom = null;
  323. }
  324. addEventListener(closeButton, 'click', close);
  325. addEventListener(refreshButton, 'click', function () {
  326. if (contentToOption == null && optionToContent != null || contentToOption != null && optionToContent == null) {
  327. if (process.env.NODE_ENV !== 'production') {
  328. // eslint-disable-next-line
  329. warn('It seems you have just provided one of `contentToOption` and `optionToContent` functions but missed the other one. Data change is ignored.');
  330. }
  331. close();
  332. return;
  333. }
  334. var newOption;
  335. try {
  336. if (zrUtil.isFunction(contentToOption)) {
  337. newOption = contentToOption(viewMain, api.getOption());
  338. } else {
  339. newOption = parseContents(textarea.value, blockMetaList);
  340. }
  341. } catch (e) {
  342. close();
  343. throw new Error('Data view format error ' + e);
  344. }
  345. if (newOption) {
  346. api.dispatchAction({
  347. type: 'changeDataView',
  348. newOption: newOption
  349. });
  350. }
  351. close();
  352. });
  353. closeButton.innerHTML = lang[1];
  354. refreshButton.innerHTML = lang[2];
  355. refreshButton.style.cssText = closeButton.style.cssText = buttonStyle;
  356. !model.get('readOnly') && buttonContainer.appendChild(refreshButton);
  357. buttonContainer.appendChild(closeButton);
  358. root.appendChild(header);
  359. root.appendChild(viewMain);
  360. root.appendChild(buttonContainer);
  361. viewMain.style.height = container.clientHeight - 80 + 'px';
  362. container.appendChild(root);
  363. this._dom = root;
  364. };
  365. DataView.prototype.remove = function (ecModel, api) {
  366. this._dom && api.getDom().removeChild(this._dom);
  367. };
  368. DataView.prototype.dispose = function (ecModel, api) {
  369. this.remove(ecModel, api);
  370. };
  371. DataView.getDefaultOption = function (ecModel) {
  372. var defaultOption = {
  373. show: true,
  374. readOnly: false,
  375. optionToContent: null,
  376. contentToOption: null,
  377. // eslint-disable-next-line
  378. icon: 'M17.5,17.3H33 M17.5,17.3H33 M45.4,29.5h-28 M11.5,2v56H51V14.8L38.4,2H11.5z M38.4,2.2v12.7H51 M45.4,41.7h-28',
  379. title: ecModel.getLocaleModel().get(['toolbox', 'dataView', 'title']),
  380. lang: ecModel.getLocaleModel().get(['toolbox', 'dataView', 'lang']),
  381. backgroundColor: '#fff',
  382. textColor: '#000',
  383. textareaColor: '#fff',
  384. textareaBorderColor: '#333',
  385. buttonColor: '#c23531',
  386. buttonTextColor: '#fff'
  387. };
  388. return defaultOption;
  389. };
  390. return DataView;
  391. }(ToolboxFeature);
  392. /**
  393. * @inner
  394. */
  395. function tryMergeDataOption(newData, originalData) {
  396. return zrUtil.map(newData, function (newVal, idx) {
  397. var original = originalData && originalData[idx];
  398. if (zrUtil.isObject(original) && !zrUtil.isArray(original)) {
  399. var newValIsObject = zrUtil.isObject(newVal) && !zrUtil.isArray(newVal);
  400. if (!newValIsObject) {
  401. newVal = {
  402. value: newVal
  403. };
  404. }
  405. // original data has name but new data has no name
  406. var shouldDeleteName = original.name != null && newVal.name == null;
  407. // Original data has option
  408. newVal = zrUtil.defaults(newVal, original);
  409. shouldDeleteName && delete newVal.name;
  410. return newVal;
  411. } else {
  412. return newVal;
  413. }
  414. });
  415. }
  416. // TODO: SELF REGISTERED.
  417. echarts.registerAction({
  418. type: 'changeDataView',
  419. event: 'dataViewChanged',
  420. update: 'prepareAndUpdate'
  421. }, function (payload, ecModel) {
  422. var newSeriesOptList = [];
  423. zrUtil.each(payload.newOption.series, function (seriesOpt) {
  424. var seriesModel = ecModel.getSeriesByName(seriesOpt.name)[0];
  425. if (!seriesModel) {
  426. // New created series
  427. // Geuss the series type
  428. newSeriesOptList.push(zrUtil.extend({
  429. // Default is scatter
  430. type: 'scatter'
  431. }, seriesOpt));
  432. } else {
  433. var originalData = seriesModel.get('data');
  434. newSeriesOptList.push({
  435. name: seriesOpt.name,
  436. data: tryMergeDataOption(seriesOpt.data, originalData)
  437. });
  438. }
  439. });
  440. ecModel.mergeOption(zrUtil.defaults({
  441. series: newSeriesOptList
  442. }, payload.newOption));
  443. });
  444. export default DataView;