F2 icon indicating copy to clipboard operation
F2 copied to clipboard

多chart平移问题

Open boxcc opened this issue 4 years ago • 5 comments

复现代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0, user-scalable=no"
    />
    <meta name="chart-name" content="日 K" />
    <title>F2 图表组件库 - AntV</title>
    <link
      rel="stylesheet"
      href="https://gw.alipayobjects.com/os/rmsportal/YmDAMEQVbLJpVbKiRQVX.css"
    />
  </head>
  <body>
    <script>
      /*Fixing iframe window.innerHeight 0 issue in Safari*/ document.body
        .clientHeight;
    </script>

    <script src="https://unpkg.com/@antv/[email protected]/dist/f2-all.min.js"></script>

    <script src="https://gw.alipayobjects.com/os/antv/assets/lib/jquery-3.2.1.min.js"></script>
    <!-- 在 PC 上模拟 touch 事件 -->
    <script src="https://gw.alipayobjects.com/os/rmsportal/NjNldKHIVQRozfbAOJUW.js"></script>

    <style>
      .chart-wrapper {
        background-color: #101419;
      }

      .chart-container {
        position: relative;
      }

      .chart-title {
        width: 100%;
        height: 20px;
        line-height: 20px;
        padding-left: 10px;
        color: #676c79;
        font-size: 12px;
        font-weight: bold;
        border-bottom: 1px solid #191e26;
      }

      canvas#chart {
        height: 212px;
        border-bottom: 1px solid #191e26;
        margin-top: 16px;
      }

      canvas#volumn {
        height: 50px;
        border-bottom: 1px solid #191e26;
      }

      .tooltip-wrapper {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 20px;
        display: flex;
        flex-wrap: wrap;
        align-content: space-between;
        visibility: hidden;
        padding: 0 10px;
        border-bottom: 1px solid #191e26;
        background-color: #101419;
      }

      .tooltip-wrapper .tooltip-item {
        width: 15%;
        height: 16px;
        line-height: 16px;
        vertical-align: middle;
      }

      .tooltip-wrapper .tooltip-item.last {
        width: 40%;
      }

      .tooltip-wrapper .tooltip-item span {
        display: inline;
        color: #899198;
        font-size: 12px;
      }

      .tooltip-wrapper .tooltip-item span.item-value {
        font-weight: bold;
      }

      #barTooltip .tooltip-item {
        width: 100%;
      }

      .ma-wrapper {
        position: absolute;
        top: 20px;
        visibility: hidden;
        width: 100%;
        height: 16px;
        display: flex;
        flex-wrap: wrap;
        align-content: flex-start;
        padding: 0 10px 0 8px;
        border-bottom: 1px solid #191e26;
        background-color: #101419;
      }

      .ma-wrapper .tooltip-item {
        width: auto;
        height: 16px;
        line-height: 16px;
        vertical-align: middle;
        font-size: 10px;
        transform: scale(0.83);
      }

      .ma-wrapper .tooltip-item.first {
        width: 7%;
      }

      .ma-wrapper .tooltip-item.first span {
        background: #676c79;
        padding: 0 4px;
      }

      .ma-wrapper .tooltip-item span {
        display: inline;
        color: #899198;
      }
    </style>
    <div class="chart-wrapper">
      <div class="chart-container">
        <div class="chart-title">日 K</div>
        <div class="tooltip-wrapper" id="kTooltip">
          <div class="tooltip-item">
            <span>开</span>
            <span class="item-value" data-type="start"></span>
          </div>
          <div class="tooltip-item">
            <span>收</span>
            <span class="item-value" data-type="end"></span>
          </div>
          <div class="tooltip-item">
            <span>高</span>
            <span class="item-value" data-type="high"></span>
          </div>
          <div class="tooltip-item">
            <span>低</span>
            <span class="item-value" data-type="low"></span>
          </div>
          <div class="tooltip-item last">
            <span>成交</span>
            <span class="item-value" data-type="volumn"></span>
          </div>
        </div>
        <div class="ma-wrapper" id="ma">
          <div class="tooltip-item first">
            <span>MA</span>
          </div>
          <div class="tooltip-item">
            <span style="color: #c6268b">5:</span>
            <span class="item-value" data-type="MA5"></span>
          </div>
          <div class="tooltip-item">
            <span style="color: #d7a429">10:</span>
            <span class="item-value" data-type="MA10"></span>
          </div>
          <div class="tooltip-item">
            <span style="color: #227baf">20:</span>
            <span class="item-value" data-type="MA20"></span>
          </div>
          <div class="tooltip-item">
            <span style="color: #6960c4">30:</span>
            <span class="item-value" data-type="MA30"></span>
          </div>
        </div>
        <canvas id="chart"></canvas>
      </div>
      <div class="chart-container">
        <div class="chart-title">成交量</div>
        <div class="tooltip-wrapper" id="barTooltip">
          <div class="tooltip-item">
            <span>成交量:</span>
            <span class="item-value" data-type="volumn"></span>
          </div>
        </div>
        <canvas id="volumn"></canvas>
      </div>
    </div>
    <p style="text-align: center; font-size: 12px; color: #808080; margin: 0"
      >数据纯属虚构</p
    >
    <p style="text-align: center; font-size: 12px; color: #808080; margin: 0"
      >手机扫码,体验更佳</p
    >
    <script>
      var COLOR_MAP = ['#FF4433', '#32A532']; // 涨跌
      var barChart = void 0;
      var kChart = void 0;
      // let min = null;
      // let max = null;

      function updateMATip(data, index) {
        var currItem = data[index];
        $('#ma .item-value').each(function (index, ele) {
          var type = $(ele).data('type');
          var value = currItem[type];
          $(ele).text(value);
        });
        $('#ma').css('visibility', 'visible');
      }

      function getMinAndMax(data = [], currentValues = []) {
        if (!data.length || !currentValues.length) {
          return [null, null];
        }

        const firstIndex = data.findIndex(
          (i) =>
            i.reportDate === currentValues[0] ||
            F2.Util.toTimeStamp(i.reportDate) === currentValues[0]
        );
        const lastIndex = data.findIndex(
          (i) =>
            i.reportDate === currentValues[currentValues.length - 1] ||
            F2.Util.toTimeStamp(i.reportDate) ===
              currentValues[currentValues.length - 1]
        );

        const currentData = data.slice(firstIndex, lastIndex + 1);
        const result = currentData.reduce(
          (result, current) => {
            const minGroup = [
              current.low,
              current.MA5,
              current.MA10,
              current.MA20,
              current.MA30,
            ];
            const maxGroup = [
              current.high,
              current.MA5,
              current.MA10,
              current.MA20,
              current.MA30,
            ];

            if (!result[0] || !result[1]) {
              const theMin = Math.min(...minGroup);
              const theMax = Math.max(...maxGroup);
              return [theMin, theMax];
            }

            const theMin = Math.min(...minGroup, result[0]);
            const theMax = Math.max(...maxGroup, result[1]);
            return [theMin, theMax];
          },
          [null, null]
        );

        return result;
      }

      function toDate(value) {
        const d = new Date(value);
        const years = d.getFullYear();
        const months = `0${d.getMonth() + 1}`;
        const days = `0${d.getDate()}`;
        return `${years}-${months.substr(-2)}-${days.substr(-2)}`;
      }

      $.getJSON(
        'https://gw.alipayobjects.com/os/antvdemo/assets/data/f2/1d-k.json',
        function (data) {
          // 构造数据结构
          var reportDates = [];
          data.forEach(function (obj) {
            reportDates.push(obj.reportDate);
            obj.range = [obj.start, obj.end, obj.high, obj.low];
            obj.trend = obj.start <= obj.end ? 0 : 1; // 0 表示涨,1 表示跌
          });
          var firstShowDates = reportDates.slice(75); // 首屏展示的日期
          // 绘制 K 线图
          kChart = drawKChart(data, firstShowDates, reportDates);
          // 绘制成交量柱状图
          barChart = drawBarChart(data, firstShowDates);
        }
      );

      // 绘制成交量柱状图
      function drawBarChart(data, firstShowDates) {
        const chart = new F2.Chart({
          id: 'volumn',
          padding: [0, 0, 6],
          pixelRatio: window.devicePixelRatio,
        });
        chart.source(data, {
          reportDate: {
            type: 'timeCat',
            values: firstShowDates,
          },
        });
        chart.axis(false);
        chart.tooltip({
          alwaysShow: true,
          showCrosshairs: true,
          crosshairsStyle: {
            stroke: '#D1D3D4',
            lineWidth: 1,
          },
          showTooltipMarker: false,
          custom: true,
          onChange: function onChange(obj) {
            var currentPoint = {
              x: obj.x,
              y: obj.y,
            };
            kChart.showTooltip(currentPoint);
            var data = obj.items[0].origin;
            $('#barTooltip .item-value').each(function (index, ele) {
              var type = $(ele).data('type');
              var value = data[type];
              $(ele).css({
                color: '#FFFFFF',
              });
              $(ele).text(value);
            });
            $('#barTooltip').css('visibility', 'visible');
          },
          onHide: function onHide() {
            $('#barTooltip').css('visibility', 'hidden');
          },
        });
        chart
          .interval()
          .position('reportDate*volumn')
          .color('trend', function (val) {
            return COLOR_MAP[val];
          });
        // chart.interaction('pinch', {
        //   maxScale: 25,
        //   onProcess: function onProcess() {
        //     if (this.pressed) return;
        //     var currentValues = chart.getXScale().values; // 获取平移后的当前展示 values
        //     kChart.scale('reportDate', {
        //       type: 'timeCat',
        //       values: currentValues,
        //       ticks: [
        //         '2018-06-08',
        //         '2018-07-02',
        //         '2018-08-01',
        //         '2018-09-03',
        //         '2018-10-08',
        //         '2018-11-01',
        //       ],
        //     });
        //     kChart.repaint();
        //   },
        //   onEnd: function onEnd() {
        //     kChart.hideTooltip();
        //     chart.hideTooltip();
        //   },
        // });
        chart.interaction('pan', {
          onProcess: function onProcess() {
            if (this.pressed) return;
            var currentValues = chart.getXScale().values; // 获取平移后的当前展示 values

            const [min, max] = getMinAndMax(data, currentValues);
            // const newValues = currentValues.map((i) => toDate(i));
            kChart.scale('reportDate', {
              type: 'timeCat',
              values: currentValues,
              // ticks: [
              //   '2018-06-08',
              //   '2018-07-02',
              //   '2018-08-01',
              //   '2018-09-03',
              //   '2018-10-08',
              //   '2018-11-01',
              // ],
            });
            kChart.scale('range', {
              max,
              min,
            });
            kChart.scale('MA5', {
              max,
              min,
            });
            kChart.scale('MA10', {
              max,
              min,
            });
            kChart.scale('MA20', {
              max,
              min,
            });
            kChart.scale('MA30', {
              max,
              min,
            });
            kChart.repaint();
          },
          onEnd: function onEnd() {
            kChart.hideTooltip();
            chart.hideTooltip();
            kChart.repaint();
          },
        });
        // // 添加进度条
        // chart.scrollBar({
        //   mode: 'x',
        //   xStyle: {
        //     backgroundColor: 'rgba(202, 215, 239, .2)',
        //     fillerColor: '#818991',
        //     size: 4,
        //     lineCap: 'square',
        //     offsetX: 0,
        //     offsetY: 1,
        //   },
        // });
        chart.render();
        return chart;
      }

      function drawKChart(data, firstShowDates, allDates) {
        const [firstMin, firstMax] = getMinAndMax(data, firstShowDates);
        const chart = new F2.Chart({
          id: 'chart',
          padding: [0, 0, 18],
          pixelRatio: window.devicePixelRatio,
          syncY: true,
        });
        chart.source(data, {
          reportDate: {
            type: 'timeCat',
            ticks: [
              '2018-06-08',
              '2018-07-02',
              '2018-08-01',
              '2018-09-03',
              '2018-10-08',
              '2018-11-01',
            ],
            values: firstShowDates,
            sortable: false,
          },
          range: {
            nice: false,
            max: firstMax,
            min: firstMin,
          },
          MA5: {
            nice: false,
            max: firstMax,
            min: firstMin,
          },
          MA10: {
            nice: false,
            max: firstMax,
            min: firstMin,
          },
          MA20: {
            nice: false,
            max: firstMax,
            min: firstMin,
          },
          MA30: {
            nice: false,
            max: firstMax,
            min: firstMin,
          },
        });
        chart.axis('reportDate', {
          labelOffset: 1,
          label: function label(text, index, total) {
            var textAlign = 'center';
            if (index === 0) {
              textAlign = 'start';
            } else if (index === total - 1) {
              textAlign = 'end';
            }
            return {
              text: text.slice(0, 7),
              fill: '#818991',
              textAlign: textAlign,
            };
          },

          line: {
            stroke: '#181D26',
          },
          grid: {
            lineWidth: 1,
            stroke: '#181D26',
          },
        });
        chart.axis('range', {
          line: {
            stroke: '#181D26',
          },
          grid: {
            stroke: '#181D26',
          },
          labelOffset: -2,
          label: function label(text, index, total) {
            var cfg = {
              textAlign: 'start',
              text: parseFloat(text).toFixed(2),
              fill: '#818991',
            };
            if (index === 0) {
              cfg.textBaseline = 'bottom';
            } else if (index === total - 1) {
              cfg.textBaseline = 'top';
            }
            return cfg;
          },
        });
        chart.axis('MA5', false);
        chart.axis('MA10', false);
        chart.axis('MA20', false);
        chart.axis('MA30', false);
        chart.tooltip({
          showTooltipMarker: false,
          alwaysShow: true,
          showCrosshairs: true,
          crosshairsType: 'xy',
          showXTip: true,
          showYTip: true,
          crosshairsStyle: {
            stroke: '#D1D3D4',
            lineWidth: 1,
          },
          xTip: {
            fill: '#80888F',
            fontSize: 10,
          },
          yTip: function yTip(val) {
            return {
              fill: '#80888F',
              fontSize: 10,
              text: val.toFixed(3),
            };
          },

          xTipBackground: {
            fill: '#232C39',
            fillOpacity: 0.75,
            radius: 2,
          },
          yTipBackground: {
            fill: '#232C39',
            fillOpacity: 0.75,
            radius: 2,
          },
          custom: true,
          onChange: function onChange(obj) {
            var currentPoint = {
              x: obj.x,
              y: obj.y,
            };
            barChart.showTooltip(currentPoint);
            var currData = obj.items[0].origin;
            $('#kTooltip .item-value').each(function (index, ele) {
              var type = $(ele).data('type');
              var value = currData[type];
              var color = void 0;
              if (type === 'volumn') {
                color = '#FFF';
              } else {
                color = currData.trend === 0 ? COLOR_MAP[0] : COLOR_MAP[1];
              }
              $(ele).css({
                color: color,
              });
              $(ele).text(value);
            });
            $('#kTooltip').css('visibility', 'visible');

            updateMATip(data, allDates.indexOf(currData.reportDate));
          },
          onHide: function onHide() {
            $('#kTooltip').css('visibility', 'hidden');
            $('#ma').css('visibility', 'hidden');
          },
        });
        chart
          .schema()
          .position('reportDate*range')
          .color('trend', function (val) {
            return COLOR_MAP[val];
          })
          .shape('candle');
        chart
          .line()
          .position('reportDate*MA5')
          .color('#C6268B')
          .size(1)
          .animate(false);
        chart
          .line()
          .position('reportDate*MA10')
          .color('#D7A429')
          .size(1)
          .animate(false);
        chart
          .line()
          .position('reportDate*MA20')
          .color('#227BAF')
          .size(1)
          .animate(false);
        chart
          .line()
          .position('reportDate*MA30')
          .color('#6960C4')
          .size(1)
          .animate(false);

        // chart.interaction('pinch', {
        //   maxScale: 25,
        //   onProcess: function onProcess() {
        //     if (this.pressed) return;

        //     var currentValues = chart.getXScale().values; // 获取平移后的当前展示 values
        //     barChart.scale('reportDate', {
        //       type: 'timeCat',
        //       values: currentValues,
        //     });
        //     barChart.repaint();
        //   },
        //   onEnd: function onEnd() {
        //     barChart.hideTooltip();
        //     chart.hideTooltip();
        //   },
        // });
        chart.interaction('pan', {
          onStart: function onStart() {},
          onProcess: function onProcess() {
            if (this.pressed) return; // TODO, 这个标识位好恶心

            const currentValues = chart.getXScale().values; // 获取平移后的当前展示 values
            // const newValues = currentValues.map((i) => toDate(i));
            barChart.scale('reportDate', {
              type: 'timeCat',
              values: currentValues,
            });
            barChart.repaint();

            const [min, max] = getMinAndMax(data, currentValues);

            const yScales = chart.getYScales();
            yScales.forEach((item) => {
              this.updateLinearScale(item.field, min, max);
            });
          },
          onEnd: function onEnd() {
            barChart.hideTooltip();
            chart.hideTooltip();
            barChart.repaint();
          },
        });
        chart.render();
        return chart;
      }
    </script>
  </body>
</html>

复现步骤: 滑动"蜡烛图", 再滑动"条形图", 这时候"蜡烛图"显示就不完整了. 反之也是一样, 只有一直滑同一个chart才正常

boxcc avatar Nov 05 '20 15:11 boxcc

我用官方的demo,平移都用不了。。警告提示[Violation] Added non-passive event listener to a scroll-blocking 'touchstart' event. Consider marking event handler as 'passive' to make the page more responsive

TrevorYS avatar Nov 06 '20 08:11 TrevorYS

我用官方的demo,平移都用不了。。警告提示[Violation] Added non-passive event listener to a scroll-blocking 'touchstart' event. Consider marking event handler as 'passive' to make the page more responsive

版本是3.7.8

TrevorYS avatar Nov 06 '20 08:11 TrevorYS

我用官方的demo,平移都用不了。。警告提示[Violation] Added non-passive event listener to a scroll-blocking 'touchstart' event. Consider marking event handler as 'passive' to make the page more responsive

用我贴出的代码 可以吗?

boxcc avatar Nov 09 '20 02:11 boxcc

同样的bug

zhenyu-dev avatar Jan 07 '21 09:01 zhenyu-dev

bug+1,这个有解决方案了吗 版本:5.0.27

zejunking avatar Aug 23 '23 06:08 zejunking