mirror of
https://github.com/exyte/Macaw.git
synced 2024-09-11 13:15:35 +03:00
Buildable example
This commit is contained in:
parent
0a54ff615c
commit
0c471cfc09
@ -180,7 +180,7 @@ class DiagramExampleView: MacawView {
|
|||||||
|
|
||||||
var groupContents = [Node]()
|
var groupContents = [Node]()
|
||||||
groupContents.append(baseRect)
|
groupContents.append(baseRect)
|
||||||
groupContents.appendContentsOf(lines)
|
groupContents.append(contentsOf: lines)
|
||||||
groupContents.append(blueLineShape)
|
groupContents.append(blueLineShape)
|
||||||
groupContents.append(redLineShape)
|
groupContents.append(redLineShape)
|
||||||
groupContents.append(outerCircleShape)
|
groupContents.append(outerCircleShape)
|
||||||
|
@ -63,50 +63,50 @@ class PathExampleView: MacawView {
|
|||||||
|
|
||||||
let cloud2Shape = Shape(
|
let cloud2Shape = Shape(
|
||||||
form: cloud2(),
|
form: cloud2(),
|
||||||
place: Transform.scale(sx: 1.5, sy: 1.5).move(dx: 0, dy: -100),
|
|
||||||
fill: Color(val: 0x60636e),
|
fill: Color(val: 0x60636e),
|
||||||
stroke: Stroke(
|
stroke: Stroke(
|
||||||
fill: Color(val: 0x7e8087),
|
fill: Color(val: 0x7e8087),
|
||||||
width: 2,
|
width: 2,
|
||||||
cap: .round,
|
cap: .round,
|
||||||
join: .round
|
join: .round
|
||||||
)
|
),
|
||||||
|
place: Transform.scale(sx: 1.5, sy: 1.5).move(dx: 0, dy: -100)
|
||||||
)
|
)
|
||||||
|
|
||||||
let lightningShape = Shape(
|
let lightningShape = Shape(
|
||||||
form: lightning(),
|
form: lightning(),
|
||||||
place: Transform.move(dx: 375, dy: 390).scale(sx: 3, sy: 3),
|
|
||||||
fill: LinearGradient(
|
fill: LinearGradient(
|
||||||
stops: [
|
y2: 1,
|
||||||
Stop(offset: 0, color: Color.rgb(r: 250, g: 220, b: 0)),
|
stops: [
|
||||||
Stop(offset: 1, color: Color(val: 0xeb6405))
|
Stop(offset: 0, color: Color.rgb(r: 250, g: 220, b: 0)),
|
||||||
],
|
Stop(offset: 1, color: Color(val: 0xeb6405))
|
||||||
y2: 1
|
]
|
||||||
)
|
),
|
||||||
|
place: Transform.move(dx: 375, dy: 390).scale(sx: 3, sy: 3)
|
||||||
)
|
)
|
||||||
|
|
||||||
let cloud1Shape = Shape(
|
let cloud1Shape = Shape(
|
||||||
form: cloud1(),
|
form: cloud1(),
|
||||||
place: .move(dx: 120, dy: 120),
|
|
||||||
fill: LinearGradient(
|
fill: LinearGradient(
|
||||||
stops: [
|
y2: 1,
|
||||||
Stop(offset: 0, color: Color(val: 0x2f3036)),
|
stops: [
|
||||||
Stop(offset: 1, color: Color.rgba(r: 47, g: 48, b: 54, a: 0.1))
|
Stop(offset: 0, color: Color(val: 0x2f3036)),
|
||||||
],
|
Stop(offset: 1, color: Color.rgba(r: 47, g: 48, b: 54, a: 0.1))
|
||||||
y2: 1
|
]
|
||||||
)
|
),
|
||||||
|
place: .move(dx: 120, dy: 120)
|
||||||
)
|
)
|
||||||
|
|
||||||
let cloud1Shape2 = Shape(
|
let cloud1Shape2 = Shape(
|
||||||
form: cloud1(),
|
form: cloud1(),
|
||||||
place: .move(dx: 120, dy: 100),
|
|
||||||
fill: Color(val: 0x7b808c),
|
fill: Color(val: 0x7b808c),
|
||||||
stroke: Stroke(
|
stroke: Stroke(
|
||||||
fill: Color(val: 0xaaacb3),
|
fill: Color(val: 0xaaacb3),
|
||||||
width: 1,
|
width: 1,
|
||||||
cap: .round,
|
cap: .round,
|
||||||
join: .round
|
join: .round
|
||||||
)
|
),
|
||||||
|
place: .move(dx: 120, dy: 100)
|
||||||
)
|
)
|
||||||
|
|
||||||
return Group(
|
return Group(
|
||||||
|
@ -74,7 +74,7 @@ class ShapesExampleView: MacawView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fileprivate static func newText(_ text: String, _ place: Transform, baseline: Baseline = .bottom) -> Text {
|
fileprivate static func newText(_ text: String, _ place: Transform, baseline: Baseline = .bottom) -> Text {
|
||||||
return Text(text: text, fill: Color.black, baseline: baseline, align: .mid, place: place)
|
return Text(text: text, fill: Color.black, align: .mid, baseline: baseline, place: place)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ internal class TransformAnimation: AnimationImpl<Transform> {
|
|||||||
self.init(animatedNode: animatedNode, valueFunc: interpolationFunc, animationDuration: animationDuration, delay: delay, autostart: autostart, fps: fps)
|
self.init(animatedNode: animatedNode, valueFunc: interpolationFunc, animationDuration: animationDuration, delay: delay, autostart: autostart, fps: fps)
|
||||||
}
|
}
|
||||||
|
|
||||||
init(animatedNode: Node, valueFunc: (Double) -> Transform, animationDuration: Double, delay: Double = 0.0, autostart: Bool = false, fps: UInt = 30) {
|
init(animatedNode: Node, valueFunc: @escaping (Double) -> Transform, animationDuration: Double, delay: Double = 0.0, autostart: Bool = false, fps: UInt = 30) {
|
||||||
super.init(observableValue: animatedNode.placeVar, valueFunc: valueFunc, animationDuration: animationDuration, delay: delay, fps: fps)
|
super.init(observableValue: animatedNode.placeVar, valueFunc: valueFunc, animationDuration: animationDuration, delay: delay, fps: fps)
|
||||||
type = .affineTransformation
|
type = .affineTransformation
|
||||||
node = animatedNode
|
node = animatedNode
|
||||||
@ -21,7 +21,7 @@ internal class TransformAnimation: AnimationImpl<Transform> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init(animatedNode: Node, factory: ((Node) -> ((Double) -> Transform)), animationDuration: Double, delay: Double = 0.0, autostart: Bool = false, fps: UInt = 30) {
|
init(animatedNode: Node, factory: @escaping ((Node) -> ((Double) -> Transform)), animationDuration: Double, delay: Double = 0.0, autostart: Bool = false, fps: UInt = 30) {
|
||||||
super.init(observableValue: animatedNode.placeVar, factory: factory, animationDuration: animationDuration, delay: delay, fps: fps)
|
super.init(observableValue: animatedNode.placeVar, factory: factory, animationDuration: animationDuration, delay: delay, fps: fps)
|
||||||
type = .affineTransformation
|
type = .affineTransformation
|
||||||
node = animatedNode
|
node = animatedNode
|
||||||
@ -75,7 +75,7 @@ public extension AnimatableVariable where T: TransformInterpolation {
|
|||||||
return TransformAnimation(animatedNode: self.node!, factory: factory, animationDuration: during, delay: delay)
|
return TransformAnimation(animatedNode: self.node!, factory: factory, animationDuration: during, delay: delay)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func animation(_ f: (Double) -> Transform, during: Double, delay: Double = 0.0) -> Animation {
|
public func animation(_ f: @escaping (Double) -> Transform, during: Double, delay: Double = 0.0) -> Animation {
|
||||||
return TransformAnimation(animatedNode: node!, valueFunc: f, animationDuration: during, delay: delay)
|
return TransformAnimation(animatedNode: node!, valueFunc: f, animationDuration: during, delay: delay)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ extension ObservableArray: Indexable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func index(after i: Int) -> Int {
|
public func index(after i: Int) -> Int {
|
||||||
elements.index(after: i)
|
return elements.index(after: i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,13 +159,13 @@ extension ObservableArray: RangeReplaceableCollection {
|
|||||||
public mutating func replaceSubrange<C : Collection>(_ subRange: Range<Int>, with newCollection: C) where C.Iterator.Element == Element {
|
public mutating func replaceSubrange<C : Collection>(_ subRange: Range<Int>, with newCollection: C) where C.Iterator.Element == Element {
|
||||||
let oldCount = elements.count
|
let oldCount = elements.count
|
||||||
elements.replaceSubrange(subRange, with: newCollection)
|
elements.replaceSubrange(subRange, with: newCollection)
|
||||||
guard let first = subRange.first else {
|
// guard let first = subRange.first else {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
let newCount = elements.count
|
// let newCount = elements.count
|
||||||
let end = first + (newCount - oldCount) + subRange.count
|
// let end = first + (newCount - oldCount) + subRange.count
|
||||||
arrayDidChange(ArrayChangeEvent(inserted: Array(first..<end),
|
// arrayDidChange(ArrayChangeEvent(inserted: Array(first..<end),
|
||||||
deleted: Array(subRange)))
|
// deleted: Array(subRange)))
|
||||||
}
|
}
|
||||||
|
|
||||||
public mutating func popLast() -> Element? {
|
public mutating func popLast() -> Element? {
|
||||||
@ -210,11 +210,11 @@ extension ObservableArray: Collection {
|
|||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
elements[bounds] = newValue
|
elements[bounds] = newValue
|
||||||
guard let first = bounds.first else {
|
// guard let first = bounds.first else {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
arrayDidChange(ArrayChangeEvent(inserted: Array(first..<first + newValue.count),
|
// arrayDidChange(ArrayChangeEvent(inserted: Array(first..<first + newValue.count),
|
||||||
deleted: Array(bounds)))
|
// deleted: Array(bounds)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ class RenderUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class func mapDash(_ dashes: [Double]) -> UnsafeMutablePointer<CGFloat> {
|
class func mapDash(_ dashes: [Double]) -> UnsafeMutablePointer<CGFloat> {
|
||||||
let p = UnsafeMutablePointer<CGFloat>(calloc(dashes.count, sizeof(CGFloat)))
|
let p = UnsafeMutablePointer<CGFloat>.allocate(capacity:dashes.count * MemoryLayout<CGFloat>.size)
|
||||||
for (index, item) in dashes.enumerated() {
|
for (index, item) in dashes.enumerated() {
|
||||||
p[index] = CGFloat(item)
|
p[index] = CGFloat(item)
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ class ShapeRenderer: NodeRenderer {
|
|||||||
let path = CGMutablePath()
|
let path = CGMutablePath()
|
||||||
var t = CGAffineTransform(translationX: CGFloat(ellipse.cx), y: CGFloat(ellipse.cy))
|
var t = CGAffineTransform(translationX: CGFloat(ellipse.cx), y: CGFloat(ellipse.cy))
|
||||||
t = CGAffineTransform(scaleX: 1.0, y: scale).concatenating(t);
|
t = CGAffineTransform(scaleX: 1.0, y: scale).concatenating(t);
|
||||||
CGPathAddArc(path, &t, 0, 0, r, startAngle, endAngle, false)
|
path.addArc(center: CGPoint.zero, radius: r, startAngle: startAngle, endAngle: endAngle, clockwise: false, transform: t)
|
||||||
ctx.addPath(path)
|
ctx.addPath(path)
|
||||||
}
|
}
|
||||||
} else if let point = locus as? Point {
|
} else if let point = locus as? Point {
|
||||||
@ -488,9 +488,12 @@ class ShapeRenderer: NodeRenderer {
|
|||||||
ctx!.setLineCap(RenderUtils.mapLineCap(stroke.cap))
|
ctx!.setLineCap(RenderUtils.mapLineCap(stroke.cap))
|
||||||
let dashes = stroke.dashes
|
let dashes = stroke.dashes
|
||||||
if !dashes.isEmpty {
|
if !dashes.isEmpty {
|
||||||
let dashPointer = RenderUtils.mapDash(dashes)
|
var floatDashes = [CGFloat]()
|
||||||
CGContextSetLineDash(ctx!, 0, dashPointer, dashes.count)
|
dashes.forEach { dash in
|
||||||
dashPointer.deallocateCapacity(dashes.count)
|
floatDashes.append(CGFloat(dash))
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx?.setLineDash(phase: 0.0, lengths: floatDashes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,9 +284,10 @@ open class SVGParser {
|
|||||||
fileprivate func getStyleAttributes(_ groupAttributes: [String: String], element: XMLElement) -> [String: String] {
|
fileprivate func getStyleAttributes(_ groupAttributes: [String: String], element: XMLElement) -> [String: String] {
|
||||||
var styleAttributes: [String: String] = groupAttributes
|
var styleAttributes: [String: String] = groupAttributes
|
||||||
if let style = element.attributes["style"] {
|
if let style = element.attributes["style"] {
|
||||||
let styleParts = style.stringByReplacingOccurrencesOfString(" ", withString: "").componentsSeparatedByString(";")
|
|
||||||
|
let styleParts = style.replacingOccurrences(of: " ", with: "").components(separatedBy: ";")
|
||||||
styleParts.forEach { styleAttribute in
|
styleParts.forEach { styleAttribute in
|
||||||
let currentStyle = styleAttribute.componentsSeparatedByString(":")
|
let currentStyle = styleAttribute.components(separatedBy: ":")
|
||||||
if currentStyle.count == 2 {
|
if currentStyle.count == 2 {
|
||||||
styleAttributes.updateValue(currentStyle[1], forKey: currentStyle[0])
|
styleAttributes.updateValue(currentStyle[1], forKey: currentStyle[0])
|
||||||
}
|
}
|
||||||
@ -416,9 +417,9 @@ open class SVGParser {
|
|||||||
fileprivate func getStrokeDashes(_ styleParts: [String: String]) -> [Double] {
|
fileprivate func getStrokeDashes(_ styleParts: [String: String]) -> [Double] {
|
||||||
var dashes = [Double]()
|
var dashes = [Double]()
|
||||||
if let strokeDashes = styleParts["stroke-dasharray"] {
|
if let strokeDashes = styleParts["stroke-dasharray"] {
|
||||||
let characterSet = NSMutableCharacterSet()
|
var characterSet = CharacterSet()
|
||||||
characterSet.addCharacters(in: " ")
|
characterSet.insert(" ")
|
||||||
characterSet.addCharacters(in: ",")
|
characterSet.insert(",")
|
||||||
let separatedValues = strokeDashes.components(separatedBy: characterSet)
|
let separatedValues = strokeDashes.components(separatedBy: characterSet)
|
||||||
separatedValues.forEach { value in
|
separatedValues.forEach { value in
|
||||||
if let doubleValue = Double(value) {
|
if let doubleValue = Double(value) {
|
||||||
@ -671,7 +672,7 @@ open class SVGParser {
|
|||||||
}
|
}
|
||||||
var id = link
|
var id = link
|
||||||
if id.hasPrefix("#") {
|
if id.hasPrefix("#") {
|
||||||
id = id.stringByReplacingOccurrencesOfString("#", withString: "")
|
id = id.replacingOccurrences(of: "#", with: "")
|
||||||
}
|
}
|
||||||
guard let referenceNode = self.defNodes[id], let node = copyNode(referenceNode) else {
|
guard let referenceNode = self.defNodes[id], let node = copyNode(referenceNode) else {
|
||||||
return .none
|
return .none
|
||||||
@ -701,10 +702,10 @@ open class SVGParser {
|
|||||||
return .none
|
return .none
|
||||||
}
|
}
|
||||||
var parentGradient: LinearGradient?
|
var parentGradient: LinearGradient?
|
||||||
if let link = element.attributes["xlink:href"]?.stringByReplacingOccurrencesOfString(" ", withString: "")
|
if let link = element.attributes["xlink:href"]?.replacingOccurrences(of: " ", with: "")
|
||||||
, link.hasPrefix("#") {
|
, link.hasPrefix("#") {
|
||||||
|
|
||||||
let id = link.stringByReplacingOccurrencesOfString("#", withString: "")
|
let id = link.replacingOccurrences(of: "#", with: "")
|
||||||
parentGradient = defFills[id] as? LinearGradient
|
parentGradient = defFills[id] as? LinearGradient
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -746,10 +747,10 @@ open class SVGParser {
|
|||||||
return .none
|
return .none
|
||||||
}
|
}
|
||||||
var parentGradient: RadialGradient?
|
var parentGradient: RadialGradient?
|
||||||
if let link = element.attributes["xlink:href"]?.stringByReplacingOccurrencesOfString(" ", withString: "")
|
if let link = element.attributes["xlink:href"]?.replacingOccurrences(of: " ", with: "")
|
||||||
, link.hasPrefix("#") {
|
, link.hasPrefix("#") {
|
||||||
|
|
||||||
let id = link.stringByReplacingOccurrencesOfString("#", withString: "")
|
let id = link.replacingOccurrences(of: "#", with: "")
|
||||||
parentGradient = defFills[id] as? RadialGradient
|
parentGradient = defFills[id] as? RadialGradient
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -802,10 +803,10 @@ open class SVGParser {
|
|||||||
return .none
|
return .none
|
||||||
}
|
}
|
||||||
|
|
||||||
var offset = getDoubleValueFromPercentage(element, attribute: "offset")
|
guard var offset = getDoubleValueFromPercentage(element, attribute: "offset") else {
|
||||||
guard let _ = offset else {
|
|
||||||
return .none
|
return .none
|
||||||
}
|
}
|
||||||
|
|
||||||
if offset < 0 {
|
if offset < 0 {
|
||||||
offset = 0
|
offset = 0
|
||||||
} else if offset > 1 {
|
} else if offset > 1 {
|
||||||
@ -817,11 +818,10 @@ open class SVGParser {
|
|||||||
}
|
}
|
||||||
var color = Color.black
|
var color = Color.black
|
||||||
if let stopColor = getStyleAttributes([:], element: element)["stop-color"] {
|
if let stopColor = getStyleAttributes([:], element: element)["stop-color"] {
|
||||||
color = createColor(stopColor
|
color = createColor(stopColor.replacingOccurrences(of: " ", with: ""), opacity: opacity)
|
||||||
.stringByReplacingOccurrencesOfString(" ", withString: ""), opacity: opacity)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Stop(offset: offset!, color: color)
|
return Stop(offset: offset, color: color)
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func parsePath(_ path: XMLIndexer) -> Path? {
|
fileprivate func parsePath(_ path: XMLIndexer) -> Path? {
|
||||||
@ -885,9 +885,9 @@ open class SVGParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func parseCommand(_ command: PathCommand) -> PathSegment? {
|
fileprivate func parseCommand(_ command: PathCommand) -> PathSegment? {
|
||||||
let characterSet = NSMutableCharacterSet()
|
var characterSet = CharacterSet()
|
||||||
characterSet.addCharacters(in: " ")
|
characterSet.insert(" ")
|
||||||
characterSet.addCharacters(in: ",")
|
characterSet.insert(",")
|
||||||
let commandParams = command.expression.components(separatedBy: characterSet)
|
let commandParams = command.expression.components(separatedBy: characterSet)
|
||||||
var separatedValues = [String]()
|
var separatedValues = [String]()
|
||||||
commandParams.forEach { param in
|
commandParams.forEach { param in
|
||||||
@ -1123,10 +1123,10 @@ open class SVGParser {
|
|||||||
guard let attributeValue = element.attributes[attribute] else {
|
guard let attributeValue = element.attributes[attribute] else {
|
||||||
return .none
|
return .none
|
||||||
}
|
}
|
||||||
if !attributeValue.containsString("%") {
|
if !attributeValue.contains("%") {
|
||||||
return self.getDoubleValue(element, attribute: attribute)
|
return self.getDoubleValue(element, attribute: attribute)
|
||||||
} else {
|
} else {
|
||||||
let value = attributeValue.stringByReplacingOccurrencesOfString("%", withString: "")
|
let value = attributeValue.replacingOccurrences(of: "%", with: "")
|
||||||
if let doubleValue = Double(value) {
|
if let doubleValue = Double(value) {
|
||||||
return doubleValue / 100
|
return doubleValue / 100
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user