Sidebar-Charts.js 12.1 KB
(function () {
	const enumConst = {

		/**
		 * @description 图表cell 默认宽度
		 */
		CHART_CELL_DEFAULT_WIDTH: 400,

		/**
		 * @description 图表cell 默认高度
		 */
		CHART_CELL_DEFAULT_HEIGHT: 400,

		/**
		 * @description 图表cell的 width attribute
		 */
		CHART_CELL_WIDTH: 'width',

		/**
		 * @description 图表cell的 height attribute
		 */
		CHART_CELL_HEIGHT: 'height',

		/**
		 * @description cell id key
		 */
		CHART_INSTANCE_ID: 'chartInstanceId',

		/**
		 * @description 图表容器 class name
		 */
		CHART_CONTAINER_CLS: 'echarts__instance',

		/**
		 * @description 图表容器  id 前缀
		 */
		CHART_CONTAINER_ID_PREFIX: 'echarts__instance__',

		/**
		 * @description 图表图片占位符大小
		 */
		CHART_IMG_PLACEHOLDER_SIZE: 30,
	}

	// Adds Atlassian shapes
	// 图表
	Sidebar.prototype.addChartsPalette = function () {
		this.chartsComponentInit()
		const self = this
		const componentType = this.enumComponentType
		const { DATA_SOURCE, DYNAMIC_EFFECT, DISPLAY_TYPE } = this.enumPermissionPanel

		const s = 'html=1;shadow=0;dashed=0;shape=mxgraph.atlassian.';
		const s2 = 'html=1;shadow=0;dashed=0;fillColor=none;strokeColor=none;shape=mxgraph.bootstrap.rect;';
		const s3 = mxConstants.STYLE_STROKEWIDTH + '=1;shadow=0;dashed=0;align=center;html=1;' + mxConstants.STYLE_SHAPE + "=mxgraph.mockup.";
		const gn = 'mxgraph.charts';
		const dt = 'charts ';
		const sb = this;

		this.setCurrentSearchEntryLibrary('charts');

		const fns = [
			this.addEntry('line chart', mxUtils.bind(this, function () {
				const id = self.generatorChartsId()
				const cell = self.generatorCell(id, enumConst.CHART_IMG_PLACEHOLDER_SIZE, enumConst.CHART_IMG_PLACEHOLDER_SIZE, componentType.LINE_CHART)
				return this.createVertexTemplateFromCells([cell], cell.geometry.width, cell.geometry.height, '折线图');
			})),
			this.addEntry('bar chart', mxUtils.bind(this, function () {
				const id = self.generatorChartsId()
				const cell = self.generatorCell(id, enumConst.CHART_IMG_PLACEHOLDER_SIZE, enumConst.CHART_IMG_PLACEHOLDER_SIZE, componentType.BAR_CHART, '/thingskit-drawio/images/thingskit/bar-chart.png')
				return this.createVertexTemplateFromCells([cell], cell.geometry.width, cell.geometry.height, '柱状图');
			})),
		];

		this.addPaletteFunctions('charts', '图表', false, fns);

		this.setCurrentSearchEntryLibrary();
	};

	/**
	 * @description echarts 实例映射
	 * @type {Map<any, any>}
	 */
	Sidebar.prototype.chartsInstanceMapping = new Map()

	/**
	 * @description 图表options 映射
	 * @type {{[p: string]: (function(): {yAxis: {type: string}, xAxis: {data, type: string}, series: [{data, type: string}]})|(function(): {yAxis: {type: string}, xAxis: {data, type: string}, series: [{data, showBackground: boolean, backgroundStyle: {color: string}, type: string}]})}}
	 */
	Sidebar.prototype.chartOptionMapping = {
		[Sidebar.prototype.enumComponentType.LINE_CHART]: function () {
			return {
				xAxis: {
					type: 'category',
					data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
				},
				yAxis: {
					type: 'value',
				},
				series: [
					{
						data: [150, 230, 224, 218, 135, 147, 260],
						type: 'line',
					},
				],
			}
		},
		[Sidebar.prototype.enumComponentType.BAR_CHART]: function () {
			return {
				xAxis: {
					type: 'category',
					data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
				},
				yAxis: {
					type: 'value',
				},
				series: [
					{
						data: [120, 200, 150, 80, 70, 110, 130],
						type: 'bar',
						showBackground: true,
						backgroundStyle: {
							color: 'rgba(180, 180, 180, 0.2)',
						},
					},
				],
			};
		},
	}

	/**
	 * @description 创建cell
	 * @param id
	 * @param width
	 * @param height
	 * @param chartType
	 * @param placeholderPath
	 * @returns {*}
	 */
	Sidebar.prototype.generatorCell = function (id, width, height, chartType, placeholderPath) {
		const cell = new mxCell(this.createChartsNode(id, width, height, placeholderPath), new mxGeometry(0, 0, width, height), 'text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;overflow=hidden;');
		cell.setVertex(true)
		const basicAttr = this.enumCellBasicAttribute
		this.setCellAttributes(cell, {
			[basicAttr.COMPONENT_TYPE]: chartType,
			[basicAttr.CHART_INSTANCE_ID]: id,
			[enumConst.CHART_CELL_WIDTH]: width,
			[enumConst.CHART_CELL_HEIGHT]: height,
		})
		return cell
	}


	/**
	 * @description 生成图表 id
	 * @returns {string}
	 */
	Sidebar.prototype.generatorChartsId = function () {
		return `${enumConst.CHART_CONTAINER_ID_PREFIX}${Date.now()}`
	}

	/**
	 * @description 创建图表节点
	 * @param id
	 * @param width
	 * @param height
	 * @param placeholderPath
	 * @returns {string}
	 */
	Sidebar.prototype.createChartsNode = function (id, width = 400, height = 400, placeholderPath = '/thingskit-drawio/images/thingskit/line-chart.png') {
		return `<div class="echarts__instance" style="width: ${width}px; height: ${height}px" id="${id}"><img src="${placeholderPath}" alt=""></div>`
	}

	/**
	 * @description 是否是图表cell
	 * @param cell
	 * @returns {boolean}
	 */
	Sidebar.prototype.isChartCell = function (cell) {
		const basitAttr = this.enumCellBasicAttribute
		const componentType = this.enumComponentType
		const currentType = cell.getAttribute(basitAttr.COMPONENT_TYPE)
		return !!(currentType && (currentType === componentType.LINE_CHART || currentType === componentType.BAR_CHART))
	}

	/**
	 * @description 创建图表实例 并 保存实例到map中
	 * @param id
	 * @param width
	 * @param height
	 * @param chartType
	 */
	Sidebar.prototype.generatorEChartInstance = function (id, width, height, chartType) {
		const chartOptionMapping = this.chartOptionMapping
		const chartsInstanceMapping = this.chartsInstanceMapping
		const chartDom = document.getElementById(id);
		if (!chartDom) return
		chartDom.style.width = `${width}px`
		chartDom.style.height = `${height}px`
		const myChart = echarts.init(chartDom);
		const option = chartOptionMapping[chartType] ? chartOptionMapping[chartType]() : {}
		option && myChart.setOption(option);
		chartsInstanceMapping.set(id, myChart)
	}

	/**
	 * @description 获取charts cell 的id
	 * @param cell
	 * @returns {*}
	 */
	Sidebar.prototype.getCellId = function (cell) {
		const basicAttr = this.enumCellBasicAttribute
		return this.graph.getAttributeForCell(cell, basicAttr.CHART_INSTANCE_ID)
	}

	/**
	 * @description 图表组件 拓展处理
	 */
	Sidebar.prototype.chartsComponentInit = function () {
		const chartsInstanceMapping = this.chartsInstanceMapping
		const graph = this.graph
		const self = this
		const basicAttr = this.enumCellBasicAttribute
		/**
		 * @description 拓展添加charts 实例方法
		 */
		const addClickHandler = Sidebar.prototype.addClickHandler
		Sidebar.prototype.addClickHandler = function (elt, ds, cells) {
			const cell = cells[0]
			const cellValue = cell.value
			const validate = cellValue && cellValue.nodeName === 'UserObject' && this.isChartCell(cell)

			/**
			 * @description 拓展Sidebar鼠标按下
			 * @type {ds.mouseDown | Function}
			 */
			const mouseDown = ds.mouseDown
			ds.mouseDown = function (evt) {
				if (validate) {
					const id = self.generatorChartsId()
					const geo = Object.assign(graph.model.getGeometry(cell), { width: 400, height: 400 })
					cell.setGeometry(geo)
					self.graph.setAttributeForCell(cell, basicAttr.CHART_INSTANCE_ID, id);
					self.graph.setAttributeForCell(cell, enumConst.CHART_CELL_WIDTH, enumConst.CHART_CELL_DEFAULT_WIDTH);
					self.graph.setAttributeForCell(cell, enumConst.CHART_CELL_HEIGHT, enumConst.CHART_CELL_DEFAULT_HEIGHT);
					self.graph.setAttributeForCell(cell, 'label', self.createChartsNode(id))
				}
				mouseDown.apply(this, arguments)
			};

			/**
			 * @description 拓展放置图表
			 * @type {ds.mouseUp | Function}
			 */
			const mouseUp = ds.mouseUp
			ds.mouseUp = function () {
				try {
					mouseUp.apply(this, arguments)
				} finally {
					if (validate) {
						const id = self.getCellId(cell)
						const chartType = cell.getAttribute(basicAttr.COMPONENT_TYPE)
						self.generatorEChartInstance(id, enumConst.CHART_CELL_DEFAULT_WIDTH, enumConst.CHART_CELL_DEFAULT_HEIGHT, chartType)

					}
				}
			}
			addClickHandler.apply(this, arguments)
		}

		/**
		 * @description charts cell发生resize时改变charts size
		 * @type {Function}
		 */
		const cellResized = mxGraph.prototype.cellResized
		mxGraph.prototype.cellResized = function (cell, rect) {
			if (Sidebar.prototype.isChartCell(cell)) {
				const { width, height } = rect
				const id = self.getCellId(cell)
				const chartDom = document.getElementById(id)
				chartDom.style.width = `${width}px`
				chartDom.style.height = `${height}px`
				self.graph.setAttributeForCell(cell, enumConst.CHART_CELL_WIDTH, width)
				self.graph.setAttributeForCell(cell, enumConst.CHART_CELL_HEIGHT, height)
				const instance = chartsInstanceMapping.get(id)

				instance && instance.resize()
			}
			cellResized.apply(this, arguments)
		}

		/**
		 * @description 删除charts cell 时 删除保存的charts 实例
		 */
		const deleteCells = Graph.prototype.deleteCells
		Graph.prototype.deleteCells = function (cell) {
			const id = self.getCellId(cell)
			chartsInstanceMapping.delete(id)
			return deleteCells.apply(this, arguments)
		}


		/**
		 * @description 拓展Sidebar 提示框
		 */
		const createTooltip = Sidebar.prototype.createTooltip
		Sidebar.prototype.createTooltip = function (elt, cells) {
			const id = self.generatorChartsId()
			const validateFlag = self.isChartCell(cells[0])

			const chartType = graph.getAttributeForCell(cells[0], basicAttr.COMPONENT_TYPE)
			try {
				if (validateFlag) {
					const cell = self.generatorCell(id, enumConst.CHART_CELL_DEFAULT_WIDTH, enumConst.CHART_CELL_DEFAULT_HEIGHT, chartType)
					const _arguments = Array.prototype.slice.call(arguments, 0)
					_arguments.splice(1, 1, [cell])
					createTooltip.apply(this, _arguments)
				} else {
					createTooltip.apply(this, arguments)
				}
			} finally {
				if (validateFlag) self.generatorEChartInstance(id, enumConst.CHART_CELL_DEFAULT_WIDTH, enumConst.CHART_CELL_DEFAULT_HEIGHT, chartType)
			}
		}
	}

	/**
	 * @description 实例化echarts
	 * @param graph
	 */
	Sidebar.prototype.initChartInstance = function (graph) {
		const basicAttr = this.enumCellBasicAttribute
		const allCell = graph.getDefaultParent().children || []
		const domIdMapping = new Map()
		for (const cell of allCell) {
			const chartInstanceId = graph.getAttributeForCell(cell, basicAttr.CHART_INSTANCE_ID)
			if (Sidebar.prototype.isChartCell(cell) && chartInstanceId) {
				const width = graph.getAttributeForCell(cell, enumConst.CHART_CELL_WIDTH)
				const height = graph.getAttributeForCell(cell, enumConst.CHART_CELL_HEIGHT)
				const chartType = graph.getAttributeForCell(cell, basicAttr.COMPONENT_TYPE)
				domIdMapping.set(chartInstanceId, { width, height, chartType })
			}
		}
		const chartsDomList = document.querySelectorAll(`.${enumConst.CHART_CONTAINER_CLS}`)
		for (const chartDom of chartsDomList) {
			const id = chartDom.getAttribute('id')
			if (!domIdMapping.has(id)) {
				continue
			}
			const { width, height, chartType } = domIdMapping.get(id)
			Sidebar.prototype.generatorEChartInstance(id, width, height, chartType)
		}
	}

	/**
	 * @description 初始化图表
	 */
	// const openFileHandle = EditorUi.prototype.openFileHandle
	// EditorUi.prototype.openFileHandle = function () {
	// 	console.log('enter open file')
	// 	try {
	// 		openFileHandle.apply(this, arguments)
	// 	} finally {
	// 		console.log('openFileHandle')
	// 		const graph = this.editor.graph
	// 		Sidebar.prototype.initChartInstance(graph)
	// 	}
	// }

	/**
	 * @description 实例化 echarts
	 */
	const refresh = Graph.prototype.refresh
	Graph.prototype.refresh = function () {
		refresh.apply(this, arguments)
		if (!arguments.length) {
			Sidebar.prototype.initChartInstance(this)
		}
	}

	// const selectPage = EditorUi.prototype.selectPage
	// EditorUi.prototype.selectPage = function () {
	// 	try {
	// 		selectPage.apply(this, arguments)

	// 	} finally {
	// 		Sidebar.prototype.chartsInstanceMapping.clear()
	// 		const graph = this.editor.graph
	// 		Sidebar.prototype.initChartInstance(graph)
	// 	}
	// }
})();