QML 3D柱形图(Bars3D)

3D柱形图是数据可视化中最直观的图表类型之一,它通过不同高度的立柱来展示数据在三维空间中的分布情况。Qt Data Visualization 模块中的 Bars3D 类型让开发者能够轻松创建功能丰富的交互式3D柱形图。

Bars3D 核心属性与方法

表:Bars3D 主要属性与方法

属性/方法类型描述示例值
widthreal设置图表宽度width: parent.width
heightreal设置图表高度height: parent.height
selectionModeenum选择模式(无/单项/行/列/行与列/切片)AbstractGraph3D.SelectionRow
shadowQualityenum阴影质量(无/低/中/高/软低/软中/软高)AbstractGraph3D.ShadowQualitySoftMedium
scene.activeCameraQ3DCamera控制场景相机xRotation: 45.0
themeTheme3D设置图表主题theme: Theme3D { type: Theme3D.ThemeQt }
barThicknessreal柱体厚度(0-1)0.5
barSpacingsize柱体间距(QSize)Qt.size(0.1, 0.1)
rowAxisCategory3DAxis行坐标轴rowAxis: Category3DAxis { labels: ["Q1","Q2","Q3","Q4"] }
columnAxisCategory3DAxis列坐标轴columnAxis: Category3DAxis { labels: ["2020","2021","2022"] }
valueAxisValue3DAxis值坐标轴valueAxis: Value3DAxis { min: 0; max: 100 }
addSeries()method添加数据系列bars3D.addSeries(barSeries)
removeSeries()method移除数据系列bars3D.removeSeries(barSeries)

基本实现示例

以下是一个完整的3D柱形图实现示例,展示了如何从数据模型创建动态3D柱形图:

Bars3D {
            id: bars3D
            width: parent.width
            height: parent.height

            // 设置相机视角
            scene.activeCamera.xRotation: xSlider.value
            scene.activeCamera.yRotation: ySlider.value
            // scene.activeCamera.zoomLevel: 0.8

            // 使用Qt预定义主题
            theme: Theme3D {
                type: Theme3D.ThemePrimaryColors
                font.pointSize: 12
                labelBackgroundEnabled: true
            }

            // 设置坐标轴
            rowAxis: CategoryAxis3D {
                labels: ["北京", "上海", "广州", "深圳"]
                title: "城市"
                titleVisible: true
            }

            columnAxis: CategoryAxis3D {
                labels: ["2020", "2021", "2022"]
                title: "年份"
                titleVisible: true
            }

            valueAxis: ValueAxis3D {
                title: "GDP(亿元)"
                titleVisible: true
                min: 0
                max: 40000
                labelFormat: "%.0f"
            }

            // 数据系列
            Bar3DSeries {
                id: mainSeries
                itemLabelFormat: "城市 @rowLabel - 年份 @colLabel: @valueLabel 亿元"

                // 使用ItemModelBarDataProxy代理模型数据
                ItemModelBarDataProxy {
                    itemModel: dataModel
                    rowRole: "city"    // 对应模型中的城市角色
                    columnRole: "year"  // 对应模型中的年份角色
                    valueRole: "gdp"   // 对应模型中的GDP值角色
                }
            }
        }

        // 数据模型
        ListModel {
            id: dataModel
            ListElement { city: "北京"; year: "2020"; gdp: 36103 }
            ListElement { city: "北京"; year: "2021"; gdp: 40270 }
            ListElement { city: "北京"; year: "2022"; gdp: 41611 }
            ListElement { city: "上海"; year: "2020"; gdp: 38701 }
            ListElement { city: "上海"; year: "2021"; gdp: 43215 }
            ListElement { city: "上海"; year: "2022"; gdp: 44653 }
            ListElement { city: "广州"; year: "2020"; gdp: 25019 }
            ListElement { city: "广州"; year: "2021"; gdp: 28232 }
            ListElement { city: "广州"; year: "2022"; gdp: 28839 }
            ListElement { city: "深圳"; year: "2020"; gdp: 27670 }
            ListElement { city: "深圳"; year: "2021"; gdp: 30665 }
            ListElement { city: "深圳"; year: "2022"; gdp: 32388 }
        }

        Row {
            width: parent.width
            anchors.bottom: parent.bottom
            anchors.bottomMargin: 60
            anchors.left: parent.left
            anchors.leftMargin: 10
            spacing: 10

            Label { text: "xr: ";font.pixelSize: 16 }

            Slider {
                id: xSlider
                width: 200
                height: 30
                from: -180
                to: 180
                stepSize: 1
                value: -25
            }

            Label { text: xSlider.value; font.pixelSize: 16 }
        }

        Row {
            width: parent.width
            anchors.bottom: parent.bottom
            anchors.bottomMargin: 30
            anchors.left: parent.left
            anchors.leftMargin: 10
            spacing: 10

            Label { text: "xy: ";font.pixelSize: 16 }

            Slider {
                id: ySlider
                width: 200
                height: 30
                from: -180
                to: 180
                stepSize: 1
                value: 40
            }

            Label { text: ySlider.value; font.pixelSize: 16 }
        }

 

动态效果与交互

3D柱形图支持丰富的动态效果和用户交互。以下示例展示了如何添加相机动画和鼠标交互:

Bars3D {
        id: bars3D
        width: parent.width
        height: parent.height

        // 设置相机视角
        scene.activeCamera.xRotation: -25
        scene.activeCamera.yRotation: 40
        // scene.activeCamera.zoomLevel: 0.8

        // 使用Qt预定义主题
        theme: Theme3D {
            type: Theme3D.ThemePrimaryColors
            font.pointSize: 12
            labelBackgroundEnabled: true
        }

        // 设置坐标轴
        rowAxis: CategoryAxis3D {
            labels: ["北京", "上海", "广州", "深圳"]
            title: "城市"
            titleVisible: true
        }

        columnAxis: CategoryAxis3D {
            labels: ["2020", "2021", "2022"]
            title: "年份"
            titleVisible: true
        }

        valueAxis: ValueAxis3D {
            title: "GDP(亿元)"
            titleVisible: true
            min: 0
            max: 40000
            labelFormat: "%.0f"
        }

        // 数据系列
        Bar3DSeries {
            id: mainSeries
            itemLabelFormat: "城市 @rowLabel - 年份 @colLabel: @valueLabel 亿元"

            // 使用ItemModelBarDataProxy代理模型数据
            ItemModelBarDataProxy {
                itemModel: dataModel
                rowRole: "city"    // 对应模型中的城市角色
                columnRole: "year"  // 对应模型中的年份角色
                valueRole: "gdp"   // 对应模型中的GDP值角色
            }
        }
    }

    // 数据模型
    ListModel {
        id: dataModel
        ListElement { city: "北京"; year: "2020"; gdp: 36103 }
        ListElement { city: "北京"; year: "2021"; gdp: 40270 }
        ListElement { city: "北京"; year: "2022"; gdp: 41611 }
        ListElement { city: "上海"; year: "2020"; gdp: 38701 }
        ListElement { city: "上海"; year: "2021"; gdp: 43215 }
        ListElement { city: "上海"; year: "2022"; gdp: 44653 }
        ListElement { city: "广州"; year: "2020"; gdp: 25019 }
        ListElement { city: "广州"; year: "2021"; gdp: 28232 }
        ListElement { city: "广州"; year: "2022"; gdp: 28839 }
        ListElement { city: "深圳"; year: "2020"; gdp: 27670 }
        ListElement { city: "深圳"; year: "2021"; gdp: 30665 }
        ListElement { city: "深圳"; year: "2022"; gdp: 32388 }
    }

    // 在Bars3D定义后添加动画
    SequentialAnimation {
        id: cameraAnimation
        running: true
        loops: Animation.Infinite

        NumberAnimation {
            target: bars3D.scene.activeCamera
            property: "xRotation"
            from: 20.0
            to: 60.0
            duration: 5000
            easing.type: Easing.InOutQuad
        }

        NumberAnimation {
            target: bars3D.scene.activeCamera
            property: "yRotation"
            from: 10.0
            to: 60.0
            duration: 5000
            easing.type: Easing.InOutCubic
        }

        // NumberAnimation {
        //     target: bars3D.scene.activeCamera
        //     property: "zoomLevel"
        //     from: 0.7
        //     to: 1.2
        //     duration: 3000
        //     easing.type: Easing.OutBack
        // }
    }

    // 添加鼠标交互区域
    MouseArea {
        anchors.fill: parent
        property point lastMousePos

        onPressed: {
            lastMousePos = Qt.point(mouseX, mouseY)
            cameraAnimation.stop()
        }

        onPositionChanged: {
            if (pressed) {
                var dx = mouseX - lastMousePos.x
                var dy = mouseY - lastMousePos.y
                bars3D.scene.activeCamera.xRotation += dy * 0.1
                bars3D.scene.activeCamera.yRotation -= dx * 0.1
                lastMousePos = Qt.point(mouseX, mouseY)
            }
        }

        onWheel: {
            bars3D.scene.activeCamera.zoomLevel += wheel.angleDelta.y * 0.05
        }
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值