AAChartModel / AAChartCore

📈📊☕️☕️☕️An elegant modern declarative data visualization chart framework for Android. Extremely powerful, supports line, spline, area, areaspline, column, bar, pie, scatter, angular gauges, arearange, areasplinerange, columnrange, bubble, box plot, error bars, funnel, waterfall and polar chart types.极其精美而又强大的 Android 数据可视化图表框架,支持柱状图、条形图、折线图、曲线图、折线填充图、曲线填充图、气泡图、扇形图、环形图、散点图、雷达图、混合图等各种类型的多达几十种的信息图图表,完全满足工作所需.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

触摸数据条弹出的框里的数据格式要如何自定义显示?

InnocentYang opened this issue · comments

sleep_chart_data

你好,我用AAChart画睡眠数据的图表,有两个serias分别表示深睡时长和浅睡时长,
数据本来是以秒为单位,在绘制图表时手动把它转换成以小时为单位,比如数据=31320秒,图表显示=8.7小时。

客户提出要显示成 8小时42分,我不知道该怎么做。(还要做国际化,小时分钟数字要根据手机的Locale显示不同的语言)

sleep_chart_code

我试了试,数据如果直接传秒,y轴坐标也会有问题,显示的单位也是10K--秒,不知道怎么将y坐标也显示成小时

请你帮我处理一下,非常感谢

实在不好意思,JS代码我看不懂,能帮我写一下这个代码吗?我自己实在搞不定。
你可以给我的邮箱 yanglihappy001@163.com 发个收款码,我发20块钱红包给你。
谢谢。

image
我 本来想尝试取一个index,然后做一个数据数组,但thisPoint.index undefined。

红包就免了吧. 你把你的图表配置 AAChartModel 或者 AAOptions 实例的代码粘贴一下, 我这边复现一下, 我看看怎么弄.

PS: 请直接粘贴代码文本, 不要截取代码图片.

String[] categories = { "周一","周二","周三","周四","周五","周六","周日"};

Object[] deepSeconds = {31320, 31320, 31320, 31320, 31320, 31320, 31320};  // 原始数据,单位是秒
Object[] lightSeconds = {3600, 3600, 3600, 3600, 3600, 3600, 3600};

Object[] deepHours = {8.7, 8.7, 8.7, 8.7, 8.7, 8.7, 8.7}; // 除以3600得到  单位是小时
Object[] lightHours = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0};

创建 AAChartModel

generateChartModel(categories , deepHours, lightHours)

private AAChartModel generateChartModel(String[] categories, Object[] deepTimes, Object[] lightTimes) {
        AASeriesElement element1 = new AASeriesElement()
                .name(getString(R.string.deep_sleep))
                .dataLabels(new AADataLabels()
                        .y(-10)
                        .format("{total} mm")
                        .color(AAColor.Red)
                        .shape("callout")
                        .backgroundColor(AAColor.White)
                        .borderColor(AAColor.Red)
                        .borderRadius(1)
                        .borderWidth(1)
                )
                .data(deepTimes);
        AASeriesElement element2 = new AASeriesElement()
                .name(getString(R.string.light_sleep))
                .data(lightTimes);
        AASeriesElement[] series = {element1, element2};

        return new AAChartModel()
                .chartType(AAChartType.Column)
                .stacking(AAChartStackingType.Normal)
                .legendEnabled(true)
                .xAxisTickInterval(xAxisInterval())
                .markerRadius(0)
                .categories(categories)
                .tooltipValueSuffix(getString(R.string.hour))
                .colorsTheme(colorsTheme)
                .markerSymbolStyle(AAChartSymbolStyleType.BorderBlank)
                .touchEventEnabled(true)
                .series(series);
    }

期望:

(1)点击图表弹出的Tooltip里面显示的是:
周三
深睡:8小时42分
浅睡:1小时0分
(还要做多语言适配,如果实在不行,8H 42M 也行)
(2)y轴显示小时数字

非常感谢

我在尝试用 AAOptions ,在拿这段代码改,在各种混乱的尝试

ArrayList<String[]> strList = new ArrayList<>();
        strList.add(deepStringArr);
        strList.add(lightStringArr);

        AAChartModel aaChartModel = generateChartModel(categories, deepTimes, lightTimes);

        String jsFormatterStr = String.format("function () {\n" +
                "        let wholeContentStr = this.points[0].x + '<br/>';\n" +
                "        let length = this.points.length;\n" +
                "        for (let i = 0; i < length; i++) {\n" +
                "            let thisPoint = this.points[i];\n" +
                "            let yValue = thisPoint.y;\n" +
                "            let indexValue = thisPoint.index;\n" +
                "            if (yValue != 0) {\n" +
                "                let prefixStr = '<span style=\\\"' + 'color:'+ thisPoint.color + '; font-size:13px\\\"' + '>◉ ';\n" +
                "                wholeContentStr += prefixStr + thisPoint.series.name + ' : ' + thisPoint.series.index + ' : ' + yValue + ' : ' + indexValue + '" + suffix + "' + '<br/>';\n" +
                "            }\n" +
                "        }\n" +
                "        return wholeContentStr;\n" +
                "    }");

        AATooltip aaTooltip = new AATooltip()
                .useHTML(true)
                .valueSuffix(suffix)
                .formatter(jsFormatterStr);
        AAOptions aaOptions = aaChartModel.aa_toAAOptions();
        aaOptions.tooltip(aaTooltip);
        return aaOptions;

配置 AAOptions

    public static AAOptions customizeTooltipFormatter() {
        String[] categories = { "周一","周二","周三","周四","周五","周六","周日"};

        Object[] deepSeconds = {31320, 31320, 31320, 31320, 31320, 31320, 31320};  // 原始数据,单位是秒
        Object[] lightSeconds = {3600, 3600, 3600, 3600, 3600, 3600, 3600};

        Object[] deepHours = {8.7, 8.7, 8.7, 8.7, 8.7, 8.7, 8.7}; // 除以3600得到  单位是小时
        Object[] lightHours = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0};

        AAChartModel aaChartModel = generateChartModel(categories , deepHours, lightHours);

        AAOptions aaOptions = aaChartModel.aa_toAAOptions();
        aaOptions.tooltip.shared(true)
                .formatter("function () {\n" +
                        "        function hoursToHoursMinutes (hours) {\n" +
                        "            const hoursInt = Math.floor(hours); \n" +
                        "            const minutes = Math.round((hours - hoursInt) * 60); \n" +
                        "            return hoursInt + \"小时 \" + minutes + \"分钟\";\n" +
                        "        }\n" +
                        "\n" +
                        "        let s = '<b>' + this.x + '</b>' + '<br/>';\n" +
                        "        const colorDot1 = '<span style=\\\"'+'color:#1e90ff; font-size:13px\\\"'+'>◉</span> ';\n" +
                        "        const colorDot2 = '<span style=\\\"'+'color:#ef476f; font-size:13px\\\"'+'>◉</span> ';\n" +
                        "\n" +
                        "        const originalPoint1 = this.points[0].y;\n" +
                        "        const originalPoint2 = this.points[1].y;\n" +
                        "\n" +
                        "        const finalPoint1 = hoursToHoursMinutes (originalPoint1);\n" +
                        "        const finalPoint2 = hoursToHoursMinutes (originalPoint2);\n" +
                        "\n" +
                        "        const s1 = colorDot1 +this.points[0].series.name + ': ' + finalPoint1 + '<br/>';\n" +
                        "        const s2 = colorDot2 +this.points[1].series.name + ': ' + finalPoint2;\n" +
                        "        s += s1 + s2;\n" +
                        "        return s;\n" +
                        "    }");


        //禁用图例点击事件
        aaOptions.plotOptions.series.events = new AASeriesEvents()
                .legendItemClick("function() { " +
                        "return false; " +
                        "}");

        return aaOptions;
    }



    private static AAChartModel generateChartModel(String[] categories, Object[] deepTimes, Object[] lightTimes) {
        AASeriesElement element1 = new AASeriesElement()
                .name("深度睡眠")
                .dataLabels(new AADataLabels()
                        .y(-10)
                        .format("{total} mm")
                        .color(AAColor.Red)
                        .shape("callout")
                        .backgroundColor(AAColor.White)
                        .borderColor(AAColor.Red)
                        .borderRadius(1)
                        .borderWidth(1)
                )
                .data(deepTimes);
        AASeriesElement element2 = new AASeriesElement()
                .name("浅睡眠")
                .data(lightTimes);
        AASeriesElement[] series = {element1, element2};

        return new AAChartModel()
                .chartType(AAChartType.Column)
                .stacking(AAChartStackingType.Normal)
                .legendEnabled(true)
//                .xAxisTickInterval(xAxisInterval())
                .markerRadius(0)
                .categories(categories)
//                .tooltipValueSuffix(getString(R.string.hour))
//                .colorsTheme(colorsTheme)
                .markerSymbolStyle(AAChartSymbolStyleType.BorderBlank)
                .touchEventEnabled(true)
                .series(series);
    }

最终图表:

Screenshot_20240508_215314

以上 Java 代码最终转化而成的 JS 代码对应的内容如下:

Highcharts.chart('container', {
    "chart": {
        "backgroundColor": "#ffffff",
        "inverted": false,
        "panning": true,
        "pinchType": "none",
        "polar": false,
        "type": "column"
    },
    "colors": [
        "#fe117c",
        "#ffc069",
        "#06caf4",
        "#7dffc0"
    ],
    "credits": {
        "enabled": false
    },
    "legend": {
        "enabled": true,
        "itemStyle": {

        }
    },
    "plotOptions": {
        "column": {
            "borderRadius": 0,
            "borderWidth": 0
        },
        "series": {
            "dataLabels": {
                "enabled": false
            },
            "stacking": "normal"
        }
    },
    "series": [
        {
            "data": [
                8.7,
                8.7,
                8.7,
                8.7,
                8.7,
                8.7,
                8.7
            ],
            "dataLabels": {
                "backgroundColor": "white",
                "borderColor": "red",
                "borderRadius": 1,
                "borderWidth": 1,
                "color": "red",
                "format": "{total} mm",
                "shape": "callout",
                "y": -10
            },
            "name": "深睡"
        },
        {
              "data": [
                1,
                1,
                1,
                1,
                1,
                1,
                1
            ],
            "name": "浅睡"
        }
    ],
    "subtitle": {

    },
    "title": {
        "text": ""
    },
    "tooltip": {
       "formatter": function () {
        function hoursToHoursMinutes (hours) {
            const hoursInt = Math.floor(hours); 
            const minutes = Math.round((hours - hoursInt) * 60); 
            return hoursInt + "小时 " + minutes + "分钟";
        }

        let s = '<b>' + this.x + '</b>' + '<br/>';
        const colorDot1 = '<span style=\"'+'color:#1e90ff; font-size:13px\"'+'>◉</span> ';
        const colorDot2 = '<span style=\"'+'color:#ef476f; font-size:13px\"'+'>◉</span> ';

        const originalPoint1 = this.points[0].y;
        const originalPoint2 = this.points[1].y;

        const finalPoint1 = hoursToHoursMinutes (originalPoint1);
        const finalPoint2 = hoursToHoursMinutes (originalPoint2);

        const s1 = colorDot1 +this.points[0].series.name + ': ' + finalPoint1 + '<br/>';
        const s2 = colorDot2 +this.points[1].series.name + ': ' + finalPoint2;
        s += s1 + s2;
        return s;
    },
        "shared": true
    },
    "touchEventEnabled": true,
    "xAxis": {
        "categories": [
            "周一",
            "周二",
            "周三",
            "周四",
            "周五",
            "周六",
            "周日"
        ],
        "gridLineWidth": 0,
        "labels": {
            "enabled": true,
            "style": {

            }
        },
        "reversed": false
    },
    "yAxis": {
        "gridLineWidth": 1,
        "labels": {
            "enabled": true,
            "style": {

            }
        },
        "reversed": false,
        "title": {
            "style": {

            },
            "text": ""
        }
    }
});

你可以将这段内容粘贴到在线 Highcharts 代码编辑器中, 自行测试运行查看效果。

好的,非常感谢,我明天去公司试试。
另外,我看代码,是传入 deepHours/lightHours 然后手动计算出 hour 和 minute,
有没有办法 直接传入 秒数组 deepSeconds,并实现需求:tooltip显示 x小时y分钟,Y轴显示小时数?
因为我有些担心分钟数的计算会有四舍五入的问题,导致UI显示时数值差1。

以上 tooltipformatter 函数配置过程比较详细,稍显啰嗦, 可以改的再简洁一些。 更简洁直观 JavaScript 代码示例如下:

  1. 使用原始数组内容去拼接字符串(低版本兼容性更强):
"tooltip": {
    "formatter": function () {
        function formatTime(hours) {
            return [Math.floor(hours), '小时', Math.round((hours - Math.floor(hours)) * 60), '分钟'].join(' ');
        }
        
        // 颜色点样式定义
        var colorStyles = {
            blue: '<span style="color:#1e90ff;font-size:13px;">◉</span> ',
            red: '<span style="color:#ef476f;font-size:13px;">◉</span> '
        };
        
        // 使用数组.join()方法代替模板字符串进行字符串拼接
        var output = [
            '<b>', this.x, '</b><br/>',
            colorStyles.blue, this.points[0].series.name, ': ', formatTime(this.points[0].y), '<br/>',
            colorStyles.red, this.points[1].series.name, ': ', formatTime(this.points[1].y)
        ].join('');
                      
        return output;
    },
    "shared": true
}
  1. 直接使用字符串模板(ES 6 语法):
"tooltip": {
    "formatter": function () {
        // 小时分钟格式化函数
        const formatTime = hours => `${Math.floor(hours)}小时 ${Math.round((hours - Math.floor(hours)) * 60)}分钟`;
        
        // 颜色点样式定义
        const colorStyles = {
            blue: '<span style="color: #1e90ff; font-size: 13px;">◉</span> ',
            red: '<span style="color: #ef476f; font-size: 13px;">◉</span> '
        };
        
        // 格式化悬浮提示信息
        return `
        <b>${this.x}</b><br/>
        ${colorStyles.blue}${this.points[0].series.name}: ${formatTime(this.points[0].y)}<br/>
        ${colorStyles.red}${this.points[1].series.name}: ${formatTime(this.points[1].y)}
    `;
    },
    "shared": true
}
  1. 直接使用字符串模板和更多箭头函数简化代码(ES 6 语法):
"tooltip": {
    "formatter": function () {
        const formatTime = hours => `${Math.floor(hours)}小时 ${Math.round((hours - Math.floor(hours)) * 60)}分钟`;

        // 颜色点样式作为函数以减少重复
        const pointStyle = (color, seriesName, yValue) =>
            `<span style="color:${color};font-size:13px;">◉</span> ${seriesName}: ${formatTime(yValue)}`;

        // 直接构建最终字符串
        return `
            <b>${this.x}</b><br/>
            ${pointStyle('#1e90ff', this.points[0].series.name, this.points[0].y)}<br/>
            ${pointStyle('#ef476f', this.points[1].series.name, this.points[1].y)}
        `;
    },
    "shared": true
}

有没有办法 直接传入 秒数组 deepSeconds,并实现需求

这样的话, 那Y 轴的 labelformatter 应该也要自定义了, 稍嫌麻烦。

睡眠时长估计不可能超过12小时,y轴就固定从0到12,也可以 。

val yAxis = AAYAxis()
yAxis.title(AATitle().text(""))
yAxis.min(0)
yAxis.max(12)
yAxis.tickInterval(1)
aaOptions.yAxisArray = arrayOf(yAxis)

image

我对代码做了一些小调整,
以前是把秒数/3600得到的数值,现在换成小数部分是分钟,这样可以直接把小数部分*100转换成分数,避免计算精度问题。

非常感谢。
我让iOS同事也依样修改。

你好,如上问题; 请问iOS OC 的 .formatterSet(@AAJSFunc(function () { 这里面的JS应该如何写 }