如何在 SwiftUI 中制作节点动画?

How to make an animation of Nodes in SwiftUI?

我正在尝试为 SwiftUI 制作这样的节点动画 --> https://oguzhaneroglu.com/projects/nodes.js/

那个 link 有我正在转换的源代码(实际上是一个小文件)。

我感到困惑的部分是,这个功能在 SwiftUI 中的等价物是什么?

 window[window.addEventListener ? 'addEventListener': 'attachEvent']
    (window.addEventListener ? 'load': 'onload', function () {

我假设该函数中的内容会导致动画循环。 任何人都可以就如何做到这一点给我任何建议吗?

The part I am confused on is, what is the equivalent in SwiftUI for this function?

window[window.addEventListener ? 'addEventListener': 'attachEvent']
    (window.addEventListener ? 'load': 'onload', function () {

实际上这相当于根视图上的 .onAppear 修饰符,所以如果原始 JS 代码在 function() 中激活动画,那么在 SwiftUI 中我们会像

那样做
struct ContentView: View {
    
    var body: some View {
       VStack {            // << any view or container
          // ... other subviews
       }
       .onAppear(perform: function)
    }

    func function() {
        // ... any needed manipulations
    }
}

对于我的问题,这必须在 Swift 中完成。如果这对您来说不是一个严格的要求,那么您可以这样做。

  1. 将其放入 node.html 文件中。
<!DOCTYPE html>
<html>
<body>
    <script type="text/javascript" src="nodes.js"></script>
    <script type="text/javascript">
        var nodesjs = new NodesJs({
            id: 'nodes',
            width: window.innerWidth,
            height: window.innerHeight,
            particleSize: 4,
            lineSize: 2,
            particleColor: [85, 85, 121],
            lineColor: [255, 255, 255],
            backgroundDuration: 4000,
            number: window.hasOwnProperty('orientation') ? 30: 100,
            speed: 15
        });
    </script>
    <div style="position: absolute; left: 0px; top: 0px; overflow: hidden; width: 100%; height: 100%;">
        <canvas id="nodes"></canvas>
    </div>
</body>
</html>
  1. 将其放入 node.js 文件
var NodesJs = (function (parameters) {
    t_NodesJs = this;
    t_NodesJs.id = parameters.id;
    t_NodesJs.width = parameters.width;
    t_NodesJs.height = parameters.height;
    t_NodesJs.particleSize = parameters.particleSize ? parameters.particleSize: 2;
    t_NodesJs.lineSize = parameters.lineSize ? parameters.lineSize: 1;
    t_NodesJs.particleColor = parameters.particleColor ? 'rgba('+parameters.particleColor.join(',')+')': 'rgba(255,255,255,0.3)';
    t_NodesJs.lineColor = parameters.lineColor ? parameters.lineColor: '255,255,255';
    t_NodesJs.number = parameters.number ? parameters.number: 100;
    t_NodesJs.speed = parameters.speed ? parameters.speed: 20;

    var canvas;
    var ctx;
    var cw;
    var ch;

    var t0 = Date.now();
    var dt = 0;

    t_NodesJs.nodes = [];

    t_NodesJs.setWidth = function (width) {
        canvas.width = width;
        cw = width;
    };

    t_NodesJs.setHeight = function (height) {
        canvas.height = height;
        ch = height;
    };

    t_NodesJs.placeNodes = function (number) {
        t_NodesJs.nodes = [];

        for (var i=0; i < number; i++) {
            t_NodesJs.nodes.push([
                Math.floor(Math.random() * (cw - 0 + 1)) + 0,
                Math.floor(Math.random() * (ch - 0 + 1)) + 0,
                Math.random() * (Math.PI * 2 - 0 + 1) + 0,
                []
            ]);
        }
    };

    var isPositive = function (num) {
        return num >= 0;
    };

    var isNetagive = function (num) {
        return num <= -1;
    };

    window[window.addEventListener ? 'addEventListener': 'attachEvent']
    (window.addEventListener ? 'load': 'onload', function () {
        canvas = document.getElementById(t_NodesJs.id);
        ctx = canvas.getContext('2d');

        canvas.width = t_NodesJs.width;
        canvas.height = t_NodesJs.height;

        cw = canvas.width;
        ch = canvas.height;

        t_NodesJs.placeNodes(t_NodesJs.number);

        var step = function () {
            window.requestAnimationFrame(step);

            ctx.clearRect(0, 0, cw, ch);
            
            // Fill the background
            ctx.beginPath();
            ctx.fillStyle = 'rgb('+0+', '+0+', '+46+')';
            ctx.fillRect(0, 0, cw, ch);
            ctx.fill();
            
            t_NodesJs.nodes.forEach(function (_node, _node_i) {
                _node[0] += Math.cos(_node[2]) * t_NodesJs.speed * (dt/1000.0);
                _node[1] += Math.sin(_node[2]) * t_NodesJs.speed * (dt/1000.0);

                if (_node[0] < 0) {
                    _node[0] = cw + (_node[0] % cw);
                }

                if (_node[0] > cw) {
                    _node[0] = _node[0] % cw;
                }

                if (_node[1] < 0) {
                    _node[1] = ch + (_node[1] % ch);
                }

                if (_node[1] > ch) {
                    _node[1] = _node[1] % ch;
                }

                ctx.fillStyle = t_NodesJs.particleColor;

                ctx.beginPath();
                ctx.arc(
                    _node[0],
                    _node[1],
                    t_NodesJs.particleSize,
                    0,
                    Math.PI * 2,
                    true
                );
                ctx.fill();

                _node[3] = [];

                t_NodesJs.nodes.forEach(function (_node2, _node2_i) {
                    if (_node_i == _node2_i) {
                        return true;
                    }

                    if (_node[3].indexOf(_node2_i) > -1) {
                        return true;
                    }

                    var dx = Math.abs(_node[0] - _node2[0]);
                    var dy = Math.abs(_node[1] - _node2[1]);
                    var d = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));

                    var alpha = 0;

                    if (d <= 300) {
                        alpha = 0.3 - ((0.3 * d) / 200);
                    }

                    if (alpha == 0) {
                        return true;
                    }

                    _node2[3].push(_node_i);

                    ctx.strokeStyle = 'rgba('+t_NodesJs.lineColor+','+alpha+')';
                    ctx.lineWidth = t_NodesJs.lineSize;

                    ctx.beginPath();
                    ctx.moveTo(_node[0], _node[1]);
                    ctx.lineTo(_node2[0], _node2[1]);
                    ctx.stroke();
                });
            });

            dt = Date.now() - t0;
            t0 = Date.now();
        };

        step();
    });
});
  1. 将这 2 个文件添加到您的项目中,然后创建名为 WebView.swift
  2. 的第三个文件
import SwiftUI
import WebKit

struct WebView : UIViewRepresentable {
    func makeUIView(context: Context) -> WKWebView  {
        return WKWebView()
    }
    
    func updateUIView(_ uiView: WKWebView, context: Context) {
        let url = Bundle.main.url(forResource: "node", withExtension: "html")!
        uiView.loadFileURL(url, allowingReadAccessTo: url)
        let request = URLRequest(url: url)
        uiView.load(request)
    }
    
}

最后,将 WebView 添加到您在 iOS 应用中需要的任何视图。您现在可以在不了解 javascript.

的情况下制作任何 html 动画的奇特动画

让我知道这是否适合你。