资讯专栏INFORMATION COLUMN

highcharts: 如何解决「移动端将图表旋转90度,tooltip表现不正常」?

Yumenokanata / 3077人阅读

摘要:背景在项目中使用是很容易的,移动端也适配的不错,按照官网教程即可。修改完成后,发现的表现符合预期了。经过测试图表的其他基本功能正常。由于的功能太多,这样的源码修改功能对其他的功能有无影响,还不能完全确定。

背景

在项目中使用highcharts是很容易的,移动端也适配的不错,按照官网教程即可。但是在移动端,由于手机端屏幕太小,需求方希望可以弄一个全屏图,把手机横过来观察曲线。

正常:

竖过来:

很容易想到的一种实现方法:设置曲线container的宽为屏幕的高,高为屏幕的宽,然后给曲线的container加一个transform:rotate(90deg),就能够实现竖屏了。

这样看起来没问题,但是当需要展现tooltip的时候,会发现tooltip不好使了。表现出来的现象是:当用户用手指延着曲线的x轴移动时,tooltip并不会跟着手指移动。
仔细观察会发现,tooltip的移动,还是根据手指在屏幕上移动时的【横坐标】来的。

开始尝试解决问题

经过查阅highcharts文档,发现chart.inverted可以实现x轴和y轴的反转。试了一下这个配置,发现并不是想象中那么理想,主要原因为:
1、y轴在屏幕下方,但我们需要的是y轴在屏幕上方。而y轴的位置不那么好调整。
2、tooltip也需要我们多带带进行旋转。但是旋转后,手指touchmove时,tooltip适配会出问题,有时候会跑到曲线外面去,无法控制。并且由于是svg画图,tooltip本身的transform-origin的选择就是一个比较蛋疼的问题。

查阅了highcharts其他的api,并且上git搜了搜issue,但是并没有这个问题的解决方法。本来想放弃highcharts, 转投echarts的, 但在echarts的issue里发现很多人遇到了这个问题,但官方直接给列为了bug, 还不知道什么时候可以修复。最后还是考虑使用highcharts。

没办法,改源码吧

由于大概知道问题产生的原因:图表竖过来后,应该用触摸事件的纵坐标而不是横坐标来作为表格内的横坐标。改源码应该挺快的。

项目是用通过npm安装的highcharts, 首先根据highcharts的package.json可以看到,引用的入口文件为:highcharts.js
这个文件是压缩过的,它对应的源代码文件为:highcharts.src.js

结合源代码文件和浏览器调试,发现在用户滑动手指是,进入了下面的逻辑:

            onContainerTouchStart: function(e) {
                this.zoomOption(e);
                this.touch(e, true);
            },

            onContainerTouchMove: function(e) {
                this.touch(e);
            },

一切都在这个touch函数里。继续往下看:

/**
             * General touch handler shared by touchstart and touchmove.
             */
            touch: function(e, start) {
                var chart = this.chart,
                    hasMoved,
                    pinchDown,
                    isInside;

                if (chart.index !== H.hoverChartIndex) {
                    this.onContainerMouseLeave({
                        relatedTarget: true
                    });
                }
                H.hoverChartIndex = chart.index;
                
                // 这里判断是是否是单触
                if (e.touches.length === 1) {
                    
                    //  e为js的触摸事件
                    e = this.normalize(e);

                    //  e.chartX ,e.chartY应该就是触摸时,在表格内部的横坐标和纵坐标,这里的normalize应该是对事件进行了扩展。
                    isInside = chart.isInsidePlot(
                        e.chartX - chart.plotLeft,
                        e.chartY - chart.plotTop
                    );
                    if (isInside && !chart.openMenu) {

                        // Run mouse events and display tooltip etc
                        if (start) {
                            this.runPointActions(e);
                        }

                        // Android fires touchmove events after the touchstart even if the
                        // finger hasn"t moved, or moved only a pixel or two. In iOS however,
                        // the touchmove doesn"t fire unless the finger moves more than ~4px.
                        // So we emulate this behaviour in Android by checking how much it
                        // moved, and cancelling on small distances. #3450.
                        if (e.type === "touchmove") {
                            pinchDown = this.pinchDown;
                            hasMoved = pinchDown[0] ? Math.sqrt( // #5266
                                Math.pow(pinchDown[0].chartX - e.chartX, 2) +
                                Math.pow(pinchDown[0].chartY - e.chartY, 2)
                            ) >= 4 : false;
                        }

                        if (pick(hasMoved, true)) {
                            this.pinch(e);
                        }

                    } else if (start) {
                        // Hide the tooltip on touching outside the plot area (#1203)
                        this.reset();
                    }

                } else if (e.touches.length === 2) {
                    this.pinch(e);
                }
            },

这里的normalize比较关键,因为产生tooltip表现不符合预期的原因应该就是:旋转时,由于图被竖过来了,需要使用触摸事件的纵坐标来表示触摸的【横坐标】,但highcharts依然采用了事件的横坐标。继续看看normalize的内容。

/**
             * Takes a browser event object and extends it with custom Highcharts
             * properties `chartX` and `chartY` in order to work on the internal 
             * coordinate system.
             * 
             * @param  {Object} e
             *         The event object in standard browsers.
             *
             * @return {PointerEvent}
             *         A browser event with extended properties `chartX` and `chartY`.
             */
            normalize: function(e, chartPosition) {
                var chartX,
                    chartY,
                    ePos;

                // IE normalizing
                e = e || win.event;
                if (!e.target) {
                    e.target = e.srcElement;
                }

                // iOS (#2757)
                ePos = e.touches ? (e.touches.length ? e.touches.item(0) : e.changedTouches[0]) : e;

                // Get mouse position
                if (!chartPosition) {
                    this.chartPosition = chartPosition = offset(this.chart.container);
                }

                // chartX and chartY
                // 这里是计算chartX和chartY,计算方法是用当前触摸(点击)事件的横坐标减去图表的横坐标,纵坐标减去图表的纵坐标。
                
                if (ePos.pageX === undefined) { // IE < 9. #886.
                    chartX = Math.max(e.x, e.clientX - chartPosition.left); // #2005, #2129: the second case is 
                    // for IE10 quirks mode within framesets
                    chartY = e.y;
                } else {
                    chartX = ePos.pageX - chartPosition.left;
                    chartY = ePos.pageY - chartPosition.top;
                }
                
                // 这里的chartX和chartY已经是在表格内部的坐标了,后续的逻辑都是根据这个chartX和chartY来的,如果当图表被竖过来时,人为把这两个值交换一下,是否就解决了tooltip的问题呢。
                if(竖屏) {
                    // 【竖屏】可以通过在配置表格的时候增加变量来判断
                    return extend(e, {
                        chartX: Math.round(chartY),
                        chartY: Math.round(chartX)
                    });
                }
                
                return extend(e, {
                    chartX: Math.round(chartX),
                    chartY: Math.round(chartY)
                });
            },

按照这个思路,找到入口文件highcharts.js里对应部分的代码,进行修改。修改完成后,发现tooltip的表现符合预期了。

经过测试, 图表的其他基本功能正常。之前还担心这样会不会影响lengends的点击等。后来想了一下,由于是svg画图,所有点击事件应该都是直接绑定在元素上的,而不是像canvas一样强依赖坐标,所以不会影响。这也是为什么在echarts下进行rotate, lengends的交互也会受影响的原因。

由于highcharts的功能太多,这样的源码修改功能对其他的功能有无影响,还不能完全确定。待后续继续补充。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/95372.html

相关文章

  • echarts 与 highcharts

    摘要:渲染能力采用渲染除了对使用,一般来说,更适合绘制图形元素数量非常大这一般是由数据量大导致的图表如热力图地理坐标系或平行坐标系上的大规模线图或散点图等,也利于实现某些视觉特效如交通图。 一.简介 echartsecharts是百度公司前端开发的一个图表库,2013年发布第一版,主要采用canvas画图,目前版本3.8.4;完全免费; highcharthighcharts是国外的一家公司...

    王笑朝 评论0 收藏0
  • 蚂蚁金服新一代数据可视化引擎 G2

    摘要:新公司已经呆了一个多月,目前着手一个数据可视化的项目,数据可视化肯定要用到图形库如等,经决定我的这个项目用阿里旗下蚂蚁金服所开发的图表库。数据提示框内提示的信息还可以通过格式化函数动态指定。 新公司已经呆了一个多月,目前着手一个数据可视化的项目,数据可视化肯定要用到图形库如D3、Highcharts、ECharts、Chart等,经决定我的这个项目用阿里旗下蚂蚁金服所开发的G2图表库。...

    animabear 评论0 收藏0
  • Vue—Cli中使用动态Highcharts line图表超初级教学

    摘要:开始让动起来我会直接贴部分代码加少量解释,建议先看下官方给的动态实时刷新示意图循环次,线从图表右侧开始出现,轴会分为秒。 效果展示 社会你龙哥,人丑话不多,先来张图!图片传不上去!!!可能公司限制了,大家自己幻想下吧 highcharts环境搭配 由于技术现水平限制,需要用到两个Highcharts,下面我会解释,先上代码 npm install --save highcharts ...

    stackvoid 评论0 收藏0
  • 玩转CSS 3D -正八面体与正十二面体

    摘要:正八面体与正十二面体,这两个正多面体虽然组合的面比较多,不过因为具备了对称性,所以只需要制作出一半的结构,另外一半再用反转的方式接在一起即可。同样的,旋转让整个正八面体旋转,看起来更有立体感。 正八面体与正十二面体,这两个正多面体虽然组合的面比较多,不过因为具备了对称性,所以只需要制作出一半的结构,另外一半再用反转的方式接在一起即可。 正八面体 正八面体可以想像成两个金字塔叠合在一起,...

    Neilyo 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<