DataView.js 14 KB

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