import * as d3 from 'd3';
import { setNewValue } from '../../../utils/util';

/**
 * data 图数据
 * id 图id
 * height 图高 500
 * margin { top: 80, right: 40, bottom: 130, left: 40 }
 * margin2 { top: 410, right: 40, bottom: 60, left: 40 }
 * titleY 图的Y轴标题 例如：顾客人数 (人)
 * titleConfig: { title: '', fontSize: '14px', fontWeight: '700', color: '#fff' } 标题
 * pointsConfig: { r: 5, color: 'orange' }  转点
 * valConfig: { fontSize: '12px', fontWeight: '500', color: '#000' } value文字样式
 */
const D3SimpleAreaChart = (params) => {
  const defaultConfig = {
    areaColor: '#4682B4',
    smallAreaColor: '#4682B4',
    margin: { top: 80, right: 40, bottom: 130, left: 40 },
    margin2: { top: 410, right: 40, bottom: 60, left: 40 },
    titleConfig: { title: '', fontSize: '16px', fontWeight: '700', color: '#000' },
    titleYConfig: { title: '', fontSize: '10px', fontWeight: '500', color: '#000' },
    pointsConfig: { r: 5, color: 'orange' },
    valConfig: { fontSize: '12px', fontWeight: '500', color: '#000' }
  }
  const {
    initData,
    id,
    height,
    margin,
    margin2,
    titleConfig,
    titleYConfig,
    areaColor,
    smallAreaColor,
    pointsConfig,
    valConfig
  } = params;
  const container = document.getElementById(`${id}`);
  if (!container) return;
  const width = container.offsetWidth;

  const _margin = setNewValue(margin, defaultConfig.margin);
  const _margin2 = setNewValue(margin2, defaultConfig.margin2);

  const _width = width - _margin.left - _margin.right;
  const _height = height - _margin.top - _margin.bottom;
  const _height2 = height - _margin2.top - _margin2.bottom;

  const _titleConfig = setNewValue(titleConfig, defaultConfig.titleConfig);
  const _titleYConfig = setNewValue(titleYConfig, defaultConfig.titleYConfig);
  const _pointsConfig = setNewValue(pointsConfig, defaultConfig.pointsConfig);
  const _valConfig = setNewValue(valConfig, defaultConfig.valConfig);

  // 设置总宽高
  let svg = d3.select(`#${id}`)
    .append('svg')
    .attr('width',  width)
    .attr('height', height);

  const parseDate = d3.timeParse('%Y-%m')

  const data = initData.map(item => {
    // 把原始数据转为d3可接受的数据
    return { ...item, day: parseDate(item.day) }
  })
  // 设置mainChart x轴
  let x = d3.scaleTime()
    .range([0, _width])
    .domain(
      d3.extent(data, function(d) {
        return d.day
      })
    );
  // 设置subChart x轴
  let x2 = d3.scaleTime()
    .range([0, _width])
    .domain(x.domain());
    let y = d3
    .scaleLinear()
    .rangeRound([_height, 0])
    .domain([
      0,
      d3.max(data, function(d) {
        return d.value
      })
    ]);
  // 设置subChart y轴
  let y2 = d3.scaleLinear()
    .range([_height2, 0])
    .domain(y.domain());
  // 设置brush
  const brush = d3.brushX()
    .extent([[0, 0], [_width, _height2]])
    .on('brush end', function(event) {
      brushed(event)
    });
  // 设置zoom
  const zoom = d3.zoom()
    .scaleExtent([1, Infinity])
    .translateExtent([[0, 0], [_width, _height]])
    .extent([[0, 0], [_width, _height]])
    .on('zoom', function(event) {
      zoomed(event)
    });
  
  svg.append('defs')
    .append('clipPath') // 添加长方形方块，遮罩作用
    .attr('id', 'clip')
    .append('rect')
    .attr('height', _height)
    .attr('width', 0) // 用遮罩实现线动画
    .transition()
    .duration(1000)
    .attr('width', _width);

  /***  mainChart部分  ***/
  const mainAreaPath = d3.area() // 设置mainChart面积图路径
    .curve(d3.curveMonotoneX)
    .x(function(d, i) {
      return x(d.day)
    })
    .y1(function(d, i) {
      return y(d.value)
    })
    .y0(y(0));

  const xAxis = d3.axisBottom(x).tickFormat(d3.timeFormat('%Y年%m月'));
  // 设mainChart在最外包层在总图上的相对位置
  let mainChart = svg.append('g')
    .attr('class', 'main-chart')
    .attr('transform', 'translate(' + _margin.left + ',' + _margin.top + ')');
  // 设置x轴
  mainChart.append('g') 
    .attr('class', 'axis axis--x')
    .attr('transform', 'translate(0,' + _height + ')')
    .call(xAxis);
  // 设置y轴
  mainChart.append('g') 
    .attr('class', 'axis axis--y')
    .call(d3.axisLeft(y).ticks(10))
    .append('text')
    .attr('y', -16)
    .attr('dy', '.71em')
    .style('text-anchor', 'middle')
    .style('fill', _titleYConfig.color)
    .style('font-weight', _titleYConfig.fontWeight)
    .style('font-size', _titleYConfig.fontSize)
    .text(_titleYConfig.title);
  // 画背景线
  mainChart.selectAll('.axis--y .tick') 
    .append('line')
    .attr('class', 'bg-line')
    .attr('stroke', '#fff1c9')
    .attr('shape-rendering', 'crispEdges')
    .attr('x2', _width);
  mainChart.select('.axis--y .bg-line:last-of-type').remove();
  // 画面积图
  mainChart.append('path') 
    .attr('class', 'area')
    .datum(data)
    .attr('d', mainAreaPath)
    .attr('stroke', 'none')
    .attr('stroke-width', 1)
    .attr('clip-path', 'url(#clip)')
    .attr('fill', areaColor || defaultConfig.areaColor);
  // 输出点
  let circles = mainChart.append('g');
  // 输出图上的数值
  let values = mainChart.append('g') 
    .attr('class', 'area--text');
  /***  subChart部分  ***/
  const subAreaPath = d3.area() // 设置subChart面积图路径
    .curve(d3.curveMonotoneX)
    .x(function(d) {
      return x2(d.day)
    })
    .y0(_height2)
    .y1(function(d) {
      return y2(d.value)
    });

  let subChart = svg.append('g')
    .attr('class', 'sub-chart')
    .attr('transform', 'translate(' + _margin2.left + ',' + _margin2.top + ')'); // 设subChart在最外包层在总图上的相对位置
  // 设置x轴
  subChart.append('g')
    .attr('class', 'axis axis--x')
    .attr('transform', 'translate(0,' + _height2 + ')')
    .call(d3.axisBottom(x2).tickFormat(d3.timeFormat('%Y年%m月')));
  // 画面积图
  subChart.append('path')
    .attr('class', 'area')
    .datum(data)
    .attr('d', subAreaPath)
    .attr('stroke', 'none')
    .attr('stroke-width', 1)
    .attr('fill', smallAreaColor || defaultConfig.smallAreaColor);
  // 添加画刷
  subChart.append('g')
    .attr('class', 'brush')
    .call(brush)
    .call(brush.move, [(_width * 2) / 3, _width]);
  /***  其他部分  ***/
  // 添加刷放方块
  svg.append('rect')
    .attr('class', 'zoom')
    .attr('width', _width)
    .attr('height', _height)
    .attr('cursor', 'move')
    .attr('pointer-events', 'all')
    .attr('fill', 'none')
    .attr('transform', 'translate(' + _margin.left + ',' + _margin.top + ')')
    .call(zoom);
  // 输出标题
  svg.append('g')
    .attr('class', 'chart--title')
    .append('text')
    .attr('fill', _titleConfig.color)
    .attr('font-size', _titleConfig.fontSize)
    .attr('font-weight', _titleConfig.fontWeight)
    .attr('transform', 'translate(' + 0 + ',' + 20 + ')')
    .attr('text-anchor', 'middle')
    .attr('x', width / 2)
    .attr('y', 0)
    .text(_titleConfig.title);

  /***  函数部分  ***/
  function brushed(event) {
    if (event.sourceEvent && event.sourceEvent.type === 'zoom') return;
    let s = event.selection || x2.range();
    x.domain(s.map(x2.invert, x2));
    mainChart.select('.area').attr('d', mainAreaPath);
    mainChart.select('.axis--x').call(xAxis);
    addPointsAndValues();
    svg.select('.zoom')
      .call(
        zoom.transform,
        d3.zoomIdentity.scale(_width / (s[1] - s[0])).translate(-s[0], 0)
      );
  }

  function zoomed(event) {
    if (event.sourceEvent && event.sourceEvent.type === 'brush') return;
    let t = event.transform;
    x.domain(t.rescaleX(x2).domain());
    mainChart.select('.area').attr('d', mainAreaPath);
    mainChart.select('.axis--x').call(xAxis);
    addPointsAndValues();
    subChart.select('.brush').call(brush.move, x.range().map(t.invertX, t));
  }

  function addPointsAndValues() {
    // 动态修改添加的点和值
    circles.selectAll('circle').remove();
    circles.selectAll('circle')
      .attr('class', 'points')
      .data(data)
      .enter()
      .append('circle')
      .attr('fill', function(d) {
        let cx = x(d.day)
        if (cx >= 0 && cx <= _width) {
          return _pointsConfig.color
        } else {
          return 'none'
        }
      })
      .attr('cx', function(d) {
        return x(d.day)
      })
      .attr('cy', function(d) {
        return y(d.value)
      })
      .attr('r', _pointsConfig.r);

    values.selectAll('text').remove();
    values.selectAll('text')
      .data(data)
      .enter()
      .append('text')
      .attr('fill', function(d) {
        let cx = x(d.day)
        if (cx >= 0 && cx <= _width) {
          return _valConfig.color
        } else {
          return 'none'
        }
      })
      .attr('font-size', _valConfig.fontSize)
      .attr('font-weight', _valConfig.fontWeight)
      .attr('text-anchor', 'middle')
      .attr('x', function(d, i) {
        return x(d.day)
      })
      .attr('y', function(d) {
        return y(d.value)
      })
      .attr('dx', '1.5em')
      .attr('dy', '0.1em')
      .text(function(d) {
        return d.value
      });
  }
}

export default D3SimpleAreaChart;
