mirror of
https://github.com/exyte/Macaw.git
synced 2024-09-21 01:47:44 +03:00
82 lines
2.6 KiB
Swift
82 lines
2.6 KiB
Swift
|
|
enum SVGLength {
|
|
case percent(Double)
|
|
case pixels(Double)
|
|
|
|
init(percent: Double) {
|
|
self = .percent(percent)
|
|
}
|
|
|
|
init(pixels: Double) {
|
|
self = .pixels(pixels)
|
|
}
|
|
}
|
|
|
|
class SVGSize {
|
|
let width: SVGLength
|
|
let height: SVGLength
|
|
|
|
public init(width: SVGLength, height: SVGLength) {
|
|
self.width = width
|
|
self.height = height
|
|
}
|
|
}
|
|
|
|
public protocol NodeLayout {
|
|
|
|
func layout(node: Node, in rect: Rect)
|
|
}
|
|
|
|
class SVGNodeLayout: NodeLayout {
|
|
|
|
let svgSize: SVGSize?
|
|
let viewBox: Rect?
|
|
let scalingMode: AspectRatio
|
|
let xAligningMode: Align
|
|
let yAligningMode: Align
|
|
|
|
init(svgSize: SVGSize? = .none, viewBox: Rect? = .none, scalingMode: AspectRatio? = .meet, xAligningMode: Align? = .mid, yAligningMode: Align? = .mid) {
|
|
self.svgSize = svgSize
|
|
self.viewBox = viewBox
|
|
self.scalingMode = scalingMode ?? .meet
|
|
self.xAligningMode = xAligningMode ?? .mid
|
|
self.yAligningMode = yAligningMode ?? .mid
|
|
}
|
|
|
|
func layout(node: Node, in rect: Rect) {
|
|
|
|
guard let size = svgSize else { return }
|
|
let width = svgLengthToPixels(size.width, framePixels: rect.w)
|
|
let height = svgLengthToPixels(size.height, framePixels: rect.h)
|
|
let svgSizeInPixels = Size(w: width, h: height)
|
|
|
|
if let viewBox = self.viewBox {
|
|
node.clip = viewBox
|
|
}
|
|
let viewBox = self.viewBox ?? Rect(x: 0, y: 0, w: svgSizeInPixels.w, h: svgSizeInPixels.h)
|
|
|
|
if scalingMode === AspectRatio.slice {
|
|
// setup new clipping to slice extra bits
|
|
let newSize = AspectRatio.meet.fit(size: svgSizeInPixels, into: viewBox)
|
|
let newX = viewBox.x + xAligningMode.align(outer: viewBox.w, inner: newSize.w)
|
|
let newY = viewBox.y + yAligningMode.align(outer: viewBox.h, inner: newSize.h)
|
|
node.clip = Rect(x: newX, y: newY, w: newSize.w, h: newSize.h)
|
|
}
|
|
|
|
let contentLayout = SVGContentLayout(scalingMode: scalingMode, xAligningMode: xAligningMode, yAligningMode: yAligningMode)
|
|
node.place = contentLayout.layout(rect: viewBox, into: Rect(x: 0, y: 0, w: svgSizeInPixels.w, h: svgSizeInPixels.h))
|
|
|
|
// move to (0, 0)
|
|
node.place = node.place.move(dx: -viewBox.x, dy: -viewBox.y)
|
|
}
|
|
}
|
|
|
|
fileprivate func svgLengthToPixels(_ svgLength: SVGLength, framePixels: Double) -> Double {
|
|
switch(svgLength) {
|
|
case let .percent(percent):
|
|
return framePixels * percent / 100.0
|
|
case let .pixels(pixels):
|
|
return pixels
|
|
}
|
|
}
|