antvis / my-f2

F2 的支付宝小程序版本
MIT License
146 stars 23 forks source link

一个页面有多个图表,有的图表有可能只画了一半的大小 #15

Open licjing opened 5 years ago

licjing commented 5 years ago

一个页面有多个图表,有的图表有可能只画了一半的大小 dd.createSelectorQuery().select('#xxx').boundingClientRect().exec((res) => { const pixelRatio = my.getSystemInfoSync().pixelRatio; const canvasWidth = res[0].width; const canvasHeight = res[0].height; // 高清解决方案 this.setData({ userChartWidth: canvasWidth pixelRatio, userChartHeight: canvasHeight pixelRatio }); const myCtx = my.createCanvasContext('xxx'); myCtx.scale(pixelRatio, pixelRatio); // �必要!按照设置的分辨率进行放大 let canvas = new F2.Renderer(myCtx); this.chart = canvas; this.drawChart(canvas, canvasWidth,canvasHeight); });

licjing commented 5 years ago

一个页面有多个图表,有的图表有时候只画了一半的大小

b2nil commented 5 years ago

遇到了同样的问题,使用分辨率 pixelRatio 放大后,使用样式的宽、高缩小不回来。

b2nil commented 5 years ago

@simaQ

可以否帮忙看一下:

根据 canvas 文档所述,将画布的宽、高属性按照设备的分辨率放大后,再通过样式的宽、高缩小,可以在高 dpr 下取得更细腻的显示。但是这样做了以后,支付宝开发工具中图表被放大很多(详见下面的截图,右侧微信小程序是可以正常显示的)。

因为是采用 Megalo 写的,不能确定是哪里出了问题。如果将 ctx.scale(pixelRatio, pixelRatio) 去掉,支付宝开发工具可以正常显示。

截图

f2

代码

// 如果需要在高 dpr 下取得更细腻的显示,需要先将 canvas 用属性设置放大,用样式缩小,例如
// <!-- getSystemInfoSync().pixelRatio === 2 -->
// <canvas width="200" height="200" style="width:100px;height:100px;"/>
const pixelRatio = my.getSystemInfoSync().pixelRatio;
_this.width = rect[0].width * pixelRatio;  // 按设备分辨率放大 canvas 的宽、高属性
_this.height = rect[0].height * pixelRatio;

const ctx = my.createCanvasContext(_this.canvasId);
ctx.scale(pixelRatio, pixelRatio); // alipay: 按设备分辨率放大 canvas 属性后,通过样式缩小不回来

const canvas = new F2.Renderer(ctx);
_this.canvas = canvas;

if (typeof callback === 'function') {
       _this.chart = callback(
            canvas,
            rect[0].width,
            rect[0].height,
            F2
       );
} else if (_this.opts && typeof _this.opts.onInit === 'function') {
         _this.chart = this.opts.onInit(
         canvas,
         rect[0].width,
         rect[0].height,
         F2
     );
}
simaQ commented 5 years ago

@b2nil 如果是使用 native canvas 版本的话,按照之前这块的负责人给我的信息,是直接在 native canvas 层解决了不同分辨率的显示问题,这样的话,在使用 my-f2 绘制图表时,就不需要再做 canvas.scale 了,你可以看下使用 canvas native 渲染的图表的例子: https://github.com/antvis/mini-program-f2-demos/tree/for-native-test/pages/charts/area,如果使用的 native canvas,高清以及事件都不用在代码中处理了

simaQ commented 5 years ago

@licjing 能提供使用的 my-f2 版本吗?另外这种现象是在 IDE 中还是真机上,最好能提供完整的可复现的代码,包括 axml,js 等文件

licjing commented 5 years ago

@licjing 能提供使用的 my-f2 版本吗?另外这种现象是在 IDE 中还是真机上,最好能提供完整的可复现的代码,包括 axml,js 等文件

"dd-charts": "^1.0.5"

axss: .pages{ padding: 12px; font-size: 13px; } canvas{ width: 100%; height: 100%; } .Demos1{ width: 100%; height: 200px; } .Demos2{ width: 100%; height: 200px;

} .Demos3{ width: 100%; height: 100px; } axml:

Demos1 Demos2 Demos3

js: import F2 from '@antv/my-f2'; const value1 = [ { date: "2017-06-05", value: 116 }, { date: "2017-06-06", value: 129 }, { date: "2017-06-07", value: 135 }, { date: "2017-06-08", value: 86 }, { date: "2017-06-09", value: 73 }, { date: "2017-06-10", value: 85 }, { date: "2017-06-11", value: 73 }, { date: "2017-06-12", value: 68 }, { date: "2017-06-13", value: 92 }, { date: "2017-06-14", value: 130 }, { date: "2017-06-15", value: 245 }, { date: "2017-06-16", value: 139 }, { date: "2017-06-17", value: 115 }, { date: "2017-06-18", value: 111 }, { date: "2017-06-19", value: 309 }, { date: "2017-06-20", value: 206 }, { date: "2017-06-21", value: 137 }, { date: "2017-06-22", value: 128 }, { date: "2017-06-23", value: 85 }, { date: "2017-06-24", value: 94 }, { date: "2017-06-25", value: 71 }, { date: "2017-06-26", value: 106 }, { date: "2017-06-27", value: 84 }, { date: "2017-06-28", value: 93 }, { date: "2017-06-29", value: 85 }, { date: "2017-06-30", value: 73 }, { date: "2017-07-01", value: 83 }, { date: "2017-07-02", value: 125 }, { date: "2017-07-03", value: 107 }, { date: "2017-07-04", value: 82 }, ]; const value2 = [{ age: '18岁以下', value: 0.20 }, { age: '18-24岁', value: 0.10 }, { age: '25-29岁', value: 0.26 }, { age: '30-34岁', value: 0.14 }, { age: '35-39岁', value: 0.13 }, { age: '40-49岁', value:0.15 }, { age: '50岁', value:0.02 }] const value3 =[{ "candy":"", "type":"钉钉", "value":446, "percent":0.24030172413793102 },{ "candy":"", "type":"非常道", "value":672, "percent":0.3620689655172414 },{ "candy":"", "type":"脉脉", "value":273, "percent":0.1470905172413793 },{ "candy":"", "type":"今目标", "value":204, "percent":0.10991379310344827 },{ "candy":"", "type":"其他", "value":261, "percent":0.140625 }];

Page({ onLoad(query) { // 页面加载 console.info(Page onLoad with query: ${JSON.stringify(query)}); }, onReady() { // 页面加载完成 this.Demos1(); this.Demos2(); this.Demos3(); }, onShow() { // 页面显示 }, onHide() { // 页面隐藏 }, onUnload() { // 页面被关闭 }, onTitleClick() { // 标题被点击 }, onPullDownRefresh() { // 页面被下拉 }, onReachBottom() { // 页面被拉到底部 }, onShareAppMessage() { // 返回自定义分享信息 return { title: 'My App', desc: 'My App description', path: 'pages/index/index', }; }, Demos1(){ dd.createSelectorQuery().select('#Demos1').boundingClientRect().exec((res) => { const pixelRatio = my.getSystemInfoSync().pixelRatio; const canvasWidth = res[0].width; const canvasHeight = res[0].height; // 高清解决方案 this.setData({ width: canvasWidth pixelRatio, height: canvasHeight pixelRatio }); const myCtx = my.createCanvasContext('Demos1'); myCtx.scale(pixelRatio, pixelRatio); // �必要!按照设置的分辨率进行放大 let canvas = new F2.Renderer(myCtx); this.Demos1Fn(canvas, canvasWidth,canvasHeight); }); }, Demos1Fn(canvas, width, height){ var that = this; var Global = F2.Global; var chart= new F2.Chart({ el: canvas, width, height }); chart.source(value1, { value: { tickCount: 5, min: 0 }, date: { type: 'timeCat', tickCount: 4 } }) chart.legend({ position:'top', custom: true, clickable: true, items: [ { name: that.data.currentName, value:0, marker: 'square', fill: 'blue' }], checked: true, })
chart.tooltip({ alwaysShow:true, custom: false, background:{ radius: 2, fill: '#ccc', padding: [ 6, 10 ] }, onChange(ev){
const legend = chart.get('legendController').legends.top[0]; const tooltipItems = ev.items; const legendItems = legend.items; const map = {};
legendItems.map(item => { map[item.name] = {...item}; }); tooltipItems.map(item => { map[that.data.currentName].value = item.value; }); legend.setItems(Object.values(map)); }, onClick(ev){

  },
  onHide(tooltip) {
    const legend = chart.get('legendController').legends.top[0];
  }
})
chart.axis('date', {
    label(text, index, total) {
    const textCfg = {};
    if (index === 0) {
        textCfg.textAlign = 'left';
    }
    if (index === total - 1) {
        textCfg.textAlign = 'right';
    }
    return textCfg;
    }
});
chart.line().position('date*value').shape('smooth');
chart.render()

}, Demos2(){ dd.createSelectorQuery().select('#Demos2').boundingClientRect().exec((res) => { // 获取分辨率 const pixelRatio = my.getSystemInfoSync().pixelRatio; // 获取画布实际宽高 const canvasWidth = res[0].width; const canvasHeight = res[0].height; // 高清解决方案 this.setData({ Demos2width: canvasWidth pixelRatio, Demos2height: canvasHeight pixelRatio }); const myCtx = my.createCanvasContext('Demos2'); myCtx.scale(pixelRatio, pixelRatio); // �必要!按照设置的分辨率进行放大 const canvas = new F2.Renderer(myCtx); this.Demos2Fn(canvas, res[0].width, res[0].height); }); }, Demos2Fn(canvas, width, height) { let that = this; const Global = F2.Global; const chart = new F2.Chart({ el: canvas, width, height }); chart.source(value2, { value: { tickCount: 5 } }); chart.coord({ transposed: false }); chart.axis('age', { line: Global._defaultAxis.line, grid: null }); chart.axis('value', { line: null, grid: Global._defaultAxis.grid, label: null }); value2.map(function(obj) { chart.guide().text({ position: [obj.age, obj.value], content: (obj.value 100).toFixed(0) + '%', style: { textBaseline: 'bottom', textAlign: 'center' }, offsetY: -2 }); }); chart.tooltip({ custom: true, }) chart.interval().position('agevalue'); chart.render(); }, Demos3(){ dd.createSelectorQuery().select('#Demos3').boundingClientRect().exec((res) => { // 获取分辨率 const pixelRatio = my.getSystemInfoSync().pixelRatio; // 获取画布实际宽高 const canvasWidth = res[0].width; const canvasHeight = res[0].height; // 高清解决方案 this.setData({ Demos3width: canvasWidth pixelRatio, Demos3height: canvasHeight pixelRatio }); const myCtx = my.createCanvasContext('Demos3'); myCtx.scale(pixelRatio, pixelRatio); // �必要!按照设置的分辨率进行放大 const canvas = new F2.Renderer(myCtx); this.Demos3Fn(canvas, canvasWidth, canvasHeight); }); }, Demos3Fn(canvas, width, height){ let colors = { '钉钉': '#399afa', '非常道': '#59aafa', '脉脉': '#94c8fc', '今目标': '#d6eafe', '其他': '#ededee'
}; const Shape = F2.Shape; const Util = F2.Util; const G = F2.G; function formatter(val) { return (val 100).toFixed(0) + '%'; } const ddChart = new F2.Chart({ el: canvas, width, height }); Shape.registerShape('interval', 'text', { draw: function draw(cfg, container) { var points = this.parsePoints(cfg.points); var style = { fill: cfg.color, z: true // 需要闭合 }; var shapes = []; var intervalWidth = points[1].x - points[0].x; var interval = container.addShape('rect', { attrs: Util.mix({ x: points[0].x, y: points[0].y, width: intervalWidth, height: -20 }, style) }); // 绘制柱形 shapes.push(interval); var origin = cfg.origin._origin; // 获取对应的原始数据 var textOffsetX = 4; var text = new G.Shape.Text({ attrs: { x: points[0].x + textOffsetX, y: (points[0].y + points[3].y) / 2, text: formatter(origin.percent), textAlign: 'start', textBaseline: 'middle', fontSize: 10 } }); var textWidth = text.getBBox().width; if (textWidth + textOffsetX < intervalWidth) { container.add(text); shapes.push(text); } return shapes; } }); ddChart.clear() ddChart.source(value3, { value: { tickCount: 5, min: 0, max: 1, nice: false, formatter: formatter } }) ddChart.coord({ transposed: true }) ddChart.legend({ marker: 'square', clickable: false, position:'bottom', itemWidth:'30%', offsetY: -10, offsetX: 10, }); ddChart.tooltip(false); ddChart.axis('percent', false) ddChart.interval().position('candypercent').color('type', function(val) { return colors[val]; }).adjust('stack').shape('text'); ddChart.render() } });

b2nil commented 5 years ago

@simaQ 谢谢。

TianBM commented 5 years ago

所以这个问题解决了吗。。。

licjing commented 5 years ago

@TianBM 没有呢

TianBM commented 5 years ago

@licjing 好吧,我是钉钉E应用遇到了类似问题,找了下原因是在my-F2的Scale方法出的问题

licjing commented 5 years ago

@TianBM 我也是钉钉E应用遇到的,您有什么解决方案吗?

TianBM commented 5 years ago

@licjing 暂时没有

licjing commented 5 years ago

@TianBM 如果后续有解决方法,共享一下,谢谢~

TianBM commented 5 years ago

import F2 from '@antv/my-f2';

Component({ mixins: [{}], data: { width: 0, height: 0 }, props: { canvasId: 'f2-canvas', onDraw: function onDraw() {} }, didUpdate: function didUpdate(prevProps, prevData) { console.log(prevProps, this.props, prevData, this.data); }, didMount: function didMount() { this.init(); }, didUnmount: function didUnmount() {},

methods: {
    init: function init(cb) {
        var me = this;
        var canvasId = me.props.canvasId;
        dd.createSelectorQuery().select('#' + canvasId).boundingClientRect().exec(function (res) {
            // 获取分辨率
            var pixelRatio = dd.getSystemInfoSync().pixelRatio;
            // 获取画布实际宽高
            var canvasWidth = res[0].width;
            var canvasHeight = res[0].height;
            me.setData({
                width: canvasWidth * pixelRatio,
                height: canvasHeight * pixelRatio
            });
            var myCtx = dd.createCanvasContext(canvasId);

            //可能导致比例失调
            myCtx.scale(pixelRatio, pixelRatio);

            var canvas = new F2.Renderer(myCtx);
            me.canvas = canvas;
            me.chart = new F2.Chart({
                el: canvas,
                width:canvasWidth,
                height:canvasHeight
            });
            if (typeof cb === 'function') {
                me.props.onDraw(me.chart, F2);
            } else if (me.props && me.props.onDraw) {
                me.props.onDraw(me.chart, F2);
            }
        });
    },
    touchStart: function touchStart(e) {
        if (this.canvas) {
            this.canvas.emitEvent('touchstart', [e]);
        }
    },
    touchMove: function touchMove(e) {
        if (this.canvas) {
            this.canvas.emitEvent('touchmove', [e]);
        }
    },
    touchEnd: function touchEnd(e) {
        if (this.canvas) {
            this.canvas.emitEvent('touchend', [e]);
        }
    }
}

});

@licjing 我定位的是钉钉封装的dd-charts组件中的myCtx.scale(pixelRatio, pixelRatio);语句可能导致比例失调的问题

licjing commented 5 years ago

@TianBM en

simaQ commented 5 years ago

参考下这个: https://www.yuque.com/antv/f2/miniprogram#comment-147139

在 setData 的回调里绘制图表:

this.setData({
  width: canvasWidth * pixelRatio,
  height: canvasHeight * pixelRatio
}, () => {
  const myCtx = my.createCanvasContext('radar');  // "radar" 替换为你自己定义的 canvas 的 id
  myCtx.scale(pixelRatio, pixelRatio); // 必要!按照设置的分辨率进行放大
  const canvas = new F2.Renderer(myCtx);
  this.canvas = canvas;
  drawChart(canvas, res[0].width, res[0].height);
});
TianBM commented 5 years ago

有用,看来确实是setData异步的问题

thefireoftheblue commented 4 years ago

@simaQ 请问是怎么解决多个图表多个是一大一小的问题的吗

huixu123 commented 4 years ago

@thefireoftheblue 解决了吗

Yrobot commented 4 years ago

@simaQ

可以否帮忙看一下:

根据 canvas 文档所述,将画布的宽、高属性按照设备的分辨率放大后,再通过样式的宽、高缩小,可以在高 dpr 下取得更细腻的显示。但是这样做了以后,支付宝开发工具中图表被放大很多(详见下面的截图,右侧微信小程序是可以正常显示的)。

因为是采用 Megalo 写的,不能确定是哪里出了问题。如果将 ctx.scale(pixelRatio, pixelRatio) 去掉,支付宝开发工具可以正常显示。

截图

f2

代码

// 如果需要在高 dpr 下取得更细腻的显示,需要先将 canvas 用属性设置放大,用样式缩小,例如
// <!-- getSystemInfoSync().pixelRatio === 2 -->
// <canvas width="200" height="200" style="width:100px;height:100px;"/>
const pixelRatio = my.getSystemInfoSync().pixelRatio;
_this.width = rect[0].width * pixelRatio;  // 按设备分辨率放大 canvas 的宽、高属性
_this.height = rect[0].height * pixelRatio;

const ctx = my.createCanvasContext(_this.canvasId);
ctx.scale(pixelRatio, pixelRatio); // alipay: 按设备分辨率放大 canvas 属性后,通过样式缩小不回来

const canvas = new F2.Renderer(ctx);
_this.canvas = canvas;

if (typeof callback === 'function') {
       _this.chart = callback(
            canvas,
            rect[0].width,
            rect[0].height,
            F2
       );
} else if (_this.opts && typeof _this.opts.onInit === 'function') {
         _this.chart = this.opts.onInit(
         canvas,
         rect[0].width,
         rect[0].height,
         F2
     );
}

你好,问题解决了吗,我微信小程序遇到了同样的问题,使用F2的pixelRatio导致画布大小变大了,使用myCtx.scale图表没有变清晰。

huixu123 commented 4 years ago

暂时没有解决  暂时是把高清操作去掉了。后面再想办法。应该是哪里异步了,需要去改my-f2那个node_module。后面你如果有办法了 也请告知一声啊

------------------ 原始邮件 ------------------ 发件人: "Yrobot"<notifications@github.com>; 发送时间: 2020年5月7日(星期四) 中午1:22 收件人: "antvis/my-f2"<my-f2@noreply.github.com>; 抄送: "洪晖旭"<709619407@qq.com>;"Comment"<comment@noreply.github.com>; 主题: Re: [antvis/my-f2] 一个页面有多个图表,有的图表有可能只画了一半的大小 (#15)

@simaQ

可以否帮忙看一下:

根据 canvas 文档所述,将画布的宽、高属性按照设备的分辨率放大后,再通过样式的宽、高缩小,可以在高 dpr 下取得更细腻的显示。但是这样做了以后,支付宝开发工具中图表被放大很多(详见下面的截图,右侧微信小程序是可以正常显示的)。

因为是采用 Megalo 写的,不能确定是哪里出了问题。如果将 ctx.scale(pixelRatio, pixelRatio) 去掉,支付宝开发工具可以正常显示。

截图

代码 // 如果需要在高 dpr 下取得更细腻的显示,需要先将 canvas 用属性设置放大,用样式缩小,例如 // <!-- getSystemInfoSync().pixelRatio === 2 --> // <canvas width="200" height="200" style="width:100px;height:100px;"/> const pixelRatio = my.getSystemInfoSync().pixelRatio; _this.width = rect[0].width pixelRatio; // 按设备分辨率放大 canvas 的宽、高属性 _this.height = rect[0].height pixelRatio; const ctx = my.createCanvasContext(_this.canvasId); ctx.scale(pixelRatio, pixelRatio); // alipay: 按设备分辨率放大 canvas 属性后,通过样式缩小不回来 const canvas = new F2.Renderer(ctx); _this.canvas = canvas; if (typeof callback === 'function') { _this.chart = callback( canvas, rect[0].width, rect[0].height, F2 ); } else if (_this.opts && typeof _this.opts.onInit === 'function') { _this.chart = this.opts.onInit( canvas, rect[0].width, rect[0].height, F2 ); }

你好,问题解决了吗,我微信小程序遇到了同样的问题,使用F2的pixelRatio导致画布大小变大了,使用myCtx.scale图表没有变清晰。

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

b2nil commented 4 years ago

@Yrobot

我当时遇到的是在支付宝小程序上,钉钉不知道具体情况,不知道是不是一样。 跟上面 @huixu123 说的那样,可以暂时把高清操作去掉。

根据 @simaQ 描述,native-canvas 版本似乎没那么复杂。于是我当时使用了 my-f2 native-canvas 分支中的代码。

然后遇到了这个问题: native canvas 事件:context.removeEventListener is not a function。 具体的 [merged PR]:(https://github.com/antvis/my-f2/commit/f7d2f9f90c41b5804e4756d7c6bd984997a7736f)

太久没有跟进这个项目了,不知道后来的进展怎么样。今天看一下,我这个 PR 也被改回来了。 如果喜欢折腾的话,看看改改 my-f2 的源码能不能解决。

Yrobot commented 4 years ago

@Yrobot

我当时遇到的是在支付宝小程序上,钉钉不知道具体情况,不知道是不是一样。 跟上面 @huixu123 说的那样,可以暂时把高清操作去掉。

根据 @simaQ 描述,native-canvas 版本似乎没那么复杂。于是我当时使用了 my-f2 native-canvas 分支中的代码。

然后遇到了这个问题: native canvas 事件:context.removeEventListener is not a function。 具体的 [merged PR]:(f7d2f9f)

太久没有跟进这个项目了,不知道后来的进展怎么样。今天看一下,我这个 PR 也被改回来了。 如果喜欢折腾的话,看看改改 my-f2 的源码能不能解决。

感谢回复,我目前已经解决高分辨率的问题,下面会分享一下

Yrobot commented 4 years ago

@b2nil @huixu123 我这边放弃使用F2自带的pixelRatio,用canvasContext.scale去处理了 ps:用的是微信kbone开发(别用kbone官方方法获取canvasDOM,很坑,用querySelector获取)

// DOM
<canvas
      type="2d"
      style={{ width: width + 'px', height: height + 'px' }}
      id={cnvasID}
      canvas-id={cnvasID}
      key={cnvasID}
    />

// JS 绘制逻辑
const draw = canvas => {
    const ctx = canvas.getContext('2d')
    ctx.restore()
    canvas.width = width * pixelRatio
    canvas.height = height * pixelRatio
    ctx.scale(pixelRatio, pixelRatio)

    F2.Global.pixelRatio = 1
    F2.Global.fontFamily = 'sans-serif'
    const chart = new F2.Chart({
      context: ctx,
      width: width,
      height: height
    })
    doChart(chart)
  }
huixu123 commented 4 years ago

@Yrobot 我当时遇到的是在支付宝小程序上,钉钉不知道具体情况,不知道是不是一样。 跟上面 @huixu123 说的那样,可以暂时把高清操作去掉。 根据 @simaQ 描述,native-canvas 版本似乎没那么复杂。于是我当时使用了 my-f2 native-canvas 分支中的代码。 然后遇到了这个问题: native canvas 事件:context.removeEventListener is not a function。 具体的 [merged PR]:(f7d2f9f) 太久没有跟进这个项目了,不知道后来的进展怎么样。今天看一下,我这个 PR 也被改回来了。 如果喜欢折腾的话,看看改改 my-f2 的源码能不能解决。

感谢回复,我目前已经解决高分辨率的问题,下面会分享一下

确实是this.setData()异步了。改下my-f2组件的代码 。把this.props.onInit()挪到的this.setData()的回调里可以解决这个问题。后面需要把这个组件从node_modules里挪出来 this.setData({ id, width: width pixelRatio, height: height pixelRatio },()=>{ this.props.onInit(F2, { context, width, height, pixelRatio }); }); //this.props.onInit(F2, { context, width, height, pixelRatio });

zengyue commented 4 years ago

再提个PR改一下?

ZHDLFFY commented 4 years ago

我就想知道有人用interaction这个接口吗,我用不了,没作用,滚动条直接报错