在 Swift 图表中使用 Foudation 库中的测量类型

news2024/11/23 18:47:10

前言

在这篇文章中,我们将建立一个条形图,比较基督城地区自然散步的持续时间。我们将使用今年推出的新的Swift Charts 框架,并将看到如何绘制默认不符合 Plottable 协议的类型的数据,如 Measurement<UnitDuration>

定义图表的数据

让我们先定义一下要在图表中展现的数据。

我们声明了一个包含标题和步行时间(小时)的 Walk 结构体。我们使用 Foundation 框架中的测量类型Measurement和单位类型UnitDuration来表示每次步行的时间。

struct Walk {
    let title: String
    let duration: Measurement<UnitDuration>
}

我们在数组 works 中存储要在图表中显示的数据。

let walks = [
    Walk(
        title: "Taylors Mistake to Sumner Beach Coastal Walk",
        duration: Measurement(value: 3.1, unit: .hours)
    ),
    Walk(
        title: "Bottle Lake Forest",
        duration: Measurement(value: 2, unit: .hours)
    ),
    Walk(
        title: "Old Halswell Quarry Loop",
        duration: Measurement(value: 0.5, unit: .hours)
    ),
    ...
]

在图表中使用测量值

尝试直接在图表中使用测量值

让我们定义一个 Chart,并将 walks 数组作为数据参数传递给它。因为我们知道我们的walk 标题是唯一的,所以我们可以直接使用它们作为 id,但你也可以将你的数据模型改为 Identifiable

Chart(walks, id: \.title) { walk in
    BarMark(
        x: .value("Duration", walk.duration),
        y: .value("Walk", walk.title)
    )
}

注意,因为 Measurement<UnitDuration> 没有遵守 Plottable 协议,我们会得到一个错误:「Initializer ‘init(x:y:width:height:stacking:)’ requires that ‘Measurement’ conform to ‘Plottable’」

BarkMark 的初始化器期望收到一个用于 x 和 y 的 PlottableValue 参数。而且 PlottableValue 的值类型必须符合 Plottable 协议。

我们有几个选择来解决这个错误。我们可以提取测量值的 value,它是一个 Double 类型,它是默认符合 Plottable 的,我们可以扩展具有 Plottable 一致性的 Measurement<UnitDuration>,或者我们可以定义一个包装了测量的类型并使其符合 Plottable 协议。

如果我们简单地从测量值中提取,我们就会失去上下文,不知道用什么单位来创建测量值。这意味着,我们将无法正确格式化图表的标签来向用户表示单位。虽然我们可以记住我们在创建测量时使用了小时 hours,但这并不理想。例如,我们可以决定以后改变数据模型,以分钟为单位存储持续时间,或者数据可能来自其他地方,所以手动重构单位并不是一个完美的解决方案。

Plottable 的一致性来扩展 Measurement<UnitDuration> 是可行的,但根据 Swift 中关于外部类型的追溯一致性的警告 (Warning for Retroactive Conformances of External Types),如果 Swift Charts 在未来添加了这种一致性,它可能会被破坏。

我们将研究如何定义我们自己的类型来包装 measurement,并为我们的自定义类型添加 Plottable 的一致性。

设计一个包装器类型

设计一个符合 Plottable 标准的包装器类型

我们将定义一个自定义的 PlottableMeasurement 类型,并使其成为通用的,所以它可以容纳任何类型的单位的测量类型。

struct PlottableMeasurement<UnitType: Unit> {
    var measurement: Measurement<UnitType>
}

然后,我们将为 PlottableMeasurement 添加 Plottable 的一致性,其单位为 UnitDuration 类型。我们可以在将来添加对其他单位的支持。

extension PlottableMeasurement: Plottable where UnitType == UnitDuration {
    var primitivePlottable: Double {
        self.measurement.converted(to: .minutes).value
    }
    
    init?(primitivePlottable: Double) {
        self.init(
            measurement: Measurement(
                value: primitivePlottable,
                unit: .minutes
            )
        )
    }
}

Plottable 协议有两个要求: primitivePlottable 属性必须返回原始类型之一,如 DoubleStringDate,以及一个可失败的初始化器,从原始 plottable 类型创建一个值。

我决定将测量值转换为分钟,但你可以选择适合你需要的任何其他单位。只是在与原始值转换时要使用相同的单位,这一点很重要。

我们现在可以更新我们的图表,以使用我们的自定义 Plottable 类型。

Chart(walks, id: \.title) { walk in
    BarMark(
        x: .value(
            "Duration",
            PlottableMeasurement(measurement: walk.duration)
        ),
        y: .value("Walk", walk.title)
    )
}

它可以工作,但X轴上的标签没有格式化,没有向用户显示测量单位。我们接下来要解决这个问题。

显示格式化标签

显示带有测量单位的格式化标签

为了定制X轴上的标签,我们将使用chartXAxis(content:)修改器,并用传递给我们的值重构x轴的标记。

Chart(walks, id: \.title) { ... }
    .chartXAxis {
        AxisMarks { value in
            AxisGridLine()
            AxisValueLabel("""
            \(value.as(PlottableMeasurement.self)!
                .measurement
                .converted(to: .hours),
            format: .measurement(
                width: .narrow,
                numberFormatStyle: .number.precision(
                    .fractionLength(0))
                )
            )
            """)
        }
    }

我们首先添加网格线,然后重构给定值的标签。

AxisValueLabel在初始化器中接受一个LocalizedStringKey,它可以通过插值测量和指定其格式风格来构建。

我们收到的值是使用我们在 Plottable 一致性中定义的初始化器创建的,所以在我们的案例中,测量值是以分钟为单位提供的。但我相信对于这个特定的图表,使用小时会更好。我们可以很容易地将测量值转换为插值内部所需的单位。在这里,我们确定该值是 PlottableMeasurement 类型的,所以我们可以强制解包类型转换。

我选择了缩小的格式和小数点后零位数作为数字样式,但你可以根据你的具体图表调整这些设置。

最后的结果是在X轴上显示以小时为单位的格式化持续时间。

你可以从我们的 GitHub repo 中获得这篇文章中使用的项目的完整 示例代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/14436.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【附源码】计算机毕业设计JAVA校园社团管理平台演示录像2021

【附源码】计算机毕业设计JAVA校园社团管理平台演示录像2021 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1…

537页15万字大数据治理体系、大数据可视化平台及应用方案

目录 第1章 前言 第2章 集团企业大数据现状分析 2.1、 基本现状 2.2、 总体现状 2.2.1、 行领导 2.2.2、 业务人员 2.3、 数据架构方面 2.3.1、 业务表现 2.3.2、 问题 2.4、 数据应用难题 2.4.1、 缺少统一的应用分析标准 2.4.1.1、 业务表现 2.4.1.2、 问题 2.4…

天天都在CRUD,你知道数据库如何工作的吗?

作为一个天天都在CRUD的程序员&#xff0c;你有没有想过&#xff0c;数据库是如何工作的&#xff1f; 今天&#xff0c;让我们从一个最最最简单的模型开始&#xff0c;揭开数据库神秘的一角。 对我们使用者而言&#xff0c;数据库就像是一个黑盒子&#xff0c;你可以往它里面…

神策 SCRM 正式发布,打通企业全域数据,聚焦私域精细化运营

随着企业微信能力的不断延展和客户接受度的持续提升&#xff0c;越来越多的企业开始基于企业微信生态搭建私域流量池&#xff0c;通过高粘性的专属服务和沟通提升客户满意度和转化效率。在企微私域运营过程中&#xff0c;他们发现&#xff1a; 管理难&#xff1a;客户分散在每位…

【Nginx】初识与环境准备

文章目录Nginx简介Nginx的优点及功能特性Nginx常用功能模块及组成Nginx系统环境准备Nginx安装方式介绍Nginx目录结构分析Nginx服务器启停命令方式一:Nginx服务的信号控制方式二:Nginx的命令行控制Nginx服务操作的问题Nginx配置成系统服务可能会出现的问题Nginx命令配置到系统环…

酷开科技 | 强势出圈,酷开系统一举突破媒介价值纵深

从起势到成熟&#xff0c;从无序到理性&#xff0c;从单一到多维&#xff0c;如今的OTT市场&#xff0c;早已是一个全新的舞台&#xff0c;不仅OTT的功能与服务承载更加丰富&#xff0c;产业的竞争维度也更加多元。踔厉奋发的OTT行业&#xff0c;在新的时代背景和产业环境下&am…

关于Python自动化的就业真相

作为近几年来特别受欢迎的编程语言之一&#xff0c;Python一直以来被众多行业内人士寄予厚望&#xff0c;今后有可能替代老牌霸主Java&#xff0c;成为新一代编程语言榜首。 为什么懂技术的人必学Python&#xff1f; 与其他语言相比&#xff0c;Python中的语言语法特别简单&a…

ABBYY FineReader PDF2023版本有什么新特点?

ABBYY FineReader PDF Windows版更加智能的 PDF 解决方案在数字化工作场所转换、编辑、共享和协作处理数字化工作场所中的 PDF 和扫描件。 在阅读某些扫描得到的PDF文档时&#xff0c;我经常因为它不可编辑而烦恼&#xff0c;直到我遇到了ABBYY。打开ABBYY FineReader PDF软件…

【MySQL进阶】深入理解B+树索引底层原理

【MySQL进阶】深入理解B树索引底层原理 文章目录【MySQL进阶】深入理解B树索引底层原理一、前言——没有索引的查找1、在一个页中的查找2、在很多页中查找3、总结二、索引1、一个简单的索引方案2、InnoDB中的索引方案3、B 树4、聚簇索引5、二级索引6、回表7、联合索引三、InnoD…

vivado跑完发邮件

前言 vivado 综合实现要跑好长时间&#xff0c;耍会儿手机不过分吧。然而我不想时不时抬头看有没有跑完&#xff0c;于是产生了该脚本 一. QQ邮箱配置 参考&#xff1a;https://blog.csdn.net/qq_40608730/article/details/104904398?spm1001.2014.3001.5502 &#xff08;注…

c++11特性(2)

目录 1.新增了两个默认成员函数 2.新增了几个关键字 3.可变参数模板 1.新增了两个默认成员函数 a.移动构造函数 b.移动赋值运算符重载 默认生成的前提条件&#xff1a;没有实现析构函数&#xff0c;拷贝构造&#xff0c;拷贝赋值重载中的任意一个。 为什么要实现移动的版…

三菱PLC单轴运动控制

1、什么是运动控制 ​ 运动控制&#xff0c;也可叫做电力拖动控制&#xff1b;它是自动化的一个分支&#xff0c;其动力源大部分都基于电动机。 也就是说&#xff0c;运动控制其实是基于电动机&#xff0c;实现物体对于角位移、速度、转矩等物理量改变的控制。 这里面&#xf…

Linux开发工具(2)——vim

文章目录多模式编辑器——vimvim的基本操作命令模式&#xff08;Normal mode&#xff09;插入模式&#xff08;Insert mode&#xff09;底行模式&#xff08;Last line mode&#xff09;vim的基本配置原理配置sudoers文件多模式编辑器——vim vim是一种多模式编辑器&#xff0c…

MYSQL语法一:创建表和查看表的所有列和所有数据库等

前言&#xff1a;接下里&#xff0c;我们即将开启mysql的旅行之路。首先是它的基础知识 1.mysql的基本知识点 mysql是客户端加服务器的模式。 客户端给服务器发送的数据称为请求request 服务器给客户端返回的数据称为响应response 客户端和服务器可以在不同主机上&#xff0c;…

轻松学习jQuery事件和动画

✅作者简介&#xff1a;热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏&#xff1a;前端开发者…

计算机网络-网络层详细讲解(持续更新中)

网络层概述 网络层的主要任务是实现网络互连&#xff0c;进而实现数据包在各网络之间的传输。 要实现网络层主要任务&#xff0c;需要解决以下主要问题&#xff1a; 网络层向运输层提供怎样的服务&#xff08;“可靠传输”还是“不可靠传输‘&#xff09;网络层寻址问题路由…

小啊呜产品读书笔记001:《邱岳的产品手记-04》第07+08讲 关于需求变更

小啊呜产品读书笔记001&#xff1a;《邱岳的产品手记-04》第0708讲 关于需求变更一、今日阅读计划二、泛读&知识摘录1、07讲 关于需求变更&#xff08;上&#xff09;&#xff1a;需求背后的需求2、08讲 关于需求变更&#xff08;下&#xff09;&#xff1a;化变更于无形三…

【Pytorch with fastai】第 14 章 :ResNet

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

自动化测试selenium在小公司的成功实践

前言 可能提到自动化测试selenium&#xff0c;大家都会想到用python语言来编写脚本。但我们选择了java语言&#xff0c;因为我相信大部分公司java程序员比python程序员多得多。而对于很多测试人员&#xff0c;并不能熟练使用编程语言&#xff0c;所以他们需要别人指导。与其使…

iOS 16.2 的7个惊人变化

看起来 iOS 16 正在不断扩展 你已经知道 iOS 16 和 iOS 16.1 有多么不可思议。所以我认为下一次更新已经没有多少了——iOS 16.2。 Apple 刚刚通过 iOS 16.2 Developer Beta 1 消除了这些信念。 Developer Beta 2 中还有 7 个变化。相信我,它们也很棒。 #1、锁定屏幕的药物…