wenmo8 发布的文章

AvalonDock
是我这些天在为自己项目做技术选型时发现的一个很好的开源项目,它是一个用于 WPF 的布局控件库,可以帮助我们实现类似 Visual Studio 的布局效果。因为它自带的一些样式我并不是很喜欢,我想要那种跟 WinUI 风格一样的样式。经过这几天的学习和尝试,我已经按照 WinUI 的样式重新设计了一套 AvalonDock 的主题,现在我把这套主题分享给大家,希望能帮助到有需要的人。

效果截图




项目地址

https://github.com/qian-o/AvalonDock.Themes.WPFUI

参考项目

目前这套主题还不够完善,字典样式也是管理得比较混乱。我会在后续的时间里继续完善这套主题,如果你有任何建议或意见,欢迎在 Issues 中提出。

在公网访问内网http服务可以用内网穿透工具,例如
frp

nps
等优秀工具。但我发现这类工具会在服务器启动不止一个端口,对于有些网络审查来说很容易发现在进行内网穿透。因此我想是否可以只在服务器启动一个http服务来完成内网穿透,公网服务只开放一个http服务端口即可。因此我完成了相关代码:
点击跳转查看代码

原理如下图所示:
image

如上图所示,内网客户端和公网服务器只会创建一个websocket连接,很好的伪装了相关数据。而且websocket收发都是分段的,因此对这些分段数据进行加解密也非常容易(我的代码懒得做)。

方式1的示例:

# 公网服务器运行程序
go run main.go -s 192.168.1.88:8080
# 内网客户端运行程序
go run main.go -c ws://192.168.1.88:8080
# 此时会使用公网 ip:port 作为http代理使用内网机器访问 https://www.baidu.com/
curl -v -x 192.168.1.88:8080 https://www.baidu.com/

方式2的示例:

# 公网服务器运行程序
go run main.go -s 192.168.1.88:8080
# 内网客户端运行程序
go run main.go -c ws://192.168.1.88:8080 -p 172.17.1.88:1080
# 此时会使用公网 ip:port 作为http代理使用内网机器通过 代理172.17.1.88:1080 访问 https://www.baidu.com/
curl -v -x 192.168.1.88:8080 https://www.baidu.com/

我已经验证过使用
git clone https://xxx.git
方式通过公网代理克隆内网仓库代码,完美运行。

1.简介

上一篇主要是讲解我们日常工作中在使用Playwright进行元素定位的一些比较常用的基础定位方式的理论基础知识以及在什么情况下推荐使用。今天这一篇讲解和分享一下剩下部分的基础定位方式。

2.过滤器定位

例如以下 DOM 结构,我们要在其中单击第二个产品卡的购买按钮。我们有几个选项来过滤定位器以获得正确的定位器。

2.1按文本过滤

定位器可以使用 locator.filter()方法按文本进行过滤。它将搜索元素内某处的特定字符串,可能在后代元素中,不区分大小写。您还可以传递正则表达式。

1.使用文本

page.getByRole(AriaRole.LISTITEM)
.filter(
new Locator.FilterOptions().setHasText("Product 2"))
.getByRole(AriaRole.BUTTON,
new Page.GetByRoleOptions().setName("Add to cart"))
.click();

2.使用正则表达式

page.getByRole(AriaRole.LISTITEM)
.filter(
newLocator.FilterOptions()
.setHasText(Pattern.compile(
"Product 2")))
.getByRole(AriaRole.BUTTON,
new Page.GetByRoleOptions().setName("Add to cart"))
.click();

2.2按没有文本进行筛选

通过没有文本进行筛选:

//5 in-stock items
assertThat(page.getByRole(AriaRole.LISTITEM)
.filter(
new Locator.FilterOptions().setHasNotText("Out of stock")))
.hasCount(
5);

2.3子项/后代过滤

定位器支持一个选项,即仅选择具有或没有与另一个定位器匹配的后代的元素的元素。因此,您可以按任何其他定位器进行过滤,例如 Locator.getByRole()、Locator.getByTestId()、Locator.getByText() 等。

page.getByRole(AriaRole.LISTITEM)
.filter(
newLocator.FilterOptions()
.setHas(page.GetByRole(AriaRole.HEADING,
newPage.GetByRoleOptions()
.setName(
"Product 2"))))
.getByRole(AriaRole.BUTTON,
new Page.GetByRoleOptions().setName("Add to cart"))
.click()

我们还可以断言产品卡,以确保只有一个:

assertThat(page
.getByRole(AriaRole.LISTITEM)
.filter(
newLocator.FilterOptions()
.setHas(page.GetByRole(AriaRole.HEADING,
new Page.GetByRoleOptions().setName("Product 2"))))
.hasCount(
1);

过滤定位器
必须相对于原始定位器进行查询,并且从原始定位器匹配项开始进行查询,而不是从文档根开始进行查询。因此,以下操作将不起作用,因为过滤定位器从列表元素开始匹配,该列表元素位于原始定位器匹配的列表项之外:

<ul>
<li>

//✖ WRONG
assertThat(page
.getByRole(AriaRole.LISTITEM)
.filter(
newLocator.FilterOptions()
.setHas(page.GetByRole(AriaRole.LIST)
.GetByRole(AriaRole.HEADING,
new Page.GetByRoleOptions().setName("Product 2"))))
.hasCount(
1);

2.4按没有子项/后代过滤

我们也可以通过内部
没有匹配的元素来过滤。

assertThat(page
.getByRole(AriaRole.LISTITEM)
.filter(
new Locator.FilterOptions().setHasNot(page.getByText("Product 2")))
.hasCount(
1);

敲黑板!!!!请注意,内部定位器是从外部定位符开始匹配的,而不是从文档根目录开始匹配的。

3.定位器操作员

3.1定位器内部匹配

您可以链接创建定位器的方法,例如 Page.getByText() 或 Locator.getByRole(),以将搜索范围缩小到页面的特定部分。

在此示例中,我们首先通过定位其角色listitem来创建一个名为 product 的定位器。然后,我们按文本进行过滤。我们可以再次使用产品定位器来获取按钮的角色并单击它,然后使用断言来确保只有一个文本为“产品 2”的产品。

Locator product =page
.getByRole(AriaRole.LISTITEM)
.filter(
new Locator.FilterOptions().setHasText("Product 2"));

product
.getByRole(AriaRole.BUTTON,
new Locator.GetByRoleOptions().setName("Add to cart"))
.click();

您还可以将两个定位器链接在一起,例如,在特定对话框中查找“保存”按钮:

Locator saveButton =page.getByRole(AriaRole.BUTTON,new Page.GetByRoleOptions().setName("Save"));//...
Locator dialog = page.getByTestId("settings-dialog");
dialog.locator(saveButton).click();

3.2同时匹配两个定位器

方法 Locator.and()通过匹配其他定位器来缩小现有定位器的范围。例如,您可以将 Page.getByRole() 和 Page.getByTitle() 组合在一起,以按角色和标题进行匹配。

Locator button = page.getByRole(AriaRole.BUTTON).and(page.getByTitle("Subscribe"));

3.3匹配两个备选定位器之一

如果您想定位两个或多个元素中的一个,但不知道会是哪一个,请使用 Locator.or() 创建一个与所有备选项匹配的定位器。

例如,考虑这样一种情况:您想单击“新电子邮件”按钮,但有时会出现安全设置对话框。在这种情况下,您可以等待“新电子邮件”按钮或对话框,然后采取相应措施。

敲黑板!!!注意:

如果屏幕上同时出现“新建电子邮件”按钮和安全对话框,则“或”定位器将匹配它们,从而可能引发“严格模式违规”错误。在这种情况下,您可以使用 Locator.first() 仅匹配其中一个。

Locator newEmail = page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("New"));
Locator dialog
= page.getByText("Confirm security settings");
assertThat(newEmail.or(dialog).first()).isVisible();
if(dialog.isVisible())
page.getByRole(AriaRole.BUTTON,
new Page.GetByRoleOptions().setName("Dismiss")).click();
newEmail.click();

3.4仅匹配可见元素

敲黑板!!!注意:

通常,找到一种更可靠的方法来唯一标识元素,而不是检查可见性。

考虑一个有两个按钮的页面,第一个不可见,第二个可见。

<buttonstyle='display:none'>Invisible</button>
<button>Visible</button>

这将找到两个按钮并抛出严格性违规错误:

page.locator("button").click();

这只会找到第二个按钮,因为它是可见的,然后单击它。

page.locator("button").locator("visible=true").click();

4.列表

4.1对列表中的项目进行计数

可以断言定位器以对列表中的项目进行计数。例如:以下DOM结构

使用count断言确保列表包含 3 个项目。

assertThat(page.getByRole(AriaRole.LISTITEM).hasCount(3);

4.2断言列表中所有文本

可以断言定位器以查找列表中的所有文本。例如:以下DOM结构

使用 assertThat(locator).hasText() 确保列表包含文本“apple”、“banana”和“orange”。

assertThat(page
.getByRole(AriaRole.LISTITEM))
.hasText(
new String[] { "apple", "banana", "orange" });

4.3定位特定项目

有许多方法可以在列表中定位特定项目。

4.3.1通过文本定位

使用 Page.getByText()方法通过文本内容在列表中查找元素,然后单击它。例如:以下DOM结构

通过文本内容找到项目并单击它。

page.getByText("orange").click();
4.3.2通过文本过滤定位

使用 locator.filter() 在列表中查找特定项目。例如:以下DOM结构

按“listitem”的角色找到一个项目,然后按“orange”的文本进行筛选,然后单击它。

page.getByRole(AriaRole.LISTITEM)
.filter(
new Locator.FilterOptions().setHasText("orange"))
.click();
4.3.3通过测试id定位

使用 Page.getByTestId()方法在列表中查找元素。如果您还没有测试 ID,则可能需要修改 html 并添加测试 ID。

通过测试 ID “orange”找到一个项目,然后单击它。

page.getByTestId("orange").click();
4.3.4通过第n项定位

如果您有一个相同元素的列表,并且区分它们的唯一方法是顺序,则可以使用 Locator.first()、Locator.last() 或 Locator.nth() 从列表中选择特定元素。

Locator banana = page.getByRole(AriaRole.LISTITEM).nth(1);

但是,请谨慎使用此方法。通常,页面可能会发生变化,定位器将指向与您预期的完全不同的元素。取而代之的是,尝试提出一个独特的定位器,该定位器将通过严格的标准。

4.4链接过滤器

当您有各种相似性的元素时,可以使用 locator.filter()方法选择正确的元素。您还可以链接多个筛选器以缩小选择范围。

要截取带有“Mary”和“Say goodbye”的行的屏幕截图,请执行以下操作:

Locator rowLocator =page.getByRole(AriaRole.LISTITEM);

rowLocator
.filter(
new Locator.FilterOptions().setHasText("Mary"))
.filter(
newLocator.FilterOptions()
.setHas(page.getByRole(
AriaRole.BUTTON,
new Page.GetByRoleOptions().setName("Say goodbye"))))
.screenshot(
new Page.ScreenshotOptions().setPath("screenshot.png"));

现在,您应该在项目的根目录中有一个“screenshot.png”文件。

4.5罕见例子

4.5.1对列表中每个元素执行某些操作

迭代元素

for(Locator row : page.getByRole(AriaRole.LISTITEM).all())
System.out.println(row.textContent());

使用常规 for 循环进行迭代:

Locator rows =page.getByRole(AriaRole.LISTITEM);int count =rows.count();for (int i = 0; i < count; ++i)
System.out.println(rows.nth(i).textContent());
4.5.2在页面中评估

locator.evaluate_all()中的代码在页面中运行,您可以在那里调用任何 DOM API。

Locator rows =page.getByRole(AriaRole.LISTITEM);
Object texts
=rows.evaluateAll("list => list.map(element => element.textContent)");

5.小结

定位器是非常严格。这意味着,如果多个元素匹配,则对定位器执行暗示某些目标 DOM 元素的所有操作都将引发异常。例如,如果 DOM 中有多个按钮,则会引发以下调用:

如果有多个button,则引发错误

page.getByRole(AriaRole.BUTTON).click();

另一方面,Playwright 了解何时执行多元素操作,因此当定位器解析为多个元素时,以下调用工作正常。

适用于多个元素

page.getByRole(AriaRole.BUTTON).count();

您可以通过 locator.first、locator.last 和 locator.nth() 告诉 Playwright 在多个元素匹配时使用哪个元素来明确选择退出严格性检查。不建议使用这些方法,因为当您的页面更改时,Playwright 可能会单击您不想要的元素。相反,请按照上述最佳实践创建唯一标识目标元素的定位器。

5.1其他定位器

对于不太常用的定位器,请查看官网的
其他定位器
指南。由于时间关系,宏哥就不在这里对其进行展开介绍和讲解了。好了时间不早了,关于元素基础定位方式今天就分享到这里!!!仅供大家学习参考,感谢您耐心的阅读。

经过多组实验对比,对于大实例下仅需恢复几张表数据的情况,有显著优化效果。尤其针对游戏业务等需要频繁回档的场景,将大幅度缩短因数据恢复导致的停服时间。后续我们将逐步在公有云上开放此特性,以惠及更多用户。

本文分享自华为云社区
《【华为云MySQL技术专栏】TaurusDB库表时间点极速恢复》
,作者:GaussDB 数据库。

1.背景介绍

云上客户经常出现误删表、删库等操作。针对这类问题,业界普遍提供库表级恢复方案。首先,在后台将选中时间点的全量数据和增量数据恢复至一个临时实例,然后,自动导出用户需要恢复的表,再将这些表恢复至原实例,以此降低对原实例的影响。

然而,为了确保数据完整性,这一过程通常涉及整个实例的完整恢复,较长的恢复时间导致客户对该方案不甚满意。尤其是当恢复的表数据量远小于整个实例时,如恢复3T实例中仅20M的表,却需先完成整个3T实例的PITR(Point-in-Time Recovery,时间点恢复),再进行表数据的导入导出,不仅效率低下,而且合理性存疑。

针对以上问题,TaurusDB结合自身架构特点,通过优化表级恢复流程,推出表级极速恢复方案,做到恢复时间仅和待恢复表数据量有关,而非整个实例的规模,从而大幅降低RTO,提升服务可用性。

2.原理介绍

2.1多区间分段下载

TaurusDB云原生数据库采用计算与存储分离架构,其备份原理参考官网
https://support.huaweicloud.com/usermanual-gaussdbformysql/gaussdbformysql_03_0052.html

TaurusDB存储的最小管理单元被定义为64MB的plog。在plog上,页面数据以16KB的粒度离散存储。为了实现细粒度的数据恢复,需要基于华为云对象存储服务(OBS)所提供的多RANGE下载能力。

图1 多RANGE仅下载示例

如图1所示,我们将分散在多个plog上的表数据下载下来,再合并成一个新plog,并在log directory中完成位置更新。

2.2 表空间存储映射

TaurusDB在存储侧的管理单元被称为slice,在计算侧由SliceManager模块管理从[tablespace id, pageno]到slice的映射关系,每个slice在逻辑上被分配10G存储空间。

如图2所示,对于tablespace id为8的表,我们仅需要恢复slice1和slice3.

图2 表与slice的映射关系

这组关系会被持久化到文件中,用于重启后的继续查询。当然,备份模块也需要在恢复时更新相关的slice信息,以确保恢复后表映射到新创建的slice上。

2.3 表空间变化记录跟踪

通过上面介绍,我们知道可以根据需要恢复的表tablespace id,识别出需要恢复哪些slice中的对应的plog中的表数据,但实际上客户在使用表级恢复时,通常提供的是表名信息,因此需要了解表名与表tablespace id之间的映射关系。这组映射关系可以通过
INNODB_TABLESPACES
表实时查询,但drop , create , rename等DDL操作会更改表的tablespace id,因此,在实际操作中需要注意这一点。

图3 表tablespace id变化过程

如图3所示,当系统恢复到T2时刻,表A的tablespace id就是12,而T3时刻及之后所识别到drop语句,会直接返回错误,因为当前的时间段及之后无该表存在。

TaurusDB在增加备份过程中,通过额外记录涉及表的tablespace id变更的信息,在做库表级时间点极速恢复时,系统会利用这些记录信息,结合全量备份的表空间信息,得到恢复时间点时刻表名对应的tablespace id。

3. 整体流程解析

表级恢复业务整体流程,如图4所示:

图4 表级恢复业务整体流程

  • 管控Agent下发待恢复表名+时间点,获取到恢复表tablespace id;

  • 全量恢复会根据表tablespace id获取要恢复的slice列表,下发恢复任务到存储侧,恢复指定plog;

  • 启动MysqlD,InnoDB层根据表tablespace id,不在列表的显示为DB_CANNOT_OPEN_FILE,回放增量日志时,跳过非恢复表日志;

  • 利用mydumper和myloader导出导入表。

4. 应用

以某公有云上的某用户使用的2T实例恢复为例,对一张大小为12M的表进行测试,优化前后整体耗时对比,如图5所示:

图5 表级恢复优化前后耗时对比

从图中数据对比可以看出,优化后恢复的数据量从TB降低到MB,整体恢复时间仅为优化前所需时间的21%。

此外,创建实例阶段,通过并行化处理各个子步骤,降低了所需时间。在表导入导出阶段,针对开源mydumper和myloader工具,通过调整相应的策略,显著提升了数据恢复性能,详见https://bbs.huaweicloud.com/blogs/433475

5. 总结

TaurusDB凭借库表时间点极速恢复特性,大幅减少了恢复所需的数据量。经过多组实验对比,对于大实例下仅需恢复几张表数据的情况,有显著优化效果。尤其针对游戏业务等需要频繁回档的场景,将大幅度缩短因数据恢复导致的停服时间。后续我们将逐步在公有云上开放此特性,以惠及更多用户。

华为开发者空间,汇聚鸿蒙、昇腾、鲲鹏、GaussDB、欧拉等各项根技术的开发资源及工具,致力于为每位开发者提供一台云主机、一套开发工具及云上存储空间,让开发者基于华为根生态创新。
点击链接
,免费领取您的专属云主机

点击关注,第一时间了解华为云新鲜技术~

本篇介绍
Manim
中用于
突出显示
某些内容的动画类,主要包括:

  1. ApplyWave
    :让图形或文字产生连续波浪式变形的动画类,用于展示波动效果,参数可调节
  2. Circumscribe
    :用于在几何场景中展示图形与其外接图形的关系,动画围绕对象生成外接图形
  3. Flash
    :通过快速改变对象视觉属性产生闪烁效果,用于强调对象,闪烁参数可自定义
  4. FocusOn
    :能模拟相机聚焦,引导观众关注特定对象,可设置聚焦速度、缩放比例等参数
  5. Indicate
    :以箭头、线条等方式指示对象部分或步骤,自定义指示形状、颜色和动态效果
  6. ShowPassingFlash
    :在对象移动路径上留下短暂闪光,用于体现快速经过的场景,闪光参数可控
  7. Wiggle
    :使对象在原始位置附近小幅度随机晃动,用于模拟不稳定状态,晃动参数能够调整

1. 动画概述

1.1. ApplyWave

ApplyWave
以一种连续、流畅的方式使对象产生波浪式的变形。

可以控制波浪的幅度、频率等参数,通过调整这些参数能够创造出不同强度和风格的波浪效果。

这种变形效果是基于对象的几何形状进行计算的,所以对于复杂形状的对象也能很好地应用,并且能够保证变形过程的平滑性。

它在制作一些具有动态美感的数学函数图像演示或者波动现象(比如物理中的波的传播)时非常有用,

也可以用于文字,使文字产生一种类似在水面上波动的视觉效果,用于一些创意动画的标题展示等场景。

它的主要参数有:

参数名称 类型 说明
mobject Mobject 要进行变形的 Mobject对象
direction np.ndarray 波浪推动形状点的方向
amplitude float 形状点移动的距离
wave_func func 定义一个波峰形状的函数
time_width float 波浪相对于 mobject 宽度的长度
ripples int 波浪的波纹数量

1.2. Circumscribe

Circumscribe
着重于突出对象与其外接图形的关系。

动画过程通常是围绕着目标对象生成外接图形,并且可以设置动画的速度和精度。

在生成外接图形的过程中,会根据对象的几何特征来确定外接图形的位置和大小,以确保准确地表现外接的概念。

它主要用于展示图形与外接图形之间的关系。

比如在讲解三角形的外接圆时,可以使用这个动画效果,清晰地展示圆是如何围绕三角形并通过其三个顶点的。

此外,对于一些有外接几何形状概念的其他图形(如四边形的外接椭圆等)也可以使用,能够直观地帮助观众理解外接这一几何关系。

它的主要参数有:

参数名称 类型 说明
mobject Mobject 要进行环绕绘制的 Mobject对象
shape Type 用于环绕给定 Mobject 的形状,只能是矩形(
Rectangle
)或圆形(
Circle
fade_in bool 是否使环绕形状淡入
fade_out bool 是否使环绕形状淡出
time_width float 绘制和擦除的时间宽度
buff float 环绕形状与给定 Mobject 之间的距离
color Color 环绕形状的颜色

1.3. Flash

Flash
的特点是快速地改变对象的颜色或透明度等视觉属性来产生闪烁效果,

可以自定义闪烁的次数、频率和颜色变化方式。

当需要强调某个对象或者对象的某个部分时
Flash
非常有用。

例如,在展示一个复杂的数学模型中的关键元素,或者在一个化学分子结构中突出特定的原子或化学键时,可以使用
Flash
来吸引观众的注意力。

它的主要参数有:

参数名称 类型 说明
point ndarray / Mobject 闪烁线条的中心点。如果传入的是Mobject,则使用其中心作为中心点
line_length float 闪烁线条的长度
num_lines int 闪烁线条的数量
flash_radius float 闪烁线条开始的距离点
line_stroke_width int 闪烁线条的笔触宽度
color Color 闪烁线条的颜色
time_width float 闪烁线条的时间宽度

1.4. FocusOn

FocusOn
能够模拟相机聚焦的效果,将画面的中心或者重点转移到目标对象上,

可以设置聚焦的速度、缩放比例等参数,使聚焦过程更加自然。

它可用于在复杂的场景或者包含多个对象的动画中,引导观众关注特定的区域或对象。

它的主要参数有:

参数名称 类型 说明
focus_point ndarray / Mobject 聚光灯收缩到的点。如果传入的是Mobject,则使用其中心作为收缩点
opacity float 聚光灯的不透明度
color Color 聚光灯的颜色

1.5. Indicate

Indicate
通常会以箭头、线条或者颜色变化等方式来指示目标,

可以自定义指示的形状、颜色和动态效果(如箭头的摆动、线条的闪烁等)。

这种指示效果是比较明确的,能够直接引导观众的视线到需要关注的地方,并且可以与其他动画效果结合使用,增强指示的效果。

它在教学动画中经常使用,用于指示对象的某个部分或者强调某个操作步骤。

它的主要参数有:

参数名称 类型 说明
mobject Mobject 要突出显示的
Mobject
scale_factor float Mobject 突出显示时缩放的比例因子
color Color Mobject 突出显示的颜色

1.6. ShowPassingFlash

ShowPassingFlash
主要是在对象移动的路径上留下短暂的闪光效果,模拟物体快速通过时的光影变化,

可以控制闪光的颜色、持续时间和强度等参数,以适应不同的场景需求。

它一般用于表现对象的短暂出现或者快速通过的场景。

它的主要参数有:

参数名称 类型 说明
mobject VMobject 要应用此动画效果的对象
time_width float 相对于笔画长度中闪光部分的长度,该参数控制了每一帧中显示的对象部分的大小比例

1.7. Wiggle

Wiggle
能够使对象在其原始位置附近进行小幅度的随机晃动,可以调整晃动的幅度、频率和方向等参数。

晃动效果看起来比较自然,不是那种规则的运动,能够很好地模拟出不稳定或者颤抖的状态,而且不会让对象偏离其原始位置太远,保持了一定的整体稳定性。

它用于给对象添加一种不稳定、轻微晃动的效果。

它的主要参数有:

参数名称 类型 说明
mobject Mobject 要摆动的Mobject对象
scale_value float Mobject 摆动时缩放的比例因子
rotation_angle float 摆动角度
n_wiggles int 摆动次数
scale_about_point ndarray Mobject 缩放的中心点
rotate_about_point ndarray Mobject 旋转的中心点

2. 使用示例

下面通过示例来演示各个突出显示类动画的使用。

2.1. ApplyWave 示例

首先创建一个文本对象
Text
,然后分别演示
ApplyWave
不同参数的设置效果。

  1. 第一次使用默认参数,展示基本的波浪变形效果
  2. 第二次指定了方向为向右(
    RIGHT
    )、时间宽度为 0.5、振幅为 0.3,观察这些参数对动画的影响
  3. 第三次设置了速率函数为线性(
    linear
    )和波纹数量为 4,查看线性速率和波纹数量下的效果。
  4. 第四次设置了速率函数为非线性(
    rush_into
    )和波纹数量为 4,查看非线性速率和波纹数量下的效果
# 创建一个文本对象
t = Text("Hello, Manim!").scale(1.5)
self.add(t)

# 默认参数的ApplyWave
self.play(ApplyWave(t))
self.wait()

# 指定方向 时间宽度和振幅的ApplyWave
self.play(
    ApplyWave(
        t,
        direction=RIGHT,
        time_width=0.5,
        amplitude=0.3,
    ),
)
self.wait()

# 线性波纹
self.play(
    ApplyWave(
        t,
        rate_func=linear,
        ripples=4,
    ),
)
self.wait()

# 非线性波纹
self.play(
    ApplyWave(
        t,
        wave_func=rush_into,
        ripples=4,
    ),
)

2.2. Circumscribe 示例

首先创建一个
矩形
,然后针对
矩形
分别演示了
Circumscribe
的不同参数设置效果。

比如默认参数、指定形状为圆形、淡入、淡出、以及
Circumscribe
与矩形的间隔
buff
等等。

# 创建一个矩形
rect = Rectangle(width=3, height=2)
self.add(rect)

# 默认参数的Circumscribe
self.play(Circumscribe(rect))
self.wait()

# 指定形状为圆形的Circumscribe
self.play(Circumscribe(rect, Circle))
self.wait()

# 淡入效果
self.play(
    Circumscribe(
        rect,
        fade_in=True,
        buff=0.1,
        color=RED,
    )
)
self.wait()

# 淡出效果
self.play(
    Circumscribe(
        rect,
        fade_out=True,
        buff=0.3,
        color=GREEN,
    )
)

2.3. Flash 示例

首先创建一个

和一个

,然后针对



分别演示了
Flash
的不同参数设置效果。

对于

,展示了默认参数的
Flash
效果;

对于

,依次展示了指定
线条长度

数量

颜色

起始半径

线条宽度

时间宽度
、和
速率函数
等参数的效果。

# 创建一个点和一个圆
dot = Dot().shift(UP * 2)
circle = Circle(radius=1)
self.add(dot, circle)

# 默认参数Flash
self.play(Flash(dot))
self.wait()

# 指定线条长度 数量和颜色的Flash
self.play(
    Flash(
        circle,
        line_length=0.5,
        num_lines=20,
        color=YELLOW,
    )
)
self.wait()

# 指定起始半径和线宽度的Flash
self.play(
    Flash(
        circle,
        line_stroke_width=5,
        flash_radius=1.5,
    )
)
self.wait()

# 指定速率函数的Flash
self.play(
    Flash(
        circle,
        rate_func=rush_into,
        time_width=2,
    )
)

2.4. FocusOn 示例

首先创建一个
正方形
,然后针对
正方形
分别演示了
FocusOn
的不同参数设置效果。

除了默认参数,还展示指定
不透明度
和指定
颜色
的效果。

# 创建一个正方形和一个三角形
square = Square()
self.add(square)

# 默认参数的FocusOn
self.play(FocusOn(square))
self.wait()

# 指定不透明度的FocusOn
self.play(FocusOn(square, opacity=0.8))
self.wait()

# 指定颜色的FocusOn
self.play(FocusOn(square, color=RED))

2.5. Indicate 示例

首先创建一个
文本对象
和一个
圆形
,然后针对
文本

圆形
分别演示
Indicate
的不同参数设置效果。

比如指定
缩放比例
因子、指定
颜色
,以及指定
速率函数
的效果。

# 创建一个文本对象和一个圆形
text = Text("Indicate Me!").shift(UP * 2)
circle = Circle(radius=1)
self.add(text, circle)

# 默认参数的Indicate
self.play(Indicate(text), Indicate(circle))
self.wait()

# 指定缩放比例因子的Indicate
self.play(
    Indicate(text, scale_factor=1.5),
    Indicate(circle, scale_factor=1.5),
)
self.wait()

# 指定颜色的Indicate
self.play(
    Indicate(text, color=GREEN),
    Indicate(circle, color=BLUE),
)
self.wait()

# 不同速率函数的Indicate
self.play(
    Indicate(text, rate_func=there_and_back),
    Indicate(circle, rate_func=there_and_back_with_pause),
)

2.6. ShowPassingFlash 示例

先创建一个
正五边形
,然后演示
ShowPassingFlash
在不同
time_width
下的效果。

# 创建一个多边形作为示例图形
p = RegularPolygon(n=5, color=GRAY).scale(2)
self.add(p)

colors = [RED, BLUE, GREEN]
time_widths = [0.5, 1, 2]

# 不同time_width参数的效果
for idx, tw in enumerate(time_widths):
    self.play(
        ShowPassingFlash(
            p.copy().set_color(colors[idx]),
            time_width=tw,
            run_time=2,
        )
    )
    self.wait()

2.7. Wiggle 示例

首先创建了一个
文本对象
和一个
矩形
,然后分别演示
Wiggle

默认参数

scale_value
参数,
rotation_angle
参数,
n_wiggles
参数以及
scale_about_point

rotate_about_point
参数的使用效果。

# 创建一个文本对象和一个矩形作为示例图形
t = Text("Wiggle Example").shift(UP)
r = Rectangle(width=2, height=1).shift(DOWN)
self.add(t, r)

# 默认参数下的Wiggle
self.play(Wiggle(t), Wiggle(r))
self.wait()

# 指定scale_value参数
self.play(
    Wiggle(t, scale_value=1.3),
    Wiggle(r, scale_value=1.5),
)
self.wait()

# 指定rotation_angle参数
self.play(
    Wiggle(t, rotation_angle=np.pi / 4),
    Wiggle(r, rotation_angle=np.pi / 3),
)
self.wait()

# 指定n_wiggles参数
self.play(
    Wiggle(t, n_wiggles=4),
    Wiggle(r, n_wiggles=8),
)
self.wait()

# 指定scale_about_point和rotate_about_point参数
self.play(
    Wiggle(
        r,
        scale_about_point=r.get_center(),
        rotate_about_point=r.get_corner(UR),
    )
)

3. 附件

文中的代码只是关键部分的截取,完整的代码共享在网盘中(
indication.py
),

下载地址:
完整代码
(访问密码: 6872)