javaFx清空缓存动画特效

package com.excellent.archimedes.fx.controller;

/**

* @author zhaoyong

* @Date 2024/10/12

* @Description

*/

import com.alibaba.fastjson.JSON;

import com.excellent.archimedes.util.AlertUtils;

import com.excellent.archimedes.util.UIViewContextUtils;

import javafx.animation.*;

import javafx.event.ActionEvent;

import javafx.fxml.FXML;

import javafx.fxml.Initializable;

import javafx.geometry.Point2D;

import javafx.scene.canvas.Canvas;

import javafx.scene.canvas.GraphicsContext;

import javafx.scene.control.Button;

import javafx.scene.layout.Pane;

import javafx.scene.paint.Color;

import javafx.util.Duration;

import org.apache.commons.lang3.StringUtils;

import org.springframework.stereotype.Component;

import java.net.URL;

import java.util.ArrayList;

import java.util.List;

import java.util.ResourceBundle;

@Component

public class SeeCacheController implements Initializable {

/* ===================== 以下为原控件 ===================== */

@FXML private Pane userPane;

@FXML private Button reset;

@FXML private Button returnHomepage;

/* ===================== 新增动画节点 ===================== */

private Canvas animCanvas; // 360°圆环+碎片

private GraphicsContext gc;

private final double RING_RADIUS = 80; // 圆环半径

private final double RING_STROKE = 6; // 圆环粗细

private final int FRAG_COUNT = 12; // 碎片数量

private final List<Fragment> fragments = new ArrayList<>();

@Override

public void initialize(URL location, ResourceBundle resources) {

/* 把 Canvas 放到原 Pane 里,居中 */

animCanvas = new Canvas(300, 300);

userPane.getChildren().add(animCanvas);

animCanvas.setLayoutX(20); // 自己按实际布局微调

animCanvas.setLayoutY(30);

gc = animCanvas.getGraphicsContext2D();

}

/* ===================== 原业务方法不动 ===================== */

@FXML void returnHome(ActionEvent event) { UIViewContextUtils.subStage.close(); }

@FXML void returnToHome(ActionEvent event) { UIViewContextUtils.subStage.hide(); }

@FXML

void checkCache(ActionEvent event) {

try {

String cacheContent = JSON.toJSONString(UIViewContextUtils.subStage.getUserData());

if (StringUtils.isNotBlank(cacheContent) && !cacheContent.equals("null")) {

AlertUtils.alert("查看缓存", cacheContent);

} else {

AlertUtils.alert("查看缓存", "缓存已清空");

}

} catch (Exception e) {

e.printStackTrace();

}

}

/* ===================== 清空缓存 + 360°特效 ===================== */

@FXML

void clearCache(ActionEvent event) {

boolean go = AlertUtils.prompt("要清空缓存", "确定要清空缓存吗?");

if (!go) return;

initFragments(); // 生成 12 片扇形碎片

Timeline master = new Timeline(new KeyFrame(Duration.millis(16), e -> drawFrame())); // 60 fps

master.setCycleCount(Timeline.INDEFINITE);

master.play();

/* 3 秒后结束动画并真正清理 */

PauseTransition end = new PauseTransition(Duration.seconds(3));

end.setOnFinished(e -> {

master.stop();

fragments.clear();

gc.clearRect(0, 0, animCanvas.getWidth(), animCanvas.getHeight());

UIViewContextUtils.thirdSubStage.setUserData(null);

UIViewContextUtils.subStage.setUserData(null);

UIViewContextUtils.primaryStage.setUserData(null);

AlertUtils.alert("清空缓存", "缓存已清空完毕");

});

end.play();

}

/* ===================== 碎片内部类 ===================== */

private static class Fragment {

double startAngle; // 初始角度

double distance; // 当前已飞出距离

double speed; // 每帧飞出速度

double opacity; // 当前透明度

final double MAX_DIST = 120;

Fragment(double angle) {

this.startAngle = angle;

this.distance = 0;

this.speed = 2 + Math.random() * 2;

this.opacity = 1.0;

}

void fly() {

distance += speed;

opacity = Math.max(0, 1 - distance / MAX_DIST);

}

}

private void initFragments() {

fragments.clear();

for (int i = 0; i < FRAG_COUNT; i++) {

fragments.add(new Fragment(i * 360.0 / FRAG_COUNT));

}

}

/* ===================== 每帧绘制 ===================== */

private double ringAngle = 0;

private void drawFrame() {

gc.clearRect(0, 0, animCanvas.getWidth(), animCanvas.getHeight());

double cx = animCanvas.getWidth() / 2;

double cy = animCanvas.getHeight() / 2;

/* 1. 旋转圆环 */

ringAngle += 4;

gc.save();

gc.translate(cx, cy);

gc.rotate(ringAngle);

gc.setStroke(Color.rgb(30, 144, 255));

gc.setLineWidth(RING_STROKE);

gc.strokeOval(-RING_RADIUS, -RING_RADIUS, RING_RADIUS * 2, RING_RADIUS * 2);

/* 画 60 条刻度 */

for (int i = 0; i < 60; i++) {

double a = Math.toRadians(i * 6);

double len = (i % 5 == 0) ? 10 : 5;

gc.strokeLine(RING_RADIUS - len, 0, RING_RADIUS, 0);

gc.rotate(6);

}

gc.restore();

/* 2. 碎片向外飞 */

gc.setFill(Color.ORANGE);

fragments.removeIf(f -> f.opacity <= 0);

for (Fragment f : fragments) {

double rad = Math.toRadians(f.startAngle);

Point2D p = new Point2D(

cx + Math.cos(rad) * (RING_RADIUS * 0.7 + f.distance),

cy + Math.sin(rad) * (RING_RADIUS * 0.7 + f.distance));

gc.setGlobalAlpha(f.opacity);

gc.fillOval(p.getX() - 4, p.getY() - 4, 8, 8);

f.fly();

}

gc.setGlobalAlpha(1.0);

}

}

相关推荐
Y38153266232 分钟前
SERP API + Redis 缓存层:4 种方案对比与选型
数据库·redis·缓存
海兰3 小时前
【高速缓存】RedisVL 高级查询(全文搜索、混合搜索和 多向量搜索)
数据库·人工智能·redis·缓存
流星白龙16 小时前
【Redis】4.基本全局命令
数据库·redis·缓存
流星白龙19 小时前
【Redis】3.Redis安装与命令行客户端
数据库·redis·缓存
我不想名字重复1 天前
redis缓存和数据库数据保持一致
数据库·redis·缓存
时空无限1 天前
vllm 大模型启动缓存相关环境变量 export
linux·缓存·vllm
流星白龙1 天前
【Redis】6.计数其他命令
数据库·redis·缓存
正儿八经的少年1 天前
redis 的大 key 和热 key 详解
数据库·redis·缓存
X-⃢_⃢-X1 天前
十、Redis之布隆过滤器
数据库·redis·缓存
Database_Cool_1 天前
阿里云 Tair(企业级内存数据库)vs 腾讯云 Redis 云缓存深度对比:性能/数据结构/成本全维度 Benchmark
数据库·阿里云·缓存