Created
June 27, 2024 08:45
-
-
Save electroheadfx/71827f8b8a997f99ac29e2768dfc3798 to your computer and use it in GitHub Desktop.
echarts labels overlapping
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const dataset = graphData.map((item, index) => { | |
| return { | |
| id: index, | |
| dimensions: ['sscount', 'pk', 'severity', 'value', 'id', 'level'], | |
| source: item.data, | |
| } | |
| }) | |
| const dataTransforms = graphData.map((_, index) => { | |
| return { | |
| id: 'transform-' + index, | |
| fromDatasetIndex: index, | |
| transform: [ | |
| { | |
| type: 'sort', | |
| config: { dimension: 'id', order: 'asc' }, | |
| }, | |
| { | |
| type: 'sort', | |
| // here filter by pk if track mode is actived else not its itinary mode (sscount) | |
| config: { dimension: track ? 'pk' : 'sscount', order: 'asc' }, | |
| } | |
| ], | |
| } | |
| }) | |
| dataTransforms.forEach((item, index) => { | |
| dataset.push(item as any) | |
| }) | |
| // add path to dataset | |
| // <--- end dataset | |
| // *************************************************************************** | |
| // *************************************************************************** | |
| // Create grid Array | |
| // --------------------------------------------------------------------------- | |
| // grid setup for n measures | |
| const grid = [] | |
| for (let i = 0;i < totalGraphs;i++) { | |
| grid.push({ | |
| ...GridPadX, | |
| show: true, | |
| id: i, | |
| z: 2, | |
| borderColor: bgAxisColor, | |
| top: (heightGrid * i + GridPadY + gapGrid * i) + topPaddingForActionBar, | |
| height: heightGrid + 'px', | |
| width: WindowWidth - gridPadRight + 'px', | |
| }) | |
| } | |
| // parcours (path) | |
| const gridPath = { | |
| ...GridPadX, | |
| left: GridPadLeft, | |
| show: true, | |
| z: 2, | |
| top: topPaddingForActionBar / 2, | |
| height: 55 + topPaddingForActionBar, // 28 | |
| width: WindowWidth - gridPadRight + 'px', | |
| bottom: '80%', | |
| // backgroundColor: '#ddd', | |
| } | |
| // assets | |
| const gridAsset = { | |
| ...GridPadX, | |
| bottom: GridPadY - 55, | |
| // bottom: 0, | |
| height: 45, | |
| z: 2, | |
| width: WindowWidth - gridPadRight + 'px', | |
| show: true, | |
| shadowOffsetX: 4, | |
| shadowOffsetY: 4, | |
| shadowColor: 'rgba(0, 0, 0, 0)', | |
| shadowBlur: 0, | |
| borderWidth: 0, | |
| } | |
| // assets | |
| const gridAssetForLabels = { | |
| ...GridPadX, | |
| bottom: GridPadY - 55, | |
| height: 45, | |
| z: 9999, | |
| zlevel: 10, | |
| width: WindowWidth - gridPadRight + 'px', | |
| show: true, | |
| shadowOffsetX: 4, | |
| shadowOffsetY: 4, | |
| shadowColor: 'rgba(0, 0, 0, 0)', | |
| shadowBlur: 0, | |
| borderWidth: 0, | |
| } | |
| grid.push(gridPath) | |
| grid.push(gridAsset) | |
| grid.push(gridAssetForLabels) | |
| // *************************************************************************** | |
| // *************************************************************************** | |
| // Create xAxis Array | |
| // --------------------------------------------------------------------------- | |
| // !! We should have only one xAxis for all measures or each axis should have the same min and max range | |
| const xAxis = [] | |
| for (let i = 0;i < totalGraphs;i++) { | |
| // const measure = measures[i] as string | |
| xAxis.push({ | |
| // name: measure, | |
| type: 'value', | |
| min: range[0], | |
| max: range[1], | |
| gridIndex: i, | |
| splitNumber: 10, | |
| boundaryGap: false, | |
| z: 1, | |
| axisPointer: { | |
| snap: true, | |
| }, | |
| axisLabel: { | |
| show: i < totalGraphs - 1 ? false : true, | |
| color: '#ddd', | |
| verticalAlign: 'top', | |
| lineHeight: 18, | |
| fontWeight: 'bold', | |
| showMinLabel: false, | |
| showMaxLabel: false, | |
| // interval: 5, | |
| formatter: (value: number) => { | |
| if (track) { | |
| return value.toLocaleString(router.locale, { minimumFractionDigits: 3 }) | |
| } | |
| if (graphData[i]) { | |
| const data = graphData[i]?.data?.sort((a, b) => Math.abs(a[0] - value) - Math.abs(b[0] - value))[0] | |
| if (!data) return null | |
| const newAxisValue = data[1] | |
| return newAxisValue?.toLocaleString(router.locale, { minimumFractionDigits: 3 }) | |
| } | |
| return null | |
| }, | |
| }, | |
| axisLine: { | |
| show: false, | |
| lineStyle: { | |
| color: bgAxisColor, | |
| }, | |
| }, | |
| axisTick: { | |
| show: false, | |
| }, | |
| }) | |
| } | |
| // Path (Parcours) xAxis | |
| xAxis.push({ | |
| show: false, | |
| type: 'value', | |
| min: range[0], | |
| // min: 'dataMin', | |
| max: range[1], | |
| // max: 'dataMax', | |
| axisPointer: { | |
| snap: false, | |
| }, | |
| gridIndex: totalGraphs, // eq to 4 with 4 graphs (0-3) | |
| }) | |
| // Assets (Patrimoines) xAxis | |
| xAxis.push({ | |
| show: false, | |
| type: 'value', | |
| min: range[0], | |
| max: range[1], | |
| axisPointer: { | |
| snap: false, | |
| }, | |
| gridIndex: totalGraphs + 1, // eq to 4 with 4 graphs (0-3) | |
| }) | |
| // Assets (Patrimoines) xAxis for labels | |
| xAxis.push({ | |
| show: false, | |
| type: 'value', | |
| min: range[0], | |
| max: range[1], | |
| axisPointer: { | |
| snap: false, | |
| }, | |
| gridIndex: totalGraphs + 2, // eq to 4 with 4 graphs (0-3) | |
| }) | |
| // <--- end xAxis Array | |
| // *************************************************************************** | |
| // *************************************************************************** | |
| // Create yAxis Array | |
| // --------------------------------------------------------------------------- | |
| const yAxis = [] | |
| for (let i = 0;i < totalGraphs;i++) { | |
| const measure = measures[i] | |
| if (measure) { | |
| yAxis.push({ | |
| type: 'value', | |
| gridIndex: i, | |
| position: 'right', | |
| z: 1, | |
| axisLine: { | |
| show: false, | |
| }, | |
| axisTick: { | |
| show: false, | |
| }, | |
| axisLabel: { | |
| showMaxLabel: false, | |
| color: '#ddd', | |
| verticalAlign: 'top', | |
| lineHeight: 10, | |
| fontSize: 10, | |
| margin: 4, | |
| formatter: (value: number) => { | |
| const isInteger = (n: number) => n.toString().split('.').length === 1 | |
| if (isInteger(value)) return value | |
| else value.toLocaleString(router.locale, measurePrecision) | |
| }, | |
| }, | |
| // min: 'datamin', | |
| // max: 'datamax', | |
| min: (value: any) => { | |
| // evaluate the ecart min with 0.1 % of max/min difference | |
| return value.min - ((value.max - value.min) * 0.02) | |
| }, | |
| max: (value: any) => { | |
| // evaluate the ecart min with 0.1 % of max/min difference | |
| return value.max + ((value.max - value.min) * 0.02) | |
| }, | |
| // formatter: (value: number) => { | |
| // return value.toLocaleString(router.locale, measurePrecision) | |
| // }, | |
| }) | |
| } | |
| } | |
| // Path (Parcours) yAxis | |
| yAxis.push({ | |
| // type: 'value', | |
| show: false, | |
| gridIndex: totalGraphs, // eq to 4 with 4 graphs (0-3) | |
| min: 0, | |
| max: 1, | |
| axisPointer: { | |
| type: 'none', | |
| snap: false | |
| } | |
| }) | |
| // Assets (patrimoines) yAxis | |
| yAxis.push({ | |
| // type: 'value', | |
| show: false, | |
| gridIndex: totalGraphs + 1, // eq to 5 with 4 graphs (0-3) | |
| min: 0, | |
| max: 1, | |
| axisPointer: { | |
| type: 'none', | |
| snap: false | |
| } | |
| }) | |
| // Assets (patrimoines) yAxis for labels | |
| yAxis.push({ | |
| // type: 'value', | |
| show: false, | |
| gridIndex: totalGraphs + 2, // eq to 5 with 4 graphs (0-3) | |
| min: 0, | |
| max: 1, | |
| axisPointer: { | |
| type: 'none', | |
| snap: false | |
| } | |
| }) | |
| // <--- end yAxis Array | |
| // *************************************************************************** | |
| // --------------------------------------------------------------------------- | |
| // *************************************************************************** | |
| // *************************************************************************** | |
| // | |
| // Create series Arrays | |
| // | |
| // *************************************************************************** | |
| // *************************************************************************** | |
| // *************************************************************************** | |
| // Create Parcours (path) series | |
| // --------------------------------------------------------------------------- | |
| const SeriesItineraryData = [ | |
| { | |
| type: 'line', | |
| name: 'range', | |
| data: [ | |
| [assets_start_pk, 0], | |
| [assets_end_pk, 0], | |
| ], | |
| showSymbol: false, | |
| tooltip: { | |
| show: false, | |
| }, | |
| lineStyle: { | |
| width: 0, | |
| }, | |
| emphasis: { | |
| disabled: true | |
| }, | |
| xAxisIndex: totalGraphs, | |
| yAxisIndex: totalGraphs, | |
| markArea: { | |
| itemStyle: { | |
| color: 'rgba(0, 0, 0, 0.05)' | |
| }, | |
| emphasis: { | |
| disabled: true | |
| }, | |
| data: [ | |
| [ | |
| { | |
| name: 'range', | |
| xAxis: zoomBounds[0] | |
| }, | |
| { | |
| xAxis: zoomBounds[1] | |
| } | |
| ], | |
| ] | |
| } | |
| } | |
| ] as any | |
| itineraryTrack.forEach((section, i) => { | |
| const label = section?.label | |
| const asset_start_pk = track ? Number(section?.startLinearReference) : section?.startSSCount | |
| const asset_end_pk = track ? Number(section?.endLinearReference) : section?.endSSCount | |
| const asset_middle_pk = ((asset_end_pk + asset_start_pk) / 2) | |
| // estimate moy px for each asset | |
| const asset_moy_pk = (asset_start_pk + asset_end_pk) / 2 | |
| const asset_ratio = (asset_moy_pk - assets_start_pk) / (assets_end_pk - assets_start_pk) | |
| const asset_moy_px = (assets_start_px + asset_ratio) * (assets_end_px - assets_start_px) | |
| const asset_width_px = ((assets_end_px - assets_start_px) * (asset_end_pk - asset_start_pk)) / (assets_end_pk - assets_start_pk) | |
| // getSeverityColor(1) = getSeverityColor('VO) | |
| const trackColor = track ? getSeverityColor(1) : getSeverityColor(1, section.trackNumber - 1, itineraryData?.trackCount) | |
| const newObject = { | |
| name: section?.label, | |
| tooltip: { | |
| show: false, | |
| }, | |
| data: [ | |
| [track ? Number(section?.startLinearReference) : Number(section?.startSSCount), positionParcours], | |
| [track ? Number(section?.endLinearReference) : Number(section?.endSSCount), positionParcours], | |
| ], | |
| type: 'line', | |
| xAxisIndex: totalGraphs, | |
| yAxisIndex: totalGraphs, | |
| showSymbol: false, | |
| symbolSize: 0, | |
| symbol: 'emptyCircle', | |
| lineStyle: { | |
| type: 'solid', | |
| width: 0, | |
| }, | |
| itemStyle: { | |
| color: 'DodgerBlue', | |
| }, | |
| markLine: { | |
| name: section?.label, | |
| animation: false, | |
| symbolSize: 0, | |
| label: { | |
| show: true, | |
| color: trackColor, | |
| fontWeight: 'bold', | |
| distance: -23, | |
| position: 'middle', | |
| formatter: asset_width_px < 20 ? '.' : section?.label, | |
| width: asset_width_px, | |
| overflow: 'truncate', | |
| }, | |
| data: [[ | |
| { | |
| name: 'itineraryTrack', | |
| lineStyle: { | |
| type: 'solid', | |
| color: trackColor, | |
| width: 4, | |
| }, | |
| symbol: section.startSymbol === 'NULL' ? 'none' : section.startSymbol === 'BACK' ? backIcon : 'square', | |
| symbolSize: section.startSymbol === 'BACK' ? 25 : 12, | |
| symbolRotate: 0, | |
| symbolOffset: section.startSymbol === 'BACK' ? [0, -2] : [0, 0], | |
| coord: [ | |
| track ? Number(section?.startLinearReference) : Number(section?.startSSCount), positionParcours, | |
| positionParcours, | |
| ] | |
| }, | |
| { | |
| symbol: section.endSymbol === 'NULL' ? 'none' : section.endSymbol === 'BACK' ? backIcon : 'circle', | |
| symbolSize: section.endSymbol === 'BACK' ? 25 : 12, | |
| symbolRotate: 0, | |
| symbolOffset: section.endSymbol === 'BACK' ? [0, -2] : [0, 0], | |
| coord: [ | |
| track ? Number(section?.endLinearReference) : Number(section?.endSSCount), positionParcours, | |
| positionParcours, | |
| ] | |
| } | |
| ]], | |
| emphasis: { | |
| // scale: true, | |
| // focus: 'series', | |
| label: { | |
| overflow: 'none', | |
| formatter: section?.label, | |
| } | |
| } | |
| } | |
| } | |
| SeriesItineraryData.push(newObject) | |
| }) | |
| itineraryAdv.forEach((adv, i) => { | |
| const advColor = track ? getSeverityColor(1) : getSeverityColor(1, adv.trackNumber - 1, itineraryData?.trackCount) | |
| const newObject = { | |
| name: adv?.label, | |
| data: [ | |
| [ | |
| track ? Number(adv?.startLinearReference) : Number(adv?.startSSCount) - 20, | |
| positionParcours, | |
| ], | |
| [ | |
| track ? Number(adv?.endLinearReference) : Number(adv?.endSSCount) + 20, | |
| positionParcours, | |
| ], | |
| ], | |
| type: 'line', | |
| xAxisIndex: totalGraphs, | |
| yAxisIndex: totalGraphs, | |
| showSymbol: false, | |
| symbolSize: 0, | |
| lineStyle: { | |
| type: 'solid', | |
| width: 0, | |
| }, | |
| label: { | |
| show: false, | |
| color: adv.mode === 'DIRECT' ? advColor : 'orange', | |
| fontWeight: 'bold', | |
| fontSize: 10, | |
| position: [4, -23], | |
| align: 'center', | |
| formatter: (obj: any) => (obj.dataIndex % 2 === 0 ? obj.seriesName : ''), | |
| }, | |
| emphasis: { | |
| focus: 'series', | |
| scale: true, | |
| label: { | |
| show: true, | |
| }, | |
| lineStyle: { | |
| type: 'solid', | |
| width: 0, | |
| }, | |
| }, | |
| markLine: { | |
| animation: false, | |
| symbolSize: 0, | |
| data: [[ | |
| { | |
| lineStyle: { | |
| type: 'solid', | |
| color: adv.mode === 'DIRECT' ? advColor : 'orange', | |
| width: 10, | |
| }, | |
| coord: [ | |
| track ? Number(adv?.startLinearReference) : Number(adv?.startSSCount), | |
| positionParcours, | |
| ] | |
| }, | |
| { | |
| coord: [ | |
| track ? Number(adv?.endLinearReference) : Number(adv?.endSSCount), | |
| positionParcours, | |
| ] | |
| } | |
| ]], | |
| emphasis: { | |
| disabled: true, | |
| // scale: true, | |
| // focus: 'series', | |
| } | |
| } | |
| } | |
| SeriesItineraryData.push(newObject) | |
| }) | |
| // *************************************************************************** | |
| // Create Assets (patrimoine) series | |
| // --------------------------------------------------------------------------- | |
| // setup series counter for capture the assets ID with React click (selected asset) | |
| const seriesCountId = campaignsId.length * dataLength | |
| const PathSeriesCountId = itineraryTrack.length + itineraryAdv.length | |
| const SeriesAssetData = [ | |
| { | |
| type: 'line', | |
| name: 'range', | |
| data: [ | |
| [range[0], positionAssetY], | |
| [range[1], positionAssetY], | |
| ], | |
| tooltip: { | |
| show: false, | |
| }, | |
| z: -1, | |
| lineStyle: { | |
| color: 'gray', | |
| width: 0.5, | |
| type: 'solid' | |
| }, | |
| itemStyle: { | |
| color: 'DodgerBlue' | |
| }, | |
| symbol: 'square', | |
| symbolSize: 5, | |
| emphasis: { | |
| disabled: true | |
| }, | |
| xAxisIndex: totalGraphs + 1, | |
| yAxisIndex: totalGraphs + 1, | |
| labelLayout: { | |
| verticalAlign: 'middle', | |
| }, | |
| }, | |
| ] as any | |
| let seriesCounter = seriesCountId + PathSeriesCountId + 2 | |
| nonAdvAssets.forEach((asset, i) => { | |
| const label = t(asset?.type, { ns: 'asset' }) + ' ' + asset?.name | |
| const asset_start_pk = track ? Number(asset?.startLinearReference) : asset?.startSSCount | |
| const asset_end_pk = track ? Number(asset?.endLinearReference) : asset?.endSSCount | |
| const asset_middle_pk = ((asset_end_pk + asset_start_pk) / 2) | |
| const informations = asset.informations.filter((info) => info.type !== '' && info.value !== '').map((info) => ({ type: info.type, value: info.value })) | |
| const nonAdvObj = { | |
| id: `nonAdvAssets-${i}`, | |
| name: 'asset', | |
| type: 'line', | |
| triggerLineEvent: true, | |
| xAxisIndex: totalGraphs + 1, | |
| yAxisIndex: totalGraphs + 1, | |
| showSymbol: true, | |
| symbolSize: 0, | |
| symbol: 'diamond', | |
| data: [ | |
| [asset_start_pk, positionAssetY], | |
| [asset_middle_pk, positionAssetY], | |
| [asset_end_pk, positionAssetY] | |
| ], | |
| lineStyle: { | |
| type: 'solid', | |
| width: 2, | |
| color: ColorAssets.get(asset.type), | |
| }, | |
| itemStyle: { | |
| color: ColorAssets.get(asset.type), | |
| }, | |
| label: { | |
| show: false, | |
| distance: -19, | |
| formatter: '{bg|' + label + '}', | |
| rich: { | |
| bg: { | |
| color: ColorAssets.get(asset.type), | |
| fontWeight: 'bold', | |
| fontSize: 11, | |
| } | |
| }, | |
| }, | |
| emphasis: { | |
| scale: true, | |
| focus: 'series', | |
| lineStyle: { | |
| width: 4, | |
| }, | |
| label: { | |
| show: true | |
| }, | |
| }, | |
| markPoint: { | |
| animation: false, | |
| data: [ | |
| { | |
| name: 'asset', | |
| symbol: 'image://' + IconAssets.get(asset.type), | |
| symbolOffset: [0, -16], | |
| symbolSize: 27, | |
| coord: [ | |
| asset_middle_pk, | |
| positionAssetY, | |
| { | |
| icon: 'image://' + IconAssets.get(`${asset.type}`), | |
| iconSelected: 'image://' + IconAssets.get(`${asset.type}-SEL`), | |
| } | |
| ] | |
| } | |
| ], | |
| emphasis: { | |
| scale: true, | |
| focus: 'series', | |
| } | |
| } | |
| } | |
| const nonAdvLabel = { | |
| id: `nonAdvAssets-${i}-label`, | |
| name: 'asset', | |
| type: 'scatter', | |
| z: 999999999, | |
| data: [[asset_middle_pk, positionAssetY + 0.6]], | |
| xAxisIndex: totalGraphs + 2, | |
| yAxisIndex: totalGraphs + 2, | |
| symbolSize: 0, | |
| showSymbol: false, | |
| itemStyle: { | |
| color: 'transparent', | |
| }, | |
| emphasis: { | |
| disabled: true | |
| }, | |
| label: { | |
| show: false, | |
| offset: [0, -100], | |
| // t(adv?.type, { ns: 'asset' }) + ' ' + adv?.name | |
| formatter: [ | |
| `{icon|} {title|${t(asset?.type, { ns: 'asset' })}}{abg|}`, | |
| `{name|${asset?.name}}`, | |
| `{key|${t('ASSET_PK_START')}}{value|${asset.startLinearReference}}`, | |
| `{key|${t('ASSET_PK_END')}}{value|${asset.endLinearReference}}`, | |
| informations.length > 0 ? informations.map((info) => `{key|${info.type}}{value|${info.value}}`).join('\n') : '' | |
| ].filter(Boolean).join('\n'), | |
| backgroundColor: 'white', | |
| borderColor: ColorAssets.get(asset.type), | |
| borderWidth: 2, | |
| borderRadius: 4, | |
| padding: [0, 0, 5, 0], | |
| color: '#000', | |
| fontSize: 14, | |
| lineHeight: 18, | |
| rich: { | |
| title: { | |
| fontSize: 14, | |
| lineHeight: 25, | |
| fontWeight: 'bold', | |
| color: 'white', | |
| padding: 10 | |
| }, | |
| abg: { | |
| backgroundColor: ColorAssets.get(asset.type), | |
| width: '100%', | |
| align: 'right', | |
| height: 25, | |
| borderRadius: [4, 4, 0, 0], | |
| }, | |
| icon: { | |
| height: 25, | |
| align: 'center', | |
| shadowColor: 'white', | |
| shadowBlur: 5, | |
| shadowOffsetX: 0, | |
| shadowOffsetY: 0, | |
| backgroundColor: { | |
| image: 'data:image://' + IconAssets.get(`${asset.type}`) | |
| } | |
| }, | |
| name: { | |
| fontSize: 12, | |
| fontWeight: 'bold', | |
| padding: 10, | |
| align: 'right', | |
| color: ColorAssets.get(asset.type) | |
| }, | |
| key: { | |
| fontWeight: 'bold', | |
| color: '#555', | |
| width: 20, | |
| padding: 10, | |
| align: 'left' | |
| }, | |
| value: { | |
| color: '#333', | |
| width: 20, | |
| padding: 10, | |
| align: 'right' | |
| } | |
| } | |
| } | |
| } | |
| SeriesAssetData.push(nonAdvObj) | |
| SeriesAssetData.push(nonAdvLabel) | |
| }) | |
| seriesCounter = seriesCounter + nonAdvAssets.length | |
| assetAdvs.forEach((adv, i) => { | |
| const label = t(adv?.type, { ns: 'asset' }) + ' ' + adv?.name | |
| const asset_start_pk = track ? Number(adv?.startLinearReference) : adv?.startSSCount | |
| const asset_end_pk = track ? Number(adv?.endLinearReference) : adv?.endSSCount | |
| const asset_middle_pk = ((asset_end_pk + asset_start_pk) / 2) | |
| const informations = adv.informations.filter((info) => info.type !== '' && info.value !== '').map((info) => ({ type: info.type, value: info.value })) | |
| const assetAdvObj = { | |
| id: `assetAdvs-${i}`, | |
| name: 'asset', | |
| type: 'line', | |
| triggerLineEvent: true, | |
| xAxisIndex: totalGraphs + 1, | |
| yAxisIndex: totalGraphs + 1, | |
| showSymbol: true, | |
| symbolSize: 0, | |
| symbol: 'diamond', | |
| data: [ | |
| [asset_start_pk, positionAssetY], | |
| [asset_middle_pk, positionAssetY], | |
| [asset_end_pk, positionAssetY] | |
| ], | |
| lineStyle: { | |
| type: 'solid', | |
| width: 2, | |
| color: ColorAssets.get(adv.type), | |
| }, | |
| itemStyle: { | |
| color: ColorAssets.get(adv.type), | |
| }, | |
| label: { | |
| show: false, | |
| distance: -19, | |
| formatter: '{bg|' + label + '}', | |
| rich: { | |
| bg: { | |
| color: ColorAssets.get(adv.type), | |
| fontWeight: 'bold', | |
| fontSize: 11, | |
| } | |
| }, | |
| }, | |
| emphasis: { | |
| scale: true, | |
| focus: 'series', | |
| lineStyle: { | |
| width: 4, | |
| z: 0 | |
| }, | |
| label: { | |
| show: true | |
| }, | |
| }, | |
| markPoint: { | |
| animation: false, | |
| data: [ | |
| { | |
| name: 'asset', | |
| symbol: 'image://' + IconAssets.get(adv.type), | |
| symbolOffset: [0, -16], | |
| symbolSize: 27, | |
| coord: [ | |
| asset_middle_pk, | |
| positionAssetY, | |
| { | |
| icon: 'image://' + IconAssets.get(`${adv.type}`), | |
| iconSelected: 'image://' + IconAssets.get(`${adv.type}-SEL`) | |
| } | |
| // adv?.startLinearReference?.toLocaleString(router.locale, { minimumFractionDigits: 3 }), | |
| // adv?.endLinearReference?.toLocaleString(router.locale, { minimumFractionDigits: 3 }), | |
| // { | |
| // label, | |
| // mode: adv.mode, | |
| // position: asset_moy_px, | |
| // informations: adv.informations.filter((info) => info.type !== '' && info.value !== '').map((info) => ({ type: info.type, value: info.value })) | |
| // } | |
| ] | |
| } | |
| ], | |
| emphasis: { | |
| scale: true, | |
| focus: 'series', | |
| } | |
| } | |
| } | |
| const AdvLabel = { | |
| id: `assetAdvs-${i}-label`, | |
| name: 'asset', | |
| type: 'scatter', | |
| z: 999999999, | |
| data: [[asset_middle_pk, positionAssetY + 0.6]], | |
| xAxisIndex: totalGraphs + 2, | |
| yAxisIndex: totalGraphs + 2, | |
| symbolSize: 0, | |
| showSymbol: false, | |
| itemStyle: { | |
| color: 'transparent', | |
| }, | |
| emphasis: { | |
| disabled: true | |
| }, | |
| label: { | |
| show: false, | |
| offset: [0, -100], | |
| // t(adv?.type, { ns: 'asset' }) + ' ' + adv?.name | |
| formatter: [ | |
| `{icon|} {title|${t(adv.type, { ns: 'asset' })}}{abg|}`, | |
| `{name|${adv.name} | ${t(adv.mode, { ns: 'common' })}}`, | |
| `{key|${t('ASSET_PK_START')}}{value|${adv.startLinearReference}}`, | |
| `{key|${t('ASSET_PK_END')}}{value|${adv.endLinearReference}}`, | |
| informations.length > 0 ? informations.map((info) => `{key|${info.type}}{value|${info.value}}`).join('\n') : '' | |
| ].filter(Boolean).join('\n'), | |
| backgroundColor: 'white', | |
| borderColor: ColorAssets.get(adv.type), | |
| borderWidth: 2, | |
| borderRadius: 4, | |
| padding: [0, 0, 5, 0], | |
| color: '#000', | |
| fontSize: 14, | |
| lineHeight: 18, | |
| rich: { | |
| title: { | |
| fontSize: 14, | |
| lineHeight: 25, | |
| fontWeight: 'bold', | |
| color: 'white', | |
| padding: 10 | |
| }, | |
| abg: { | |
| backgroundColor: ColorAssets.get(adv.type), | |
| width: '100%', | |
| align: 'right', | |
| height: 25, | |
| borderRadius: [4, 4, 0, 0], | |
| }, | |
| icon: { | |
| height: 25, | |
| align: 'center', | |
| shadowColor: 'white', | |
| shadowBlur: 5, | |
| shadowOffsetX: 0, | |
| shadowOffsetY: 0, | |
| backgroundColor: { | |
| image: 'data:image://' + IconAssets.get(`${adv.type}`) | |
| } | |
| }, | |
| name: { | |
| fontSize: 12, | |
| fontWeight: 'bold', | |
| padding: 10, | |
| align: 'right', | |
| color: ColorAssets.get(adv.type) | |
| }, | |
| key: { | |
| fontWeight: 'bold', | |
| color: '#555', | |
| width: 20, | |
| padding: 10, | |
| align: 'left' | |
| }, | |
| value: { | |
| color: '#333', | |
| width: 20, | |
| padding: 10, | |
| align: 'right' | |
| } | |
| } | |
| } | |
| } | |
| SeriesAssetData.push(assetAdvObj) | |
| SeriesAssetData.push(AdvLabel) | |
| }) | |
| // --------------------------------------------------------------------------- | |
| // *************************************************************************** | |
| // Create series data Array | |
| // --------------------------------------------------------------------------- | |
| const series = [] as any | |
| const datasetIndexStart = dataLength * campaignsId.length | |
| // totalGraphs = liste des graphs (measures non applaties) | |
| // dataLength = liste des measures applaties | |
| // track les measures sont toujours applati : | |
| // [ ['measure1'], ['measure2'] ] -> totalGraphs = dataLength = 2 | |
| // itinerary les measures sont composé: | |
| //[ ['measure1', 'measure2'], ['measure3', 'measure3'] ] -> totalGraphs 2, = dataLength = 4 | |
| const createMeasureAxisIterrator = (layout: string[][]) => { | |
| const axisMeasures = layout.map((graph, index) => { | |
| return graph.map((_) => { | |
| return index | |
| }) | |
| }).flatMap(s => s) | |
| return axisMeasures[Symbol.iterator]() | |
| } | |
| const axisMeasuresIndex = createMeasureAxisIterrator(graphsLayout) | |
| // foreach on campaignsId | |
| campaignsId.forEach((campaignId, index) => { | |
| for (let i = 0;i < dataLength;i++) { | |
| const measure = measures[i] | |
| if (measure) { | |
| // get the layout position for Xaxis and yAxis | |
| // const layoutPosition = track ? i : getMeasureLayoutPosition(measure, graphsLayout) | |
| const layoutPosition = track ? i : axisMeasuresIndex.next().value | |
| series.push({ | |
| id: `series-${i}-campaignID${campaignId}`, | |
| name: track ? `${campaignId}` : `${measure}-campaignID${campaignId}`, | |
| // name: `${measure}-campaignID${campaignId}`, | |
| nameId: `${campaignId}`, | |
| type: 'line', | |
| datasetIndex: datasetIndexStart + i + (dataLength * index), | |
| largeThreshold: 2000, | |
| xAxisIndex: layoutPosition, | |
| yAxisIndex: layoutPosition, | |
| showSymbol: true, | |
| hoverAnimation: false, | |
| animation: false, | |
| // symbolSize: 0.1, | |
| endLabel: { | |
| show: false, | |
| }, | |
| labelLine: { | |
| show: false, | |
| }, | |
| encode: { | |
| tooltip: [1, 3, 2], | |
| x: track ? 'pk' : 'sscount', | |
| y: 'value', | |
| }, | |
| lineStyle: { | |
| width: 0.8, | |
| }, | |
| itemStyle: { | |
| color: getSeverityColor(1, 0, totalGraphs), | |
| }, | |
| emphasis: { | |
| scale: true, | |
| focus: 'series', | |
| }, | |
| }) | |
| } | |
| } | |
| }) | |
| // Path (Parcours) series | |
| series.push(...SeriesItineraryData) | |
| // Assets (Patrimoine) series | |
| series.push(...SeriesAssetData) | |
| // console.log('series', series, 'dataset', dataset) | |
| // return {} | |
| // <--- end series Array | |
| // *************************************************************************** | |
| // *************************************************************************** | |
| // Create visualMap pieces with thresholds | |
| // --------------------------------------------------------------------------- | |
| // Attention : here map through thresholds 2 times : one for each measure and one for each threshold | |
| const baseColor = getSeverityColor(1) | |
| const defaultVisualMapPiece = { | |
| type: 'piecewise', | |
| bottom: 50, | |
| right: 10, | |
| dimension: track ? 1 : 0, | |
| show: false, | |
| color: [baseColor], | |
| symbolSize: 0, | |
| outOfRange: { | |
| color: baseColor, | |
| symbolSize: 0 | |
| }, | |
| seriesIndex: 'all' | |
| } | |
| let visualMapPieces: any = [] | |
| const thresholdsMap = graphData.map((d) => ({ | |
| data: d.thresholds, | |
| measureName: d.measureName, | |
| runId: d.runId | |
| })) | |
| if (thresholdsMap.length > 0) { | |
| visualMapPieces = thresholdsMap.map((threshold, index) => { | |
| const tresholdPieces = threshold.data.map((item) => { | |
| return { | |
| label: item.label, | |
| min: item.min, | |
| max: item.max, | |
| color: item.color, | |
| } | |
| }) | |
| let positionColor = 0 | |
| if (track) { | |
| positionColor = threshold.runId | |
| } else { | |
| positionColor = getMeasurePosition(threshold.measureName, graphsLayout) | |
| } | |
| const measuresCountPerGraph = track ? campaignsId.length + 1 : 2 | |
| const color = getSeverityColor(1, positionColor, measuresCountPerGraph) | |
| const baseVisualMapPiece = { | |
| type: 'piecewise', | |
| bottom: 50, | |
| right: 10, | |
| dimension: track ? 1 : 0, | |
| show: false, | |
| color: [color], | |
| symbolSize: 0.1, | |
| outOfRange: { | |
| color: color, | |
| symbolSize: 0.1 | |
| }, | |
| } | |
| return { ...baseVisualMapPiece, pieces: tresholdPieces, seriesIndex: index } | |
| }) | |
| } | |
| const visualMapPoints = { | |
| // setup for point severity color | |
| type: 'piecewise', | |
| orient: 'horizontal', | |
| show: false, | |
| selectedMode: false, | |
| padding: [20, 10 + GridPadLeft], | |
| dimension: 5, // set the column which is used in categories (severity) // 2 | |
| seriesIndex: Array.from(Array(thresholdsMap.length).keys()), | |
| // categories: classifications, | |
| categories: [1, 2, 3, 4], | |
| inRange: { | |
| symbolSize: [0.1, 3, 4, 5], // 4 levels defect classification by size | |
| // color: [1, 2, 3, 4].map((d: any) => getSeverityColor(d)), | |
| color: [getSeverityColor(1), DScolorSeverity[1], DScolorSeverity[2], DScolorSeverity[3]], // 'VO' 'VA' 'VI' 'VR' | |
| symbol: { | |
| '': 'circle', | |
| }, | |
| }, | |
| outRange: { | |
| symbolSize: [0.1], | |
| symbol: { | |
| '': 'circle', | |
| }, | |
| } | |
| } | |
| // const FinalvisualMapPieces = [...visualMapPieces] | |
| const FinalvisualMapPieces = [...visualMapPieces, visualMapPoints] | |
| // <--- end visualMap | |
| // *************************************************************************** | |
| // synchronize dataZoom axis graphs | |
| const dataZoomSync = Array.from(Array(totalGraphs).keys()) | |
| // const dataZoomSync = measures.map((d, i) => i) | |
| // add dataZoom sync for path (section) | |
| // dataZoomSync.push(dataZoomSync.length) | |
| // add dataZoom sync for asset (patrimoine) | |
| dataZoomSync.push(dataZoomSync.length + 1) | |
| // *************************************************************************** | |
| // DataZooms creation | |
| // --------------------------------------------------------------------------- | |
| const dataZoom = [ | |
| { | |
| // dataZoom inside for all measures | |
| type: 'inside', | |
| maxSpan: 100, | |
| minSpan: 0.02, | |
| start: initZoomState[0], | |
| end: initZoomState[1], | |
| xAxisIndex: dataZoomSync, | |
| filterMode: 'none', | |
| zoomOnMouseWheel: 'ctrl', | |
| }, | |
| { | |
| // X Top Global DataZoom Slider | |
| type: 'slider', | |
| show: true, | |
| start: initZoomState[0], | |
| end: initZoomState[1], | |
| realtime: true, | |
| showDetail: true, | |
| labelFormatter: (value: any, valueStr: string) => { | |
| if (track) return valueStr | |
| if (dataset[0]?.source === undefined) return '' | |
| const sorted = dataset[0].source.sort( | |
| (a, b) => Math.abs(a[0] - Number(valueStr)) - Math.abs(b[0] - Number(valueStr)) | |
| ) | |
| if (sorted[0] === undefined) return '' | |
| return sorted[0][1] | |
| }, | |
| xAxisIndex: dataZoomSync, | |
| height: 8, // 50 | |
| left: GridPadLeft, | |
| right: gridPadRight - 15, | |
| top: 52, // 0 | |
| filterMode: 'none', | |
| // inactive the drawing zoom feature | |
| brushSelect: false, | |
| borderRadius: 0, | |
| borderColor: 'transparent', | |
| // Remove graph shadow | |
| showDataShadow: false, | |
| backgroundColor: bgAxisColor, | |
| fillerColor: 'DodgerBlue', | |
| handleIcon: 'path:M2 1C2 1.55229 1.55228 2 1 2C0.447716 2 0 1.55229 0 1C0 0.447708 0.447716 0 1 0C1.55228 0 2 0.447708 2 1Z,M6 1C6 1.55229 5.55228 2 5 2C4.44772 2 4 1.55229 4 1C4 0.447708 4.44772 0 5 0C5.55228 0 6 0.447708 6 1Z,M9 2C9.55228 2 10 1.55229 10 1C10 0.447708 9.55228 0 9 0C8.44772 0 8 0.447708 8 1C8 1.55229 8.44772 2 9 2Z', | |
| handleSize: 20, | |
| handleStyle: { color: 'white', borderColor: '#ddd', borderWidth: 0 }, | |
| textStyle: { | |
| color: 'white', | |
| fontWeight: 'bold', | |
| lineHeight: 11, | |
| fontSize: 11, | |
| backgroundColor: 'DodgerBlue', | |
| padding: [1, 3, 1, 3], | |
| borderRadius: 2, | |
| }, | |
| emphasis: { | |
| // handleStyle: { borderColor: 'PowderBlue' }, | |
| }, | |
| }, | |
| ] | |
| if (offline) { | |
| for (let i = 0;i < totalGraphs;i++) { | |
| dataZoom.push({ | |
| // Y dataZoom Slider for measure #i | |
| type: 'slider', | |
| yAxisIndex: [i], | |
| right: gridPadRight - 15, | |
| width: 10, // 20, | |
| brushSelect: false, | |
| show: true, | |
| filterMode: 'none', | |
| handleSize: '150%', | |
| showDataShadow: false, | |
| handleStyle: { color: 'gray', borderColor: '#ccc', borderWidth: 1 }, | |
| } as any) | |
| dataZoom.push({ | |
| // Y dataZoom inside for measure #i | |
| type: 'inside', | |
| maxSpan: 100, | |
| minSpan: 0.02, | |
| yAxisIndex: [i], | |
| filterMode: 'none', | |
| zoomOnMouseWheel: 'shift', | |
| } as any) | |
| } | |
| } | |
| // <--- end DataZooms | |
| // ************************************************************************** | |
| // graphic for Background Axis color with bgAxisColor ----> | |
| const graphic = [ | |
| { | |
| type: 'group', | |
| bounding: 'raw', | |
| left: GridPadLeft, | |
| right: gridPadRight + 10, | |
| top: WindowHeight! - 226 - totalGaps + totalGraphs * gapGrid, | |
| z: 0, | |
| children: [ | |
| { | |
| type: 'rect', | |
| z: 1, | |
| shape: { | |
| width: WindowWidth + 11, | |
| height: 30, | |
| }, | |
| style: { | |
| fill: bgAxisColor, | |
| }, | |
| }, | |
| ], | |
| }, | |
| { | |
| type: 'group', | |
| bounding: 'raw', | |
| top: 59 - 7, | |
| right: gridPadRight - 15, | |
| z: 0, | |
| children: [ | |
| { | |
| type: 'rect', | |
| z: 1, | |
| shape: { | |
| width: 40, | |
| height: WindowHeight! - 284 + 7 - totalGaps + totalGraphs * gapGrid, | |
| }, | |
| style: { | |
| fill: bgAxisColor, | |
| }, | |
| }, | |
| ], | |
| }, | |
| ] | |
| // <----- end graphic | |
| // ************************************************************************** | |
| // ********************* | |
| // ********************* | |
| // Create echarts option | |
| // ********************* | |
| // ********************* | |
| const option = { | |
| graphic: graphic, | |
| width: String(WindowWidth) + 'px', | |
| grid: grid, | |
| dataset: dataset, | |
| xAxis: xAxis, | |
| yAxis: yAxis, | |
| series: series, | |
| dataZoom: dataZoom, | |
| legend: { | |
| // show: track ? true : false, | |
| show: false, | |
| top: 10, | |
| left: 25, | |
| z: 99999, | |
| formatter: function (name: string) { | |
| const campaign = campaignsInfo?.docs.find((item) => item.id === name) | |
| return campaign?.date.toLocaleString(router.locale) | |
| }, | |
| data: campaignsId.map((campaignId, index) => { | |
| return { | |
| name: campaignId, | |
| icon: 'circle', | |
| itemStyle: { | |
| color: getSeverityColor(1, index, campaignsId.length + 1), | |
| } | |
| } | |
| }), | |
| }, | |
| visualMap: pending ? defaultVisualMapPiece : FinalvisualMapPieces, | |
| tooltip: { | |
| trigger: 'axis', // => 'axis' show all measures graphData in tooltip, 'item' show one measure | |
| alwaysShowContent: true, // if you want the tooltip fixed | |
| shadowBlur: 0, | |
| shadowOffsetX: 0, | |
| shadowOffsetY: 0, | |
| backgroundColor: 'transparent', | |
| borderColor: 'transparent', | |
| padding: 0, | |
| position: [String(tooltipPosX) + 'px', topPaddingForActionBar + GridPadY - 6 + 'px'], | |
| formatter: (params: any) => { | |
| // data dimension : ['sscount', 'pk', 'severity', 'value', 'id'] | |
| let html = '<div>' | |
| if (track) { | |
| // track mode | |
| measures.forEach((measure) => { | |
| html += ` | |
| <section style="height: ${heightGrid}px; margin-bottom: ${gapGrid}px; padding-top: 12px;"> | |
| <div style=" | |
| font-size: 12px; | |
| color: #666; | |
| font-weight: 400; | |
| text-align: right; | |
| width: 45px; | |
| float: left; | |
| "> | |
| ${t(measure.toUpperCase(), { ns: 'measure' })} | |
| </div> | |
| ` | |
| campaignsId.forEach((campaignId, index) => { | |
| // const measureName = `${measure}-campaignID${campaignId}` | |
| const measureName = `series-${index}-campaignID${campaignId}` | |
| // const data = params.find((p: any) => p.seriesName === measureName) | |
| const data = params.find((p: any) => p.seriesId === measureName) | |
| if (data === undefined) return null | |
| const pk = data.value[1]?.toLocaleString(router.locale, { minimumFractionDigits: 3 }) | |
| const severity = data.value[5] as number // point[5] = level | |
| let value = null | |
| if (data.value[3]) value = data.value[3].toLocaleString(router.locale, measurePrecision) | |
| const color = DScolorSeverity[severity] // const color = getSeverityColor(severity) | |
| const colorMeasureBase = getSeverityColor(1, index, campaignsId.length) // 'VO' color | |
| html += ` | |
| <span style=" | |
| margin-left: 6px; | |
| border-color: ${colorMeasureBase}; | |
| background-color: rgba(255,255,255,0.65); | |
| border-width: 2px; | |
| border-radius: 5px; | |
| padding: 2px 4px | |
| "> | |
| <span | |
| style=" | |
| display: inline-block; | |
| border-radius: 10px; | |
| width: 10px; | |
| height: 10px; | |
| background-color: ${color}; " | |
| ></span> | |
| <span | |
| style=" | |
| font-size: 12px; | |
| color: #666; | |
| font-weight: 400;" | |
| >${value} | |
| </span> | |
| </span> | |
| ` | |
| }) | |
| html += `</section><div>` | |
| }) | |
| } else { | |
| // itinary mode | |
| graphsLayout.forEach((graph, index) => { | |
| html += `<section style="height: ${heightGrid}px; margin-bottom: ${gapGrid}px; padding-top: 12px;">` | |
| graph.forEach((measure, index) => { | |
| const seriesName = params[0].seriesName | |
| const data = params.find((p: any) => p.seriesName === `${measure}-campaignID${campaignsId[0]}`) | |
| if (data === undefined) return null | |
| const pk = data.value[1]?.toLocaleString(router.locale, { minimumFractionDigits: 3 }) | |
| const severity = data.value[5] as number // point[5] = level | |
| let value = null | |
| if (data.value[3]) value = data.value[3].toLocaleString(router.locale, measurePrecision) | |
| const color = getSeverityColor(severity) | |
| const colorMeasureBase = getSeverityColor(1, index, 2) // 'VO' color | |
| html += ` | |
| <span style=" | |
| margin-left: 10px; | |
| border-color: ${colorMeasureBase}; | |
| background-color: rgba(255,255,255,0.65); | |
| border-width: 2px; | |
| border-radius: 5px; | |
| padding: 2px 4px | |
| "> | |
| <span style=" | |
| font-size: 12px; | |
| color: #666; | |
| font-weight: 400;">${t(measure.toUpperCase(), { ns: 'measure' })} | |
| </span> | |
| <span | |
| style=" | |
| display: inline-block; | |
| border-radius: 10px; | |
| width: 10px; | |
| height: 10px; | |
| background-color: ${color};" | |
| ></span> | |
| <span | |
| style=" | |
| font-size: 12px; | |
| color: #666; | |
| font-weight: 400;" | |
| >${value} | |
| </span | |
| </span> | |
| </span> | |
| ` | |
| }) | |
| html += `</section>` | |
| }) | |
| } | |
| return `${html}` | |
| }, | |
| axisPointer: { type: 'cross' }, | |
| }, | |
| axisPointer: { | |
| animation: false, | |
| snap: true, | |
| z: -10, | |
| link: [ | |
| { | |
| xAxisIndex: [0, 1, 2, 3], | |
| }, | |
| ], | |
| lineStyle: { | |
| width: 1, | |
| color: 'gray', | |
| type: 'dashed', | |
| }, | |
| label: { | |
| show: true, | |
| formatter: (params: any) => { | |
| if (params.axisIndex > totalGraphs - 1) { | |
| return null | |
| } | |
| if (params.axisDimension === 'y' && params.axisIndex < totalGraphs) { | |
| return '{box|' + Math.round(params.value) + '}' | |
| } | |
| if (params.axisDimension === 'x' && params.axisIndex === totalGraphs - 1) { | |
| const value = params.value | |
| if (track) return '{box|' + value.toLocaleString(router.locale, { minimumFractionDigits: 3 }) + '}' | |
| let newValue = '' | |
| if (graphData[1]?.data) { | |
| const sortedData = graphData[1].data.sort((a, b) => Math.abs(a[0] - value) - Math.abs(b[0] - value)) | |
| if (sortedData[0]) { | |
| newValue = sortedData[0]?.[1]?.toLocaleString(router.locale, { minimumFractionDigits: 3 }) | |
| } | |
| } else { | |
| return null | |
| } | |
| return '{box|' + newValue + '}' | |
| } | |
| }, | |
| margin: 0, | |
| padding: [10, -36, 4, 7], | |
| verticalAlign: 'middle', | |
| align: 'center', | |
| height: 4, | |
| backgroundColor: 'transparent', | |
| color: 'black', | |
| rich: { | |
| box: { | |
| backgroundColor: '#E5342A', | |
| lineHeight: 26, | |
| align: 'center', | |
| verticalAlign: 'middle', | |
| width: 32, | |
| height: 20, | |
| color: 'white', | |
| padding: 4, | |
| borderRadius: 4, | |
| fontSize: 11, | |
| }, | |
| }, | |
| }, | |
| }, | |
| animation: false, | |
| } | |
| return option | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment