f2chart.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. import { getColorValue } from './chart';
  2. import { isTypeof, objectMerge } from '@/components/thrid/em-element-ui/src/tools/utils';
  3. export function formatLegendData(params) {
  4. let result = '',
  5. number = 4,
  6. name = params.name.toString(),
  7. str = name.replace(/^\s+|\s+$/g, ''),
  8. len = str.length;
  9. number = len > number ? Math.ceil(len / 2) : number;
  10. for (let i = 0; i < len; i++) {
  11. if (i > 0 && i < len && (i % number) == 0) {
  12. result += '\n';
  13. }
  14. result += str.charAt(i);
  15. }
  16. //str.replace(/(?=(?:.{4})+$)/g, '\n');
  17. return result;
  18. }
  19. export function debounce(func, wait, immediate) {
  20. let timeout, args, context, timestamp, result
  21. const later = function () {
  22. // 据上一次触发时间间隔
  23. const last = +new Date() - timestamp
  24. // 上次被包装函数被调用时间间隔last小于设定时间间隔wait
  25. if (last < wait && last > 0) {
  26. timeout = setTimeout(later, wait - last)
  27. } else {
  28. timeout = null
  29. // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
  30. if (!immediate) {
  31. result = func.apply(context, args)
  32. if (!timeout) context = args = null
  33. }
  34. }
  35. }
  36. return function (...args) {
  37. context = this
  38. timestamp = +new Date()
  39. const callNow = immediate && !timeout
  40. // 如果延时不存在,重新设定延时
  41. if (!timeout) timeout = setTimeout(later, wait)
  42. if (callNow) {
  43. result = func.apply(context, args)
  44. context = args = null
  45. }
  46. return result
  47. }
  48. }
  49. //页面data初始化
  50. export function chartsInitData(cls) {
  51. let options = {},
  52. option = {
  53. elChart: null, //chart对象
  54. chartOptions: { //画图使用的默认值
  55. options: {
  56. type: 'line', //chart类型,默认为line
  57. x: 'name',
  58. y: 'value',
  59. tickCount: 5,
  60. scrollNum: 6,
  61. ScrollColor: 'F1F2F6',
  62. tooltip: {
  63. showCrosshairs: true
  64. },
  65. size: 2,
  66. adjust: '',
  67. shape: ''
  68. }
  69. },
  70. color: getColorValue(1), //chart颜色值
  71. };
  72. Object.assign(options, option);
  73. if (arguments.length > 1) {
  74. options = objectMerge(options, arguments[1]());
  75. }
  76. return options;
  77. }
  78. function isChartScrollBar(_this, chart) {
  79. let option = chart.options;
  80. if (!option.scroll) return false;
  81. if (option.type == 'pie' || (!option.type && option.axis === false)) return false;
  82. //是否显示scrollBar
  83. let names = [],
  84. xname = option.x,
  85. series = chart.data.series,
  86. scrollMax = option.scroll && option.scroll['number'] ? option.scroll['number'] : option.scrollNum,
  87. scrollColor = option.scroll && option.scroll['color'] ? option.scroll['color'] : option.scrollColor;
  88. //option.adjust = '';//滚动不支持adjust
  89. //name重新组合,并去重
  90. series.forEach(item => {
  91. names.push(item[xname]);
  92. });
  93. names = names.filter((item, index) => names.indexOf(item) === index);
  94. if (names.length > scrollMax) {
  95. names = names.filter((item, index) => index < scrollMax);
  96. option.scrollBar = {
  97. mode: 'x',
  98. xStyle: {
  99. backgroundColor: scrollColor,
  100. fillerColor: scrollColor,
  101. offsetY: -5
  102. }
  103. };
  104. let valueArea = {
  105. values: names
  106. };
  107. sourceDefs(option, xname, valueArea);
  108. /*{
  109. min: 0,
  110. max: scrollMax
  111. };type:line*/
  112. }
  113. }
  114. function sourceDefs(option, key, value) {
  115. if(option.defs){
  116. option.defs = option.defs.filter(item => item.key!==key);
  117. }else{
  118. option.defs = [];
  119. }
  120. option.defs.push({
  121. key: key,
  122. value: value
  123. });
  124. }
  125. //init merge data
  126. function getObjectValue(currObj, paramObj) {
  127. let result = Object.create(currObj ? currObj : null);
  128. if (currObj) {
  129. result = objectMerge(result, paramObj);
  130. return result;
  131. } else {
  132. return paramObj;
  133. }
  134. }
  135. function initDefSource(_this, chart) {
  136. let flagX = false,
  137. data = chart.downList ? chart.downList : chart.data.series,
  138. defs = chart.options.defs || [],
  139. currDef = {};
  140. if (Array.isArray(defs)) {
  141. defs.forEach(item => {
  142. if (chart.options.x == item.key) {
  143. flagX = true;
  144. }
  145. currDef[item.key] = item.value;
  146. });
  147. }
  148. //如果没有y轴校验,增加默认
  149. if (!currDef[chart.options.y]){
  150. currDef[chart.options.y] = {
  151. tickCount: 5
  152. }
  153. }
  154. _this.elChart.source(data, currDef);
  155. }
  156. function initDefScale(_this, chart) {
  157. let scale = chart.options.scale;
  158. if (Array.isArray(scale)) {
  159. scale.forEach(item => {
  160. _this.elChart.scale(item.key, item.value);
  161. });
  162. }
  163. }
  164. function initPieLabel(_this, chart) {
  165. let pieLabel = chart.options.pieLabel;
  166. if (pieLabel) {
  167. _this.elChart.pieLabel(pieLabel)
  168. }
  169. }
  170. function initReloadShape(_this, chart){
  171. let draw = chart.options.draw;
  172. // 绘制内阴影
  173. if(draw && draw.iShadow){
  174. const frontPlot = _this.elChart.get('frontPlot');
  175. const coord = _this.elChart.get('coord'); // 获取坐标系对象
  176. frontPlot.addShape('sector', {
  177. attrs: {
  178. x: coord.center.x,
  179. y: coord.center.y,
  180. r: coord.circleRadius * coord.innerRadius * 1.2, // 全半径
  181. r0: coord.circleRadius * coord.innerRadius,
  182. fill: '#000',
  183. opacity: 0.15
  184. }
  185. });
  186. _this.elChart.get('canvas').draw();
  187. }
  188. }
  189. function initDefCoord(_this, chart) {
  190. let coord = chart.options.coord;
  191. if (Array.isArray(coord)) {
  192. coord.forEach(item => {
  193. if (item.value) {
  194. _this.elChart.coord(item.key, item.value);
  195. } else {
  196. _this.elChart.coord(item.key);
  197. }
  198. });
  199. }
  200. }
  201. function axisTextLabels(text, index, total){
  202. const textCfg = {};
  203. /*if (index === 0) {
  204. textCfg.textAlign = 'start';
  205. } else if (index === total - 1) {
  206. textCfg.textAlign = 'right';
  207. }*/
  208. return textCfg;
  209. }
  210. function initDefAxis(_this, chart) {
  211. let axis = chart.options.axis;
  212. if (isTypeof(axis) === 'array') {
  213. axis.forEach(item => {
  214. _this.elChart.axis(item.key, item.value ? item.value : {
  215. label(text, index, total){
  216. return chart.options.scroll ? {} : axisTextLabels(text, index, total);
  217. }
  218. });
  219. });
  220. } else if (isTypeof(axis) === 'object'){
  221. _this.elChart.axis(axis.key, {
  222. label: function(text, index, total){
  223. let number = axis.number ? axis.number : 1,
  224. textCfg = chart.options.scroll ? {} : axisTextLabels(text, index, total);
  225. if(text < chart.data.series.length) {
  226. if(axis.mapping) textCfg.text = chart.data.series[parseInt(text)][axis.mapping];
  227. return textCfg;
  228. }
  229. }
  230. });
  231. } else if (isTypeof(axis) === 'string'){
  232. _this.elChart.axis(axis, {
  233. label: function(text, index, total){
  234. return chart.options.scroll ? {} : axisTextLabels(text, index, total);
  235. }
  236. });
  237. } else if (axis === false) {
  238. _this.elChart.axis(axis);
  239. }
  240. }
  241. function initDefLegend(_this, chart) {
  242. let legend = chart.options.legend;
  243. if (Array.isArray(legend)) {
  244. legend.forEach(item => {
  245. if(item.key){
  246. _this.elChart.legend(item.key, item.value);
  247. }else{
  248. _this.elChart.legend(item);
  249. }
  250. });
  251. } else {
  252. _this.elChart.legend(legend);
  253. }
  254. }
  255. function initDefTooltip(_this, chart, option) {
  256. let tooltip = chart.options.tooltip;
  257. if (tooltip) {
  258. tooltip = getObjectValue(option.tooltip, tooltip);
  259. }
  260. _this.elChart.tooltip(tooltip);
  261. }
  262. function initDefScrollBar(_this, chart, option) {
  263. let scrollBar = chart.options.scrollBar;
  264. if (scrollBar) {
  265. scrollBar = getObjectValue(option.scrollBar, scrollBar);
  266. }
  267. _this.elChart.scrollBar(scrollBar);
  268. }
  269. function initDefGuide(_this, chart) {
  270. let guide = chart.options.guide;
  271. if (Array.isArray(guide)) {
  272. guide.forEach(item => {
  273. _this.elChart.guide().text(item);
  274. });
  275. }
  276. }
  277. function initMarkTag(_this, chart) {
  278. let mark = chart.options.mark;
  279. if (mark && mark.isTrue) {
  280. let number = mark.number,
  281. name = mark.name;
  282. // 绘制辅助线
  283. _this.elChart.guide().line({
  284. start: function start(xScale, yScales) {
  285. let price = yScales[0].max * number / yScales[1].max;
  286. return ['min', price];
  287. },
  288. end: function end(xScale, yScales) {
  289. let price = yScales[0].max * number / yScales[1].max;
  290. return ['max', price];
  291. },
  292. style: {
  293. stroke: 'red', // 线的颜色
  294. lineDash: [0, 2, 2], // 虚线的设置
  295. lineWidth: 1 // 线的宽度
  296. // 图形样式配置
  297. }
  298. });
  299. _this.elChart.guide().text({
  300. position: function position(xScale, yScales) {
  301. let price = yScales[0].max * number / yScales[1].max;
  302. return ['max', price];
  303. },
  304. content: name + ':' + number,
  305. style: {
  306. textAlign: 'end',
  307. textBaseline: 'bottom',
  308. fill: 'red'
  309. },
  310. offsetY: -5
  311. });
  312. }
  313. }
  314. function panEventProcessReload(_this, chart) {
  315. let yValues = [],
  316. option = chart.options,
  317. xScale = _this.elChart.getXScale(),
  318. source = _this.elChart.get('data');
  319. source.map(obj => {
  320. if (xScale.translate(obj.year) >= 0) {
  321. yValues.push(obj.sales);
  322. }
  323. });
  324. sourceDefs(option, option.x, {values: xScale.values});//x轴
  325. sourceDefs(option, option.y, {
  326. min: 0,
  327. tickCount: 5,
  328. max: Math.max.apply(null, yValues)
  329. });//y轴
  330. initDefSource(_this, chart);
  331. _this.elChart.changeData(source);
  332. }
  333. function panEventEndReload(_this, chart) {
  334. _this.elChart.repaint();
  335. }
  336. function initDefRender(_this, chart) {
  337. let axis = chart.options.axis;
  338. if (isTypeof(axis) === 'array') {
  339. axis.forEach(item => {
  340. if (item.position) {
  341. drawChartType(_this, chart, item);
  342. }
  343. });
  344. } else {
  345. drawChartType(_this, chart);
  346. }
  347. if(chart.options.scroll){
  348. _this.elChart.interaction('pan', {
  349. mode: 'x',
  350. onProcess: () => {
  351. panEventProcessReload(_this, chart);
  352. },
  353. onEnd: () => {
  354. panEventEndReload(_this, chart);
  355. }
  356. });
  357. }
  358. _this.elChart.render();
  359. }
  360. function drawChartTypeMap(type){
  361. let map = {
  362. path: '.path()',
  363. point: '.point()',
  364. line: '.line()',
  365. area: '.area()',
  366. interval: '.interval()',
  367. polygon: '.polygon()',
  368. schema: '.schema()'
  369. };
  370. return map[type] || false;
  371. }
  372. function chartColorValue(options){
  373. if(options.mode && options.mode == 'more'){
  374. return '.color(name, color)';
  375. }else{
  376. return '.color(color)';
  377. }
  378. }
  379. function chartAdjustValue(options){
  380. if (options.adjust) {
  381. if(isTypeof(options.adjust) === 'object') return '.adjust(' + JSON.stringify(options.adjust) + ')';
  382. else if(isTypeof(options.adjust) === 'string') return '.adjust("' + options.adjust + '")';
  383. }
  384. return '';
  385. }
  386. function chartSizeValue(options){
  387. if(options.size) return '.size("' + options.size + '")';
  388. return '';
  389. }
  390. function chartShapeValue(options){
  391. if(options.shape) return '.shape("' + options.shape + '")';
  392. return '';
  393. }
  394. function chartStyleValue(type, options){
  395. if(options.style){
  396. if(isTypeof(options.style) == 'string'){
  397. return '.style("' + options.style + '")';
  398. }else if(isTypeof(options.style) == 'object'){
  399. if(options.style.type == type){
  400. return '.style(' + JSON.stringify(options.style) + ')';
  401. }
  402. }else if(isTypeof(options.style) == 'array'){
  403. options.style.forEach(item => {
  404. if(item.type == type){
  405. return '.style(' + JSON.stringify(item) + ')';
  406. }
  407. });
  408. }
  409. }
  410. return '';
  411. }
  412. function execDrawRender(type, options){
  413. let execDrawChart = '_this.elChart',
  414. execPostions = '.position(position)',//坐标
  415. execType = drawChartTypeMap(type),//根据类型执行对应的函数
  416. execColor = chartColorValue(options),
  417. execAdjust = chartAdjustValue(options),
  418. execSize = type === 'line' ? '' : chartSizeValue(options),
  419. execStyle = chartStyleValue(type, options),
  420. execShape = chartShapeValue(options),
  421. animate = '.animate({update: {duration: 1000}})';
  422. return execDrawChart + execType + execPostions + execColor + execAdjust + execShape + execSize + execStyle + animate;
  423. }
  424. function drawChartType(_this, chart, item) {
  425. let options = chart.options,
  426. color = options.color ? options.color : _this.color,
  427. size = options.size ? options.size : '',
  428. adjust = options.adjust ? options.adjust : '',
  429. shape = options.shape ? options.shape : '',
  430. name = options.name ? options.name : '',
  431. key = options.x ? options.x : '',
  432. value = options.y ? options.y : '',
  433. position = key + '*' + value,
  434. type = options.type ? options.type : '';
  435. if (typeof (item) == 'object') {
  436. type = item.type ? item.type : type;
  437. value = item.position ? item.position : value;
  438. position = key + '*' + value;
  439. }
  440. if(isTypeof(type) === 'string'){
  441. eval('(' + execDrawRender(type, options) + ')');
  442. }else if(isTypeof(type) === 'object'){
  443. for(let [k, v] of Object.entries(type)){
  444. if(v && drawChartTypeMap(k)) eval('(' + execDrawRender(k, options) + ')');
  445. }
  446. }
  447. }
  448. export function mergeChartsOptions(_this) {
  449. let option = {},
  450. chartOptions = objectMerge(_this.chartOptions, _this.chart.chartOptions);
  451. isChartScrollBar(_this, chartOptions); //判断是否显示滚动条
  452. initDefSource(_this, chartOptions);
  453. initDefScale(_this, chartOptions);
  454. initDefCoord(_this, chartOptions);
  455. initDefAxis(_this, chartOptions);
  456. initDefLegend(_this, chartOptions);
  457. initDefTooltip(_this, chartOptions, option);
  458. initDefScrollBar(_this, chartOptions, option);
  459. initPieLabel(_this, chartOptions);
  460. initDefGuide(_this, chartOptions);
  461. initMarkTag(_this, chartOptions);
  462. initDefRender(_this, chartOptions);
  463. initReloadShape(_this, chartOptions);
  464. }
  465. export function legendSelecthanged(_this, option) {
  466. if (!option.legendData) return;
  467. _this.elChart.on('legendselectchanged', function (params) {
  468. let num = 0,
  469. name = params.name;
  470. option.series[num].data.forEach((item, index) => {
  471. let value = 0;
  472. option.legendData[index].forEach(legend => {
  473. if (name == legend.subjectName) {
  474. value = Number(legend.fee);
  475. }
  476. });
  477. if (params.selected[name]) {
  478. option.series[num].data[index] = item + value;
  479. } else {
  480. option.series[num].data[index] = item - value;
  481. }
  482. });
  483. _this.elChart.setOption(option);
  484. });
  485. }
  486. export function drawCharts(_this) {
  487. mergeChartsOptions(_this);
  488. }