DataView.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  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. })); // @ts-ignore TODO Polar
  104. var columns = [categoryAxis.model.getCategories()];
  105. zrUtil.each(group.series, function (series) {
  106. var rawData = series.getRawData();
  107. columns.push(series.getRawData().mapArray(rawData.mapDimension(valueAxisDim), function (val) {
  108. return val;
  109. }));
  110. }); // Assemble table content
  111. var lines = [headers.join(ITEM_SPLITER)];
  112. for (var i = 0; i < columns[0].length; i++) {
  113. var items = [];
  114. for (var j = 0; j < columns.length; j++) {
  115. items.push(columns[j][i]);
  116. }
  117. lines.push(items.join(ITEM_SPLITER));
  118. }
  119. tables.push(lines.join('\n'));
  120. });
  121. return tables.join('\n\n' + BLOCK_SPLITER + '\n\n');
  122. }
  123. /**
  124. * Assemble content of other series
  125. */
  126. function assembleOtherSeries(series) {
  127. return zrUtil.map(series, function (series) {
  128. var data = series.getRawData();
  129. var lines = [series.name];
  130. var vals = [];
  131. data.each(data.dimensions, function () {
  132. var argLen = arguments.length;
  133. var dataIndex = arguments[argLen - 1];
  134. var name = data.getName(dataIndex);
  135. for (var i = 0; i < argLen - 1; i++) {
  136. vals[i] = arguments[i];
  137. }
  138. lines.push((name ? name + ITEM_SPLITER : '') + vals.join(ITEM_SPLITER));
  139. });
  140. return lines.join('\n');
  141. }).join('\n\n' + BLOCK_SPLITER + '\n\n');
  142. }
  143. function getContentFromModel(ecModel) {
  144. var result = groupSeries(ecModel);
  145. return {
  146. value: zrUtil.filter([assembleSeriesWithCategoryAxis(result.seriesGroupByCategoryAxis), assembleOtherSeries(result.other)], function (str) {
  147. return !!str.replace(/[\n\t\s]/g, '');
  148. }).join('\n\n' + BLOCK_SPLITER + '\n\n'),
  149. meta: result.meta
  150. };
  151. }
  152. function trim(str) {
  153. return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
  154. }
  155. /**
  156. * If a block is tsv format
  157. */
  158. function isTSVFormat(block) {
  159. // Simple method to find out if a block is tsv format
  160. var firstLine = block.slice(0, block.indexOf('\n'));
  161. if (firstLine.indexOf(ITEM_SPLITER) >= 0) {
  162. return true;
  163. }
  164. }
  165. var itemSplitRegex = new RegExp('[' + ITEM_SPLITER + ']+', 'g');
  166. /**
  167. * @param {string} tsv
  168. * @return {Object}
  169. */
  170. function parseTSVContents(tsv) {
  171. var tsvLines = tsv.split(/\n+/g);
  172. var headers = trim(tsvLines.shift()).split(itemSplitRegex);
  173. var categories = [];
  174. var series = zrUtil.map(headers, function (header) {
  175. return {
  176. name: header,
  177. data: []
  178. };
  179. });
  180. for (var i = 0; i < tsvLines.length; i++) {
  181. var items = trim(tsvLines[i]).split(itemSplitRegex);
  182. categories.push(items.shift());
  183. for (var j = 0; j < items.length; j++) {
  184. series[j] && (series[j].data[i] = items[j]);
  185. }
  186. }
  187. return {
  188. series: series,
  189. categories: categories
  190. };
  191. }
  192. function parseListContents(str) {
  193. var lines = str.split(/\n+/g);
  194. var seriesName = trim(lines.shift());
  195. var data = [];
  196. for (var i = 0; i < lines.length; i++) {
  197. // if line is empty, ignore it.
  198. // there is a case that a user forgot to delete `\n`.
  199. var line = trim(lines[i]);
  200. if (!line) {
  201. continue;
  202. }
  203. var items = line.split(itemSplitRegex);
  204. var name_1 = '';
  205. var value = void 0;
  206. var hasName = false;
  207. if (isNaN(items[0])) {
  208. // First item is name
  209. hasName = true;
  210. name_1 = items[0];
  211. items = items.slice(1);
  212. data[i] = {
  213. name: name_1,
  214. value: []
  215. };
  216. value = data[i].value;
  217. } else {
  218. value = data[i] = [];
  219. }
  220. for (var j = 0; j < items.length; j++) {
  221. value.push(+items[j]);
  222. }
  223. if (value.length === 1) {
  224. hasName ? data[i].value = value[0] : data[i] = value[0];
  225. }
  226. }
  227. return {
  228. name: seriesName,
  229. data: data
  230. };
  231. }
  232. function parseContents(str, blockMetaList) {
  233. var blocks = str.split(new RegExp('\n*' + BLOCK_SPLITER + '\n*', 'g'));
  234. var newOption = {
  235. series: []
  236. };
  237. zrUtil.each(blocks, function (block, idx) {
  238. if (isTSVFormat(block)) {
  239. var result = parseTSVContents(block);
  240. var blockMeta = blockMetaList[idx];
  241. var axisKey = blockMeta.axisDim + 'Axis';
  242. if (blockMeta) {
  243. newOption[axisKey] = newOption[axisKey] || [];
  244. newOption[axisKey][blockMeta.axisIndex] = {
  245. data: result.categories
  246. };
  247. newOption.series = newOption.series.concat(result.series);
  248. }
  249. } else {
  250. var result = parseListContents(block);
  251. newOption.series.push(result);
  252. }
  253. });
  254. return newOption;
  255. }
  256. var DataView =
  257. /** @class */
  258. 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'); // use padding to avoid 5px whitespace
  276. root.style.cssText = 'position:absolute;top:0;bottom:0;left:0;right:0;padding:5px';
  277. root.style.backgroundColor = model.get('backgroundColor') || '#fff'; // Create elements
  278. var header = document.createElement('h4');
  279. var lang = model.get('lang') || [];
  280. header.innerHTML = lang[0] || model.get('title');
  281. header.style.cssText = 'margin:10px 20px';
  282. header.style.color = model.get('textColor');
  283. var viewMain = document.createElement('div');
  284. var textarea = document.createElement('textarea');
  285. viewMain.style.cssText = 'overflow:auto';
  286. var optionToContent = model.get('optionToContent');
  287. var contentToOption = model.get('contentToOption');
  288. var result = getContentFromModel(ecModel);
  289. if (zrUtil.isFunction(optionToContent)) {
  290. var htmlOrDom = optionToContent(api.getOption());
  291. if (zrUtil.isString(htmlOrDom)) {
  292. viewMain.innerHTML = htmlOrDom;
  293. } else if (zrUtil.isDom(htmlOrDom)) {
  294. viewMain.appendChild(htmlOrDom);
  295. }
  296. } else {
  297. // Use default textarea
  298. textarea.readOnly = model.get('readOnly');
  299. var style = textarea.style; // eslint-disable-next-line max-len
  300. 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';
  301. style.color = model.get('textColor');
  302. style.borderColor = model.get('textareaBorderColor');
  303. style.backgroundColor = model.get('textareaColor');
  304. textarea.value = result.value;
  305. viewMain.appendChild(textarea);
  306. }
  307. var blockMetaList = result.meta;
  308. var buttonContainer = document.createElement('div');
  309. buttonContainer.style.cssText = 'position:absolute;bottom:5px;left:0;right:0'; // eslint-disable-next-line max-len
  310. var buttonStyle = 'float:right;margin-right:20px;border:none;cursor:pointer;padding:2px 5px;font-size:12px;border-radius:3px';
  311. var closeButton = document.createElement('div');
  312. var refreshButton = document.createElement('div');
  313. buttonStyle += ';background-color:' + model.get('buttonColor');
  314. buttonStyle += ';color:' + model.get('buttonTextColor');
  315. var self = this;
  316. function close() {
  317. container.removeChild(root);
  318. self._dom = null;
  319. }
  320. addEventListener(closeButton, 'click', close);
  321. addEventListener(refreshButton, 'click', function () {
  322. if (contentToOption == null && optionToContent != null || contentToOption != null && optionToContent == null) {
  323. if (process.env.NODE_ENV !== 'production') {
  324. // eslint-disable-next-line
  325. warn('It seems you have just provided one of `contentToOption` and `optionToContent` functions but missed the other one. Data change is ignored.');
  326. }
  327. close();
  328. return;
  329. }
  330. var newOption;
  331. try {
  332. if (zrUtil.isFunction(contentToOption)) {
  333. newOption = contentToOption(viewMain, api.getOption());
  334. } else {
  335. newOption = parseContents(textarea.value, blockMetaList);
  336. }
  337. } catch (e) {
  338. close();
  339. throw new Error('Data view format error ' + e);
  340. }
  341. if (newOption) {
  342. api.dispatchAction({
  343. type: 'changeDataView',
  344. newOption: newOption
  345. });
  346. }
  347. close();
  348. });
  349. closeButton.innerHTML = lang[1];
  350. refreshButton.innerHTML = lang[2];
  351. refreshButton.style.cssText = closeButton.style.cssText = buttonStyle;
  352. !model.get('readOnly') && buttonContainer.appendChild(refreshButton);
  353. buttonContainer.appendChild(closeButton);
  354. root.appendChild(header);
  355. root.appendChild(viewMain);
  356. root.appendChild(buttonContainer);
  357. viewMain.style.height = container.clientHeight - 80 + 'px';
  358. container.appendChild(root);
  359. this._dom = root;
  360. };
  361. DataView.prototype.remove = function (ecModel, api) {
  362. this._dom && api.getDom().removeChild(this._dom);
  363. };
  364. DataView.prototype.dispose = function (ecModel, api) {
  365. this.remove(ecModel, api);
  366. };
  367. DataView.getDefaultOption = function (ecModel) {
  368. var defaultOption = {
  369. show: true,
  370. readOnly: false,
  371. optionToContent: null,
  372. contentToOption: null,
  373. // eslint-disable-next-line
  374. 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',
  375. title: ecModel.getLocaleModel().get(['toolbox', 'dataView', 'title']),
  376. lang: ecModel.getLocaleModel().get(['toolbox', 'dataView', 'lang']),
  377. backgroundColor: '#fff',
  378. textColor: '#000',
  379. textareaColor: '#fff',
  380. textareaBorderColor: '#333',
  381. buttonColor: '#c23531',
  382. buttonTextColor: '#fff'
  383. };
  384. return defaultOption;
  385. };
  386. return DataView;
  387. }(ToolboxFeature);
  388. /**
  389. * @inner
  390. */
  391. function tryMergeDataOption(newData, originalData) {
  392. return zrUtil.map(newData, function (newVal, idx) {
  393. var original = originalData && originalData[idx];
  394. if (zrUtil.isObject(original) && !zrUtil.isArray(original)) {
  395. var newValIsObject = zrUtil.isObject(newVal) && !zrUtil.isArray(newVal);
  396. if (!newValIsObject) {
  397. newVal = {
  398. value: newVal
  399. };
  400. } // original data has name but new data has no name
  401. var shouldDeleteName = original.name != null && newVal.name == null; // Original data has option
  402. newVal = zrUtil.defaults(newVal, original);
  403. shouldDeleteName && delete newVal.name;
  404. return newVal;
  405. } else {
  406. return newVal;
  407. }
  408. });
  409. } // TODO: SELF REGISTERED.
  410. echarts.registerAction({
  411. type: 'changeDataView',
  412. event: 'dataViewChanged',
  413. update: 'prepareAndUpdate'
  414. }, function (payload, ecModel) {
  415. var newSeriesOptList = [];
  416. zrUtil.each(payload.newOption.series, function (seriesOpt) {
  417. var seriesModel = ecModel.getSeriesByName(seriesOpt.name)[0];
  418. if (!seriesModel) {
  419. // New created series
  420. // Geuss the series type
  421. newSeriesOptList.push(zrUtil.extend({
  422. // Default is scatter
  423. type: 'scatter'
  424. }, seriesOpt));
  425. } else {
  426. var originalData = seriesModel.get('data');
  427. newSeriesOptList.push({
  428. name: seriesOpt.name,
  429. data: tryMergeDataOption(seriesOpt.data, originalData)
  430. });
  431. }
  432. });
  433. ecModel.mergeOption(zrUtil.defaults({
  434. series: newSeriesOptList
  435. }, payload.newOption));
  436. });
  437. export default DataView;