Skip to content

Commit

Permalink
Merge pull request #18 from chenhaiteng/develop
Browse files Browse the repository at this point in the history
Merge for release
  • Loading branch information
chenhaiteng authored May 13, 2021
2 parents 4c5c9af + b79d86e commit 1d5894e
Show file tree
Hide file tree
Showing 18 changed files with 1,340 additions and 14 deletions.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2021 Chen-Hai Teng

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
17 changes: 15 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,37 @@ import PackageDescription

let package = Package(
name: "Rings",
platforms: [.macOS(.v10_15), .iOS(.v13), .tvOS(.v13), .watchOS(.v6)],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "CommonExts",
targets: ["CommonExts"]),
.library(
name: "Rings",
targets: ["Rings"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
.package(name: "CoreGraphicsExtension", url: "https://github.com/chenhaiteng/CoreGraphicsExtension.git", from: "0.2.0"),
.package(name: "ArchimedeanSpiral", url: "https://github.com/chenhaiteng/ArchimedeanSpiral.git", from: "1.0.12")
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(name: "CommonExts",
dependencies: []),
.target(
name: "Rings",
dependencies: []),
dependencies: ["CoreGraphicsExtension", "CommonExts", "ArchimedeanSpiral"],
exclude: ["RingText.md",
"ClockIndex.md",
"ArchimedeanSpiralText.md",
"HandAiguille.md"]),
.testTarget(
name: "RingsTests",
dependencies: ["Rings"]),
dependencies: ["Rings",
"CoreGraphicsExtension", "CommonExts"]),
]
)
83 changes: 81 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,82 @@
# Rings
# Rings ![GitHub](https://img.shields.io/github/license/chenhaiteng/Rings?style=plastic) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/chenhaiteng/rings)

A description of this package.
**Rings** is a collection of controls which have similar shapes of ring, circle...

It includes following controls, click to see what it looks like:

* **[RingText](#ringtext)**
* **[ClockIndex](#clockindex)**
* **[HandAiguille](#handaiguille)**
* **[ArchimedeanSpiralText](#archimedeanspiraltext)**

and following functions are in progress:
* SphericText
* Knob

---
## Installation:
### Install with Swift Package Manager
#### - Add to Xcode:

1. File > Swift Packages > Add Package Dependency...
2. Choose Project you want to add Rings
3. Paste repository https://github.com/chenhaiteng/Rings.git
4. Rules > Version: Up to Next Major 0.1.0
It's can also apply Rules > Branch : main to access latest code.
If you want try some experimental features, you can also apply Rules > Branch : develop

**Note:** It might need to link Rings to your target maunally.

1. Open *Project Editor* by tap on root of project navigator
2. Choose the target you want to use Rings.
3. Choose **Build Phases**, and expand **Link Binary With Libraries**
4. Tap on **+** button, and choose Rings to add it.

#### - Add to SPM package:
```swift
dependencies: [
.package(name: "Rings", url: "https://github.com/chenhaiteng/Rings.git", from: "0.1.0")
// To specify branch, use following statement to instead of.
// .package(name: "Rings", url: "https://github.com/chenhaiteng/Rings.git", .branch("branch_name"))
],
targets: [
.target(
name: "MyPackage",
dependencies: ["Rings"]),
]
```
---

## RingText

### What it looks like
![RingDemo](https://user-images.githubusercontent.com/1284944/115984682-fb26a700-a5da-11eb-8a59-a1554ec41bdf.gif)

### ![How to use it](Sources/Rings/RingText.md)

## ClockIndex

### What it looks like
![ClockIndex Demo Classic](https://user-images.githubusercontent.com/1284944/116664495-26d6d200-a9cb-11eb-906c-7ffe659dcfbc.gif)

<img width="598" alt="earchly_clock_demo" src="https://user-images.githubusercontent.com/1284944/116664737-73baa880-a9cb-11eb-97e1-afcb49dfcfcd.png">

### ![How to use it](Sources/Rings/ClockIndex.md)

## HandAiguille

### What it looks like:
![HandAguille](https://user-images.githubusercontent.com/1284944/118101511-47128200-b40a-11eb-870f-90ac2f2a302a.gif)

### ![How to use it](Sources/Rings/HandAiguille.md)

## ArchimedeanSpiralText

### What it looks like:
![ArchimedeanSpiralTextDemo](https://user-images.githubusercontent.com/1284944/117950922-3ef10e80-b346-11eb-9da1-50b0f87990a2.gif)

### ![How to use it](Sources/Rings/ArchimedeanSpiralText.md)

---
# License
Rings is released under the [MIT License](LICENSE).
15 changes: 15 additions & 0 deletions Sources/CommonExts/CollectionExts.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// CollectionExts.swift
//
// Refer to https://stackoverflow.com/a/37225027/505763
// Created by Chen Hai Teng on 4/22/21.
//

import Foundation

public extension Collection where Indices.Iterator.Element == Index {
subscript (safe index: Index) -> Iterator.Element? {
return indices.contains(index) ? self[index] : nil
}
}

19 changes: 19 additions & 0 deletions Sources/CommonExts/ViewExts.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// ViewExts.swift
//
// Refer to https://stackoverflow.com/a/57685253/505763
// Created by Chen Hai Teng on 4/22/21.
//

import SwiftUI

public extension View {
@ViewBuilder
func `if`<Content: View>(_ conditional: Bool, content: (Self)->Content) -> some View {
if(conditional) {
content(self)
} else {
self
}
}
}
120 changes: 120 additions & 0 deletions Sources/Rings/ArchimedeanSpiralPath.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
//
// ArchimedeanSpiralPath.swift
// Rings
//
// Created by Chen Hai Teng on 3/5/21.
//

import SwiftUI
import ArchimedeanSpiral
import CoreGraphicsExtension

public struct ArchimedeanSpiralPath: View {
var radiusSpacing: Double
var innerRadius: Double
var gap: Double
var ptCount: Int
var spiralDesc :ArchimedeanSpiral
var startAngle: CGAngle = CGAngle.zero

private lazy var points: [CGPoint] = spiralDesc.equidistantPoints(start: startAngle, num: ptCount).map { polar in
polar.cgpoint
}

init(_ innerRadius: Double = 12.0, spacing: Double = 10.0, gap: Double = 5.0, count: Int = 100) {
self.radiusSpacing = spacing
self.innerRadius = innerRadius
self.gap = gap
self.ptCount = count
spiralDesc = ArchimedeanSpiral(innerRadius: self.innerRadius, radiusSpacing: self.radiusSpacing, spacing: self.gap)

}

func getPoints()-> [CGPoint] {
var mutateSelf = self
return mutateSelf.points
}

public var body: some View {
GeometryReader { geo in
Path { path in
let midX = geo.size.width/2
let midY = geo.size.height/2
path.move(to: CGPoint(
x: midX,
y: midY
))
getPoints().forEach { pt in
let next = CGPoint(x: pt.x + midX, y: pt.y + midY)
path.addLine(to: next)
}
}.stroke(Color.red)
}
}
}

extension ArchimedeanSpiralPath : Adjustable {
func start(_ angle: CGAngle) -> Self {
setProperty { tmp in
tmp.startAngle = angle
}
}
}

struct ArchimedeanSpiralPathDemo : View {
@State var radiusSpacing: Double = 10.0
@State var innerR: Double = 5.0
@State var spacing: Double = 25.0
@State var count: Double = 100.0
@State var startAt: Double = 0.0
@State var showInner: Bool = false
@State var showRadius: Bool = false
var body: some View {
VStack {
ZStack {
GeometryReader { geo in
let midX = geo.size.width/2
let midY = geo.size.height/2
ArchimedeanSpiralPath(innerR, spacing: radiusSpacing, gap: spacing, count: Int(count)).start(CGAngle.degrees(startAt))
Group {
if (showInner) {
Path { p in
p.move(to: CGPoint(x: midX, y: midY))
p.addLine(to: CGPoint(x: midX + CGFloat(innerR), y: midY))
}.stroke(style: StrokeStyle(lineWidth: 2.0, lineCap: .butt, lineJoin: .miter, miterLimit: 0, dash: [3,1], dashPhase: 0))
}
if(showRadius) {
Path { p in
p.move(to: CGPoint(x: midX + CGFloat(innerR), y: midY))
p.addLine(to: CGPoint(x: midX + CGFloat(innerR) + CGFloat(radiusSpacing), y: midY))
}.stroke(Color.blue, style: StrokeStyle(lineWidth: 2.0, lineCap: .butt, lineJoin: .miter, miterLimit: 0, dash: [3,1], dashPhase: 0))
}
}
}
}
Slider(value: $startAt, in: 0.0...360.0) {
Text("start at (\(startAt))")
}.padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10))
Slider(value: $radiusSpacing, in: 10.0...50.0) {
Toggle("", isOn: $showRadius)
Text("radius spacing (\(radiusSpacing))")
}.padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10))
Slider(value: $innerR, in: 10.0...50.0) {
Toggle("", isOn: $showInner)
Text("inner radius(\(innerR))")
}.padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10))
Slider(value: $spacing, in: 10.0...50.0) {
Text("points spacing(\(spacing))")
}.padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10))
Slider(value: $count, in: 100.0...200.0, step: 10.0) {
Text("count(\(Int(count)))")
}.padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10))
}
}
}

struct SwiftUIView_Previews: PreviewProvider {
static var previews: some View {
ArchimedeanSpiralPathDemo()
}
}
24 changes: 24 additions & 0 deletions Sources/Rings/ArchimedeanSpiralText.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# ArchimedeanSpiralText

## Preview:

![ArchimedeanSpiralTextDemo](https://user-images.githubusercontent.com/1284944/117950922-3ef10e80-b346-11eb-9da1-50b0f87990a2.gif)

### Usage:
```swift
// Create text along archimedean spiral
ArchimedeanSpiralText("My Archimedean Spiral")

// Setup Archimedean Spiral parameters
ArchimedeanSpiralText("My Archimedean Spiral")
.gap(10.0) // To setup the distance between two calculated points.
.innerRadius(15.0) // To specify the start radius of an archimedean spiral
.spacing(radiusSpacing) // To adjust the constant separation distance between intersection points measured from the origin.

// Update the text appearance
ArchimedeanSpiralText()
.text("My Archimedean Spiral") // Modifing text content
.textDirection(direction) // Specifing the direction of text.
.textColor(color) // Change text color
.font(font) // Change font and text size
```
Loading

0 comments on commit 1d5894e

Please sign in to comment.