| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 | /* * << * Davinci * == * Copyright (C) 2016 - 2017 EDP * == * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * >> */import { IChartProps } from '../../components/Chart'import {  decodeMetricName,  getChartTooltipLabel,  getSizeValue,  getSizeRate} from '../../components/util'import {  getMetricAxisOption,  getLabelOption,  getLegendOption,  getGridPositions,  getSymbolSize,  getCartesianChartReferenceOptions} from './util'import { PIVOT_DEFAULT_SCATTER_SIZE } from 'app/globalConstants'import ChartTypes from '../../config/chart/ChartTypes'export default function (chartProps: IChartProps, drillOptions?: any) {  const {    data,    cols,    metrics,    chartStyles,    color,    tip,    size,    references  } = chartProps  const {    spec,    xAxis,    yAxis,    splitLine,    label: labelStyleConfig,    legend  } = chartStyles  const {    showVerticalLine,    verticalLineColor,    verticalLineSize,    verticalLineStyle,    showHorizontalLine,    horizontalLineColor,    horizontalLineSize,    horizontalLineStyle  } = splitLine  const { selectedItems } = drillOptions  const labelOption = {    label: getLabelOption('scatter', labelStyleConfig, metrics)  }  const referenceOptions = getCartesianChartReferenceOptions(references, ChartTypes.Scatter, metrics, data)  let sizeRate = 0  let sizeItemName = ''  if (size.items.length) {    const sizeItem = size.items[0]    sizeItemName = `${sizeItem.agg}(${decodeMetricName(sizeItem.name)})`    const sizeValues = data.map((d) => d[sizeItemName])    sizeRate = getSizeRate(Math.min(...sizeValues), Math.max(...sizeValues))  }  const series = []  const seriesData = []  if (cols.length || color.items.length) {    const groupColumns = color.items.map((c) => c.name).concat(cols.map((c) => c.name))      .reduce((distinctColumns, col) => {        if (!distinctColumns.includes(col)) {          distinctColumns.push(col)        }        return distinctColumns      }, [])    const grouped = data.reduce((obj, val) => {      const groupingKey = groupColumns        .reduce((keyArr, col) => keyArr.concat(val[col]), [])        .join(String.fromCharCode(0))      if (!obj[groupingKey]) {        obj[groupingKey] = []      }      obj[groupingKey].push(val)      return obj    }, {})    const labelItemName = color.items.length      ? color.items[0].name      : cols[0].name    const groupedEntries = Object.entries(grouped)    groupedEntries.forEach(([key, value], gIndex) => {      series.push({        name: key.replace(String.fromCharCode(0), ' '),        type: 'scatter',        data: value.map((v, index) => {          const [x, y] = metrics          const currentSize = size.items.length ? v[sizeItemName] : PIVOT_DEFAULT_SCATTER_SIZE          const sizeValue = getSizeValue(size.value['all'])          const itemStyleObj = selectedItems && selectedItems.length && selectedItems.some((item) => item === gIndex) ? {itemStyle: {            normal: {              opacity: 1            }          }} : {}          return {            ...itemStyleObj,            value: [              v[`${x.agg}(${decodeMetricName(x.name)})`],              v[`${y.agg}(${decodeMetricName(y.name)})`],              v[labelItemName],              currentSize            ],            symbolSize: size.items.length              ? getSymbolSize(sizeRate, currentSize) * sizeValue              : currentSize * sizeValue          }        }),        itemStyle: {          normal: {            color: color.items.length              ? color.items[0].config.values[key.split(String.fromCharCode(0))[0]]              : color.value['all'],            opacity: selectedItems && selectedItems.length > 0 ? 0.25 : 1          }        },        ...labelOption,        ...(gIndex === groupedEntries.length - 1 && referenceOptions)      })      seriesData.push(value)    })  } else {    series.push({      name: 'single',      type: 'scatter',      data: data.map((d, index) => {        const [x, y] = metrics        const currentSize = size.items.length ? d[sizeItemName] : PIVOT_DEFAULT_SCATTER_SIZE        const sizeValue = getSizeValue(size.value['all'])        const itemStyleObj = selectedItems && selectedItems.length && selectedItems.some((item) => item === index) ? {itemStyle: {          normal: {            opacity: 1          }        }} : {}        return {          ...itemStyleObj,          value: [            d[`${x.agg}(${decodeMetricName(x.name)})`],            d[`${y.agg}(${decodeMetricName(y.name)})`],            '',            currentSize          ],          symbolSize: size.items.length            ? getSymbolSize(sizeRate, currentSize) * sizeValue            : currentSize * sizeValue        }      }),      itemStyle: {        normal: {          color: color.value['all'],          opacity: selectedItems && selectedItems.length > 0 ? 0.25 : 1        }      },      ...labelOption,      ...referenceOptions    })    seriesData.push(data)  }  const seriesNames = series.map((s) => s.name)  // dataZoomOptions = dataZoomThreshold > 0 && dataZoomThreshold < dataSource.length && {  //   dataZoom: [{  //     type: 'inside',  //     start: Math.round((1 - dataZoomThreshold / dataSource.length) * 100),  //     end: 100  //   }, {  //     start: Math.round((1 - dataZoomThreshold / dataSource.length) * 100),  //     end: 100,  //     handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',  //     handleSize: '80%',  //     handleStyle: {  //       color: '#fff',  //       shadowBlur: 3,  //       shadowColor: 'rgba(0, 0, 0, 0.6)',  //       shadowOffsetX: 2,  //       shadowOffsetY: 2  //     }  //   }]  // }  const {isDrilling, getDataDrillDetail, instance } = drillOptions  const brushedOptions = isDrilling === true ? {    brush: {      toolbox: ['rect', 'polygon', 'keep', 'clear'],      throttleType: 'debounce',      throttleDelay: 300,      brushStyle: {        borderWidth: 1,        color: 'rgba(255,255,255,0.2)',        borderColor: 'rgba(120,140,180,0.6)'      }    }  } : null  if (isDrilling) {    //  instance.off('brushselected')     // instance.on('brushselected', brushselected)      setTimeout(() => {          instance.dispatchAction({          type: 'takeGlobalCursor',          key: 'brush',          brushOption: {            brushType: 'rect',            brushMode: 'multiple'          }        })      }, 0)    }  function brushselected (params) {    console.log({params})  //  console.log({seriesData})    const brushComponent = params.batch[0]    const brushed = []    const sourceData = seriesData[0]    let range: any[] = []    if (brushComponent && brushComponent.areas && brushComponent.areas.length) {      brushComponent.areas.forEach((area) => {        range = range.concat(area.range)      })    }    if (brushComponent && brushComponent.selected && brushComponent.selected.length) {      for (let i = 0; i < brushComponent.selected.length; i++) {        const rawIndices = brushComponent.selected[i].dataIndex        const seriesIndex = brushComponent.selected[i].seriesIndex        brushed.push({[i]: rawIndices})      }    }   // console.log({sourceData})    if (getDataDrillDetail) {      getDataDrillDetail(JSON.stringify({range, brushed, sourceData}))    }  }  const xAxisSplitLineConfig = {    showLine: showVerticalLine,    lineColor: verticalLineColor,    lineSize: verticalLineSize,    lineStyle: verticalLineStyle  }  const yAxisSplitLineConfig = {    showLine: showHorizontalLine,    lineColor: horizontalLineColor,    lineSize: horizontalLineSize,    lineStyle: horizontalLineStyle  }  return {    xAxis: getMetricAxisOption(xAxis, xAxisSplitLineConfig, decodeMetricName(metrics[0].name), 'x'),    yAxis: getMetricAxisOption(yAxis, yAxisSplitLineConfig, decodeMetricName(metrics[1].name)),    series,    tooltip: {      formatter: getChartTooltipLabel('scatter', seriesData, { cols, metrics, color, tip })    },    legend: getLegendOption(legend, seriesNames),    grid: getGridPositions(legend, seriesNames, '', false, yAxis)    // ...brushedOptions  }}
 |