// // GraphicUtils.swift // VoidLink // // Created by True砖家 on 2025/12/24. // Copyright © 2025 True砖家@Bilibili. All rights reserved. // import Foundation import SVGKit @objc public class GraphicUtils: NSObject { @objc public static func makeSVGLayer( from file: String, in container: CALayer, at normalizedPosition: CGPoint = .zero, targetSize: CGSize ) -> CALayer { guard let url = Bundle.main.url(forResource: file, withExtension: "svg"), let data = try? Data(contentsOf: url) else { return CALayer() } guard let svg = SVGKImage(data: data) else { fatalError("Failed to load SVG \(file)") } return _makeSVGLayer( from: svg, in: container, at: normalizedPosition, targetSize: targetSize ) } public static func makeCenteredSVGLayer( from svg: SVGKImage, in container: CALayer, targetSize: CGSize ) -> CALayer { return _makeSVGLayer( from: svg, in: container, targetSize: targetSize ) } @objc public static func _makeSVGLayer( from svg: SVGKImage, in container: CALayer, at normalizedPosition: CGPoint = .zero, targetSize: CGSize, getWrapperLayer: Bool = true ) -> CALayer { let svgLayer = svg.caLayerTree! svgLayer.transform = CATransform3DIdentity var unionRect = CGRect.null func accumulateBounds(_ layer: CALayer) { unionRect = unionRect.union(layer.frame) layer.sublayers?.forEach { accumulateBounds($0) } } accumulateBounds(svgLayer) svgLayer.setAffineTransform( CGAffineTransform( translationX: -unionRect.origin.x, y: -unionRect.origin.y ) ) let realPosition = (normalizedPosition == .zero ? CGPoint(x: container.bounds.midX,y: container.bounds.midY) : CGPoint(x: container.bounds.width*normalizedPosition.x,y: container.bounds.height*normalizedPosition.y)) let wrapper = CALayer() wrapper.bounds = CGRect(origin: .zero, size: unionRect.size) wrapper.anchorPoint = CGPoint(x: 0.5, y: 0.5) wrapper.position = realPosition let scale = min( targetSize.width / unionRect.width, targetSize.height / unionRect.height ) wrapper.setAffineTransform( CGAffineTransform(scaleX: scale, y: scale) ) wrapper.addSublayer(svgLayer) if !getWrapperLayer { return wrapper } let wrappedLayer = CALayer() wrappedLayer.anchorPoint = CGPoint(x: 0.5, y: 0.5) wrappedLayer.bounds = CGRect(x: 0, y: 0, width: container.bounds.size.width, height: container.bounds.size.height) wrappedLayer.position = CGPoint(x: container.bounds.midX, y: container.bounds.midY) wrappedLayer.insertSublayer(wrapper, at: 0) return wrappedLayer } @objc public static func changeColor(layer: CALayer, color: UIColor) { if let shape = layer as? CAShapeLayer { shape.fillColor = color.cgColor shape.strokeColor = color.cgColor } layer.sublayers?.forEach { changeColor(layer: $0, color: color) } } @objc public static func makeTouchTrackpoint(in view:UIView) -> CAShapeLayer { var trackPoint = CAShapeLayer() let path = UIBezierPath( arcCenter: CGPoint(x: 0, y: 0), radius: GenericUtils.isIPhone() ? 12 : 15, startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true ) trackPoint = CAShapeLayer() trackPoint.path = path.cgPath trackPoint.fillColor = UIColor.white.withAlphaComponent(0.3).cgColor trackPoint.strokeColor = UIColor.clear.cgColor trackPoint.lineWidth = 0 view.layer.addSublayer(trackPoint) trackPoint.position = view.center trackPoint.isHidden = true return trackPoint } }