├── .gitattributes
├── .github
└── FUNDING.yml
├── ChartJS Demo
├── ChartJS Demo
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── AccentColor.colorset
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── ChartJS_DemoApp.swift
│ ├── ChartJS_Demo.entitlements
│ ├── Charts
│ │ ├── Polar.swift
│ │ ├── Pie.swift
│ │ ├── Line.swift
│ │ └── Bar.swift
│ └── ContentView.swift
├── ChartJS Demo.xcodeproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── project.pbxproj
├── ChartJS DemoTests
│ └── ChartJS_DemoTests.swift
└── ChartJS DemoUITests
│ ├── ChartJS_DemoUITestsLaunchTests.swift
│ └── ChartJS_DemoUITests.swift
├── Tests
└── ChartJSTests
│ └── ChartJSTests.swift
├── Package.swift
├── LICENSE
├── .gitignore
├── README
├── README.zh-CN.md
├── README.zh-TW.md
├── README.zh-HK.md
├── README.ja.md
└── README.es.md
├── README.md
└── Sources
└── ChartJS
└── ChartJS.swift
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: 1998code
4 |
--------------------------------------------------------------------------------
/ChartJS Demo/ChartJS Demo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Tests/ChartJSTests/ChartJSTests.swift:
--------------------------------------------------------------------------------
1 | import Testing
2 | @testable import ChartJS
3 |
4 | @Test func example() async throws {
5 | // Write your test here and use APIs like `#expect(...)` to check expected conditions.
6 | }
7 |
--------------------------------------------------------------------------------
/ChartJS Demo/ChartJS Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ChartJS Demo/ChartJS Demo/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/ChartJS Demo/ChartJS Demo/ChartJS_DemoApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartJS_DemoApp.swift
3 | // ChartJS Demo
4 | //
5 | // Created by Ming on 21/5/2025.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @main
11 | struct ChartJS_DemoApp: App {
12 | var body: some Scene {
13 | WindowGroup {
14 | Text("Demo")
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/ChartJS Demo/ChartJS DemoTests/ChartJS_DemoTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartJS_DemoTests.swift
3 | // ChartJS DemoTests
4 | //
5 | // Created by Ming on 21/5/2025.
6 | //
7 |
8 | import Testing
9 |
10 | struct ChartJS_DemoTests {
11 |
12 | @Test func example() async throws {
13 | // Write your test here and use APIs like `#expect(...)` to check expected conditions.
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/ChartJS Demo/ChartJS Demo/ChartJS_Demo.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-only
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ChartJS Demo/ChartJS DemoUITests/ChartJS_DemoUITestsLaunchTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartJS_DemoUITestsLaunchTests.swift
3 | // ChartJS DemoUITests
4 | //
5 | // Created by Ming on 21/5/2025.
6 | //
7 |
8 | import XCTest
9 |
10 | final class ChartJS_DemoUITestsLaunchTests: XCTestCase {
11 |
12 | override class var runsForEachTargetApplicationUIConfiguration: Bool {
13 | true
14 | }
15 |
16 | override func setUpWithError() throws {
17 | continueAfterFailure = false
18 | }
19 |
20 | @MainActor
21 | func testLaunch() throws {
22 | let app = XCUIApplication()
23 | app.launch()
24 |
25 | // Insert steps here to perform after app launch but before taking a screenshot,
26 | // such as logging into a test account or navigating somewhere in the app
27 |
28 | let attachment = XCTAttachment(screenshot: app.screenshot())
29 | attachment.name = "Launch Screen"
30 | attachment.lifetime = .keepAlways
31 | add(attachment)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 5.9
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "ChartJS",
8 | platforms: [
9 | .iOS(.v13),
10 | // .macOS(.v10_15), .tvOS(.v13), .watchOS(.v6)
11 | ],
12 | products: [
13 | // Products define the executables and libraries a package produces, making them visible to other packages.
14 | .library(
15 | name: "ChartJS",
16 | targets: ["ChartJS"]),
17 | ],
18 | targets: [
19 | // Targets are the basic building blocks of a package, defining a module or a test suite.
20 | // Targets can depend on other targets in this package and products from dependencies.
21 | .target(
22 | name: "ChartJS",
23 | resources: [
24 | .process("Resources")
25 | ]),
26 | // .testTarget(
27 | // name: "ChartJSTests",
28 | // dependencies: ["ChartJS"]
29 | // ),
30 | ]
31 | )
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 MING
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/ChartJS Demo/ChartJS DemoUITests/ChartJS_DemoUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartJS_DemoUITests.swift
3 | // ChartJS DemoUITests
4 | //
5 | // Created by Ming on 21/5/2025.
6 | //
7 |
8 | import XCTest
9 |
10 | final class ChartJS_DemoUITests: XCTestCase {
11 |
12 | override func setUpWithError() throws {
13 | // Put setup code here. This method is called before the invocation of each test method in the class.
14 |
15 | // In UI tests it is usually best to stop immediately when a failure occurs.
16 | continueAfterFailure = false
17 |
18 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
19 | }
20 |
21 | override func tearDownWithError() throws {
22 | // Put teardown code here. This method is called after the invocation of each test method in the class.
23 | }
24 |
25 | @MainActor
26 | func testExample() throws {
27 | // UI tests must launch the application that they test.
28 | let app = XCUIApplication()
29 | app.launch()
30 |
31 | // Use XCTAssert and related functions to verify your tests produce the correct results.
32 | }
33 |
34 | @MainActor
35 | func testLaunchPerformance() throws {
36 | // This measures how long it takes to launch your application.
37 | measure(metrics: [XCTApplicationLaunchMetric()]) {
38 | XCUIApplication().launch()
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/ChartJS Demo/ChartJS Demo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "platform" : "ios",
6 | "size" : "1024x1024"
7 | },
8 | {
9 | "appearances" : [
10 | {
11 | "appearance" : "luminosity",
12 | "value" : "dark"
13 | }
14 | ],
15 | "idiom" : "universal",
16 | "platform" : "ios",
17 | "size" : "1024x1024"
18 | },
19 | {
20 | "appearances" : [
21 | {
22 | "appearance" : "luminosity",
23 | "value" : "tinted"
24 | }
25 | ],
26 | "idiom" : "universal",
27 | "platform" : "ios",
28 | "size" : "1024x1024"
29 | },
30 | {
31 | "idiom" : "mac",
32 | "scale" : "1x",
33 | "size" : "16x16"
34 | },
35 | {
36 | "idiom" : "mac",
37 | "scale" : "2x",
38 | "size" : "16x16"
39 | },
40 | {
41 | "idiom" : "mac",
42 | "scale" : "1x",
43 | "size" : "32x32"
44 | },
45 | {
46 | "idiom" : "mac",
47 | "scale" : "2x",
48 | "size" : "32x32"
49 | },
50 | {
51 | "idiom" : "mac",
52 | "scale" : "1x",
53 | "size" : "128x128"
54 | },
55 | {
56 | "idiom" : "mac",
57 | "scale" : "2x",
58 | "size" : "128x128"
59 | },
60 | {
61 | "idiom" : "mac",
62 | "scale" : "1x",
63 | "size" : "256x256"
64 | },
65 | {
66 | "idiom" : "mac",
67 | "scale" : "2x",
68 | "size" : "256x256"
69 | },
70 | {
71 | "idiom" : "mac",
72 | "scale" : "1x",
73 | "size" : "512x512"
74 | },
75 | {
76 | "idiom" : "mac",
77 | "scale" : "2x",
78 | "size" : "512x512"
79 | }
80 | ],
81 | "info" : {
82 | "author" : "xcode",
83 | "version" : 1
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/ChartJS Demo/ChartJS Demo/Charts/Polar.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Polar.swift
3 | // ChartJS
4 | //
5 | // Created by Ming on 21/5/2025.
6 | //
7 |
8 | import SwiftUI
9 | import ChartJS
10 |
11 | #Preview("Polar Area Chart") {
12 | let dataJson = """
13 | {
14 | "labels": ["Red", "Orange", "Yellow", "Green", "Blue"],
15 | "datasets": [
16 | {
17 | "label": "Dataset 1",
18 | "data": [65, 59, 80, 81, 56],
19 | "backgroundColor": [
20 | "rgba(255, 99, 132, 0.5)",
21 | "rgba(255, 159, 64, 0.5)",
22 | "rgba(255, 205, 86, 0.5)",
23 | "rgba(75, 192, 192, 0.5)",
24 | "rgba(54, 162, 235, 0.5)"
25 | ]
26 | }
27 | ]
28 | }
29 | """
30 |
31 | let configJson = """
32 | {
33 | "type": "polarArea",
34 | "options": {
35 | "responsive": true,
36 | "scales": {
37 | "r": {
38 | "pointLabels": {
39 | "display": true,
40 | "centerPointLabels": true,
41 | "font": {
42 | "size": 18
43 | }
44 | }
45 | }
46 | },
47 | "plugins": {
48 | "legend": {
49 | "position": "top"
50 | },
51 | "title": {
52 | "display": true,
53 | "text": "Chart.js Polar Area Chart With Centered Point Labels"
54 | }
55 | }
56 | }
57 | }
58 | """
59 |
60 | return GeometryReader { geometry in
61 | Charts(dataJson: dataJson, configJson: configJson)
62 | .frame(height: geometry.size.width > geometry.size.height ?
63 | geometry.size.height : // landscape
64 | geometry.size.height * 0.5) // portrait
65 | .padding()
66 | .frame(maxWidth: .infinity, maxHeight: .infinity)
67 | .position(x: geometry.size.width/2, y: geometry.size.height/2)
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## User settings
6 | xcuserdata/
7 |
8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
9 | *.xcscmblueprint
10 | *.xccheckout
11 |
12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
13 | build/
14 | DerivedData/
15 | *.moved-aside
16 | *.pbxuser
17 | !default.pbxuser
18 | *.mode1v3
19 | !default.mode1v3
20 | *.mode2v3
21 | !default.mode2v3
22 | *.perspectivev3
23 | !default.perspectivev3
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 |
28 | ## App packaging
29 | *.ipa
30 | *.dSYM.zip
31 | *.dSYM
32 |
33 | ## Playgrounds
34 | timeline.xctimeline
35 | playground.xcworkspace
36 |
37 | # Swift Package Manager
38 | #
39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
40 | # Packages/
41 | # Package.pins
42 | # Package.resolved
43 | # *.xcodeproj
44 | #
45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
46 | # hence it is not needed unless you have added a package configuration file to your project
47 | # .swiftpm
48 |
49 | .build/
50 |
51 | # CocoaPods
52 | #
53 | # We recommend against adding the Pods directory to your .gitignore. However
54 | # you should judge for yourself, the pros and cons are mentioned at:
55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
56 | #
57 | # Pods/
58 | #
59 | # Add this line if you want to avoid checking in source code from the Xcode workspace
60 | # *.xcworkspace
61 |
62 | # Carthage
63 | #
64 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
65 | # Carthage/Checkouts
66 |
67 | Carthage/Build/
68 |
69 | # Accio dependency management
70 | Dependencies/
71 | .accio/
72 |
73 | # fastlane
74 | #
75 | # It is recommended to not store the screenshots in the git repo.
76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
77 | # For more information about the recommended setup visit:
78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
79 |
80 | fastlane/report.xml
81 | fastlane/Preview.html
82 | fastlane/screenshots/**/*.png
83 | fastlane/test_output
84 |
85 | # Code Injection
86 | #
87 | # After new code Injection tools there's a generated folder /iOSInjectionProject
88 | # https://github.com/johnno1962/injectionforxcode
89 |
90 | iOSInjectionProject/
91 |
--------------------------------------------------------------------------------
/ChartJS Demo/ChartJS Demo/Charts/Pie.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Pie.swift
3 | // ChartJS
4 | //
5 | // Created by Ming on 21/5/2025.
6 | //
7 |
8 | import SwiftUI
9 | import ChartJS
10 |
11 | #Preview("Pie Chart") {
12 | let dataJson = """
13 | {
14 | "labels": ["Red", "Orange", "Yellow", "Green", "Blue"],
15 | "datasets": [
16 | {
17 | "label": "Dataset 1",
18 | "data": [65, 59, 80, 81, 56],
19 | "backgroundColor": [
20 | "rgb(255, 99, 132)",
21 | "rgb(255, 159, 64)",
22 | "rgb(255, 205, 86)",
23 | "rgb(75, 192, 192)",
24 | "rgb(54, 162, 235)"
25 | ]
26 | }
27 | ]
28 | }
29 | """
30 |
31 | let configJson = """
32 | {
33 | "type": "pie",
34 | "options": {
35 | "responsive": true,
36 | "plugins": {
37 | "legend": {
38 | "position": "top"
39 | },
40 | "title": {
41 | "display": true,
42 | "text": "Chart.js Pie Chart"
43 | }
44 | }
45 | }
46 | }
47 | """
48 |
49 | return GeometryReader { geometry in
50 | Charts(dataJson: dataJson, configJson: configJson)
51 | .frame(height: geometry.size.width > geometry.size.height ?
52 | geometry.size.height : // landscape
53 | geometry.size.height * 0.3) // portrait
54 | .padding()
55 | .frame(maxWidth: .infinity, maxHeight: .infinity)
56 | .position(x: geometry.size.width/2, y: geometry.size.height/2)
57 | }
58 | }
59 |
60 | #Preview("Doughnut Chart") {
61 | let dataJson = """
62 | {
63 | "labels": ["Red", "Orange", "Yellow", "Green", "Blue"],
64 | "datasets": [
65 | {
66 | "label": "Dataset 1",
67 | "data": [65, 59, 80, 81, 56],
68 | "backgroundColor": [
69 | "rgb(255, 99, 132)",
70 | "rgb(255, 159, 64)",
71 | "rgb(255, 205, 86)",
72 | "rgb(75, 192, 192)",
73 | "rgb(54, 162, 235)"
74 | ]
75 | }
76 | ]
77 | }
78 | """
79 |
80 | let configJson = """
81 | {
82 | "type": "doughnut",
83 | "options": {
84 | "responsive": true,
85 | "plugins": {
86 | "legend": {
87 | "position": "top"
88 | },
89 | "title": {
90 | "display": true,
91 | "text": "Chart.js Doughnut Chart"
92 | }
93 | }
94 | }
95 | }
96 | """
97 |
98 | return GeometryReader { geometry in
99 | Charts(dataJson: dataJson, configJson: configJson)
100 | .frame(height: geometry.size.width > geometry.size.height ?
101 | geometry.size.height : // landscape
102 | geometry.size.height * 0.3) // portrait
103 | .padding()
104 | .frame(maxWidth: .infinity, maxHeight: .infinity)
105 | .position(x: geometry.size.width/2, y: geometry.size.height/2)
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/ChartJS Demo/ChartJS Demo/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // ChartJS Demo
4 | //
5 | // Created by Ming on 21/5/2025.
6 | //
7 |
8 | import SwiftUI
9 | import ChartJS
10 |
11 | #Preview("Simple Chart") {
12 | // Use the entire view for the chart
13 | let dataJson = """
14 | {
15 | "labels": ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
16 | "datasets": [{
17 | "label": "Data",
18 | "data": [12, 19, 3, 5, 2, 3],
19 | "backgroundColor": "rgba(75, 192, 192, 0.2)",
20 | "borderColor": "rgba(75, 192, 192, 1)",
21 | "borderWidth": 1
22 | }]
23 | }
24 | """
25 |
26 | let configJson = """
27 | {
28 | "type": "bar",
29 | "options": {
30 | "responsive": true,
31 | "plugins": {
32 | "title": {
33 | "display": true,
34 | "text": "Simple Chart Example"
35 | }
36 | },
37 | "scales": {
38 | "y": {
39 | "beginAtZero": true
40 | }
41 | }
42 | }
43 | }
44 | """
45 |
46 | return GeometryReader { geometry in
47 | Charts(dataJson: dataJson, configJson: configJson)
48 | .frame(height: geometry.size.width > geometry.size.height ?
49 | geometry.size.height : // landscape
50 | geometry.size.height * 0.3) // portrait
51 | .padding()
52 | .frame(maxWidth: .infinity, maxHeight: .infinity)
53 | .position(x: geometry.size.width/2, y: geometry.size.height/2)
54 | }
55 | }
56 |
57 | #Preview("Multiple Datasets") {
58 | // Use the entire view for the chart
59 | let dataJson = """
60 | {
61 | "labels": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
62 | "datasets": [
63 | {
64 | "label": "Sales",
65 | "data": [12, 19, 3, 5, 2, 3],
66 | "backgroundColor": "rgba(255, 99, 132, 0.2)",
67 | "borderColor": "rgba(255, 99, 132, 1)",
68 | "borderWidth": 1
69 | },
70 | {
71 | "label": "Revenue",
72 | "data": [7, 11, 5, 8, 3, 7],
73 | "backgroundColor": "rgba(54, 162, 235, 0.2)",
74 | "borderColor": "rgba(54, 162, 235, 1)",
75 | "borderWidth": 1
76 | }
77 | ]
78 | }
79 | """
80 |
81 | let configJson = """
82 | {
83 | "type": "bar",
84 | "options": {
85 | "responsive": true,
86 | "plugins": {
87 | "title": {
88 | "display": true,
89 | "text": "Dynamic Chart Example"
90 | }
91 | },
92 | "scales": {
93 | "y": {
94 | "beginAtZero": true
95 | }
96 | }
97 | }
98 | }
99 | """
100 |
101 | return GeometryReader { geometry in
102 | Charts(dataJson: dataJson, configJson: configJson)
103 | .frame(height: geometry.size.width > geometry.size.height ?
104 | geometry.size.height : // landscape
105 | geometry.size.height * 0.3) // portrait
106 | .padding()
107 | .frame(maxWidth: .infinity, maxHeight: .infinity)
108 | .position(x: geometry.size.width/2, y: geometry.size.height/2)
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/README/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | # ChartJS for Swift
2 |
3 | Chart.js 的 SwiftUI 封装,让您可以在 iOS ~~和 macOS~~ 应用程序中轻松创建美观、响应式的图表。
4 |
5 | 
6 |
7 | ## 功能特点
8 |
9 | - 支持 Chart.js 提供的各种图表类型(条形图、折线图、饼图、环形图等)
10 | - 完全可定制的 Chart.js 配置选项
11 | - 适用于 iOS 和 macOS(tvOS 和 watchOS 提供回退消息)
12 | - 与 `Charts` 视图的 SwiftUI 集成
13 | - 响应式设计,可适应不同屏幕尺寸
14 |
15 | ## 系统要求
16 |
17 | - iOS 13.0+ / ~~macOS 10.15+~~(即将推出)
18 | - Swift 5.9+
19 | - Xcode 16.0+
20 |
21 | ## 安装
22 |
23 | ### Swift Package Manager
24 |
25 | 通过在 `Package.swift` 文件中添加以下内容来将此包添加到您的项目:
26 |
27 | ```swift
28 | dependencies: [
29 | .package(url: "https://github.com/1998code/ChartJS-for-Swift", from: "1.0.0")
30 | ]
31 | ```
32 |
33 | 或者直接从 Xcode 添加:
34 | 1. 文件 > Swift Packages > 添加包依赖
35 | 2. 输入仓库 URL:`https://github.com/1998code/ChartJS-for-Swift`
36 |
37 | ## 用法
38 |
39 | ### 基本示例
40 |
41 | ```swift
42 | import SwiftUI
43 | import ChartJS
44 |
45 | struct ContentView: View {
46 | let dataJson = """
47 | {
48 | "labels": ["一月", "二月", "三月", "四月", "五月", "六月"],
49 | "datasets": [{
50 | "label": "2025年销售额",
51 | "data": [12, 19, 3, 5, 2, 3],
52 | "backgroundColor": "rgba(75, 192, 192, 0.2)",
53 | "borderColor": "rgba(75, 192, 192, 1)",
54 | "borderWidth": 1
55 | }]
56 | }
57 | """
58 |
59 | let configJson = """
60 | {
61 | "type": "bar",
62 | "options": {
63 | "responsive": true,
64 | "plugins": {
65 | "title": {
66 | "display": true,
67 | "text": "月度销售"
68 | }
69 | },
70 | "scales": {
71 | "y": {
72 | "beginAtZero": true
73 | }
74 | }
75 | }
76 | }
77 | """
78 |
79 | var body: some View {
80 | VStack {
81 | Charts(dataJson: dataJson, configJson: configJson)
82 | .frame(height: 300)
83 | .padding()
84 |
85 | Text("月度销售图表")
86 | .font(.caption)
87 | }
88 | }
89 | }
90 | ```
91 |
92 | ### 多种图表类型
93 |
94 | 您可以通过更改配置中的 `type` 属性来创建不同类型的图表:
95 |
96 | ```swift
97 | // 折线图
98 | let lineConfigJson = """
99 | {
100 | "type": "line",
101 | "options": {
102 | "responsive": true,
103 | "plugins": {
104 | "title": {
105 | "display": true,
106 | "text": "折线图"
107 | }
108 | }
109 | }
110 | }
111 | """
112 |
113 | // 饼图
114 | let pieConfigJson = """
115 | {
116 | "type": "pie",
117 | "options": {
118 | "responsive": true,
119 | "plugins": {
120 | "title": {
121 | "display": true,
122 | "text": "饼图"
123 | }
124 | }
125 | }
126 | }
127 | """
128 | ```
129 |
130 | ### 响应式布局
131 |
132 | 为了获得最佳的响应式体验,请使用 GeometryReader:
133 |
134 | ```swift
135 | GeometryReader { geometry in
136 | Charts(dataJson: dataJson, configJson: configJson)
137 | .frame(height: geometry.size.width > geometry.size.height ?
138 | geometry.size.height : // 横向
139 | geometry.size.height * 0.3) // 纵向
140 | .padding()
141 | }
142 | ```
143 |
144 | ### 自定义 JavaScript
145 |
146 | 如果需要添加自定义 JavaScript 初始化,请使用 `scriptSetup` 参数:
147 |
148 | ```swift
149 | let scriptSetup = """
150 |
157 | """
158 |
159 | Charts(dataJson: dataJson, configJson: configJson, scriptSetup: scriptSetup)
160 | ```
161 |
162 | ## 平台支持
163 |
164 | - **iOS**:完全支持
165 | - **macOS**:即将推出
166 | - **tvOS**:(不支持 WebKit)
167 | - **watchOS**:(不支持 WebKit)
168 |
169 | ## 故障排除
170 |
171 | 如果遇到任何问题:
172 |
173 | 1. 确保您的 JSON 是有效的
174 | 2. 检查您的数据结构是否符合 Chart.js 的预期
175 | 3. 对于复杂图表,请先在 Chart.js 网站上测试您的配置
176 |
177 | ## 许可证
178 |
179 | 本项目基于 MIT 许可证可用。有关更多信息,请参阅 LICENSE 文件。
180 |
181 | ## 致谢
182 |
183 | - [Chart.js](https://www.chartjs.org/) - 简单而灵活的 JavaScript 图表库
184 |
185 | ---
186 |
187 | ## 翻译
188 |
189 | 本文档还提供以下语言版本:
190 |
191 | [English](../README.md) | [繁中](README.zh-TW.md) / [简中](README.zh-CN.md) / [粵語](README.zh-HK.md) | [日本語](README.ja.md) | [Español](README.es.md)
192 |
193 | 欢迎通过 pull request 添加新的语言翻译或修正任何错误。
--------------------------------------------------------------------------------
/README/README.zh-TW.md:
--------------------------------------------------------------------------------
1 | # ChartJS for Swift
2 |
3 | Chart.js 的 SwiftUI 封裝,讓您可以在 iOS ~~和 macOS~~ 應用程式中輕鬆建立美觀、響應式的圖表。
4 |
5 | 
6 |
7 | ## 功能特點
8 |
9 | - 支援 Chart.js 提供的各種圖表類型(條形圖、折線圖、圓餅圖、環形圖等)
10 | - 完全可定制的 Chart.js 配置選項
11 | - 適用於 iOS 和 macOS(tvOS 和 watchOS 提供回退訊息)
12 | - 與 `Charts` 視圖的 SwiftUI 整合
13 | - 響應式設計,可適應不同屏幕尺寸
14 |
15 | ## 系統要求
16 |
17 | - iOS 13.0+ / ~~macOS 10.15+~~(即將推出)
18 | - Swift 5.9+
19 | - Xcode 16.0+
20 |
21 | ## 安裝
22 |
23 | ### Swift Package Manager
24 |
25 | 通過在 `Package.swift` 文件中添加以下內容來將此套件添加到您的專案:
26 |
27 | ```swift
28 | dependencies: [
29 | .package(url: "https://github.com/1998code/ChartJS-for-Swift", from: "1.0.0")
30 | ]
31 | ```
32 |
33 | 或者直接從 Xcode 添加:
34 | 1. 文件 > Swift Packages > 添加套件依賴
35 | 2. 輸入儲存庫 URL:`https://github.com/1998code/ChartJS-for-Swift`
36 |
37 | ## 使用方法
38 |
39 | ### 基本示例
40 |
41 | ```swift
42 | import SwiftUI
43 | import ChartJS
44 |
45 | struct ContentView: View {
46 | let dataJson = """
47 | {
48 | "labels": ["一月", "二月", "三月", "四月", "五月", "六月"],
49 | "datasets": [{
50 | "label": "2025年銷售額",
51 | "data": [12, 19, 3, 5, 2, 3],
52 | "backgroundColor": "rgba(75, 192, 192, 0.2)",
53 | "borderColor": "rgba(75, 192, 192, 1)",
54 | "borderWidth": 1
55 | }]
56 | }
57 | """
58 |
59 | let configJson = """
60 | {
61 | "type": "bar",
62 | "options": {
63 | "responsive": true,
64 | "plugins": {
65 | "title": {
66 | "display": true,
67 | "text": "月度銷售"
68 | }
69 | },
70 | "scales": {
71 | "y": {
72 | "beginAtZero": true
73 | }
74 | }
75 | }
76 | }
77 | """
78 |
79 | var body: some View {
80 | VStack {
81 | Charts(dataJson: dataJson, configJson: configJson)
82 | .frame(height: 300)
83 | .padding()
84 |
85 | Text("月度銷售圖表")
86 | .font(.caption)
87 | }
88 | }
89 | }
90 | ```
91 |
92 | ### 多種圖表類型
93 |
94 | 您可以通過更改配置中的 `type` 屬性來創建不同類型的圖表:
95 |
96 | ```swift
97 | // 折線圖
98 | let lineConfigJson = """
99 | {
100 | "type": "line",
101 | "options": {
102 | "responsive": true,
103 | "plugins": {
104 | "title": {
105 | "display": true,
106 | "text": "折線圖"
107 | }
108 | }
109 | }
110 | }
111 | """
112 |
113 | // 圓餅圖
114 | let pieConfigJson = """
115 | {
116 | "type": "pie",
117 | "options": {
118 | "responsive": true,
119 | "plugins": {
120 | "title": {
121 | "display": true,
122 | "text": "圓餅圖"
123 | }
124 | }
125 | }
126 | }
127 | """
128 | ```
129 |
130 | ### 響應式布局
131 |
132 | 為了獲得最佳的響應式體驗,請使用 GeometryReader:
133 |
134 | ```swift
135 | GeometryReader { geometry in
136 | Charts(dataJson: dataJson, configJson: configJson)
137 | .frame(height: geometry.size.width > geometry.size.height ?
138 | geometry.size.height : // 橫向
139 | geometry.size.height * 0.3) // 縱向
140 | .padding()
141 | }
142 | ```
143 |
144 | ### 自定義 JavaScript
145 |
146 | 如果需要添加自定義 JavaScript 初始化,請使用 `scriptSetup` 參數:
147 |
148 | ```swift
149 | let scriptSetup = """
150 |
157 | """
158 |
159 | Charts(dataJson: dataJson, configJson: configJson, scriptSetup: scriptSetup)
160 | ```
161 |
162 | ## 平台支持
163 |
164 | - **iOS**:完全支持
165 | - **macOS**:即將推出
166 | - **tvOS**:(不支持 WebKit)
167 | - **watchOS**:(不支持 WebKit)
168 |
169 | ## 故障排除
170 |
171 | 如果遇到任何問題:
172 |
173 | 1. 確保您的 JSON 是有效的
174 | 2. 檢查您的數據結構是否符合 Chart.js 的預期
175 | 3. 對於複雜圖表,請先在 Chart.js 網站上測試您的配置
176 |
177 | ## 許可證
178 |
179 | 本項目基於 MIT 許可證可用。有關更多信息,請參閱 LICENSE 文件。
180 |
181 | ## 致謝
182 |
183 | - [Chart.js](https://www.chartjs.org/) - 簡單而靈活的 JavaScript 圖表庫
184 |
185 | ---
186 |
187 | ## 翻譯
188 |
189 | 本文檔還提供以下語言版本:
190 |
191 | [English](../README.md) | [繁中](README.zh-TW.md) / [简中](README.zh-CN.md) / [粵語](README.zh-HK.md) | [日本語](README.ja.md) | [Español](README.es.md)
192 |
193 | 歡迎通過 pull request 添加新的語言翻譯或修正任何錯誤。
--------------------------------------------------------------------------------
/README/README.zh-HK.md:
--------------------------------------------------------------------------------
1 | # ChartJS for Swift
2 |
3 | Chart.js 嘅 SwiftUI 封裝,畀你喺 iOS ~~同 macOS~~ 應用程式入面輕鬆建立靚靚嘅響應式圖表。
4 |
5 | 
6 |
7 | ## 功能特點
8 |
9 | - 支援 Chart.js 提供嘅各種圖表類型(條形圖、折線圖、圓餅圖、環形圖等)
10 | - 完全可以自訂嘅 Chart.js 配置選項
11 | - 適用於 iOS 同 macOS(tvOS 同 watchOS 提供回退訊息)
12 | - 同 `Charts` 視圖嘅 SwiftUI 整合
13 | - 響應式設計,可以適應唔同屏幕尺寸
14 |
15 | ## 系統要求
16 |
17 | - iOS 13.0+ / ~~macOS 10.15+~~(即將推出)
18 | - Swift 5.9+
19 | - Xcode 16.0+
20 |
21 | ## 安裝
22 |
23 | ### Swift Package Manager
24 |
25 | 喺 `Package.swift` 文件入面加入以下內容,將呢個套件添加到你嘅專案:
26 |
27 | ```swift
28 | dependencies: [
29 | .package(url: "https://github.com/1998code/ChartJS-for-Swift", from: "1.0.0")
30 | ]
31 | ```
32 |
33 | 或者直接由 Xcode 添加:
34 | 1. 文件 > Swift Packages > 添加套件依賴
35 | 2. 輸入倉庫 URL:`https://github.com/1998code/ChartJS-for-Swift`
36 |
37 | ## 使用方法
38 |
39 | ### 基本示例
40 |
41 | ```swift
42 | import SwiftUI
43 | import ChartJS
44 |
45 | struct ContentView: View {
46 | let dataJson = """
47 | {
48 | "labels": ["一月", "二月", "三月", "四月", "五月", "六月"],
49 | "datasets": [{
50 | "label": "2025年銷售額",
51 | "data": [12, 19, 3, 5, 2, 3],
52 | "backgroundColor": "rgba(75, 192, 192, 0.2)",
53 | "borderColor": "rgba(75, 192, 192, 1)",
54 | "borderWidth": 1
55 | }]
56 | }
57 | """
58 |
59 | let configJson = """
60 | {
61 | "type": "bar",
62 | "options": {
63 | "responsive": true,
64 | "plugins": {
65 | "title": {
66 | "display": true,
67 | "text": "月度銷售"
68 | }
69 | },
70 | "scales": {
71 | "y": {
72 | "beginAtZero": true
73 | }
74 | }
75 | }
76 | }
77 | """
78 |
79 | var body: some View {
80 | VStack {
81 | Charts(dataJson: dataJson, configJson: configJson)
82 | .frame(height: 300)
83 | .padding()
84 |
85 | Text("月度銷售圖表")
86 | .font(.caption)
87 | }
88 | }
89 | }
90 | ```
91 |
92 | ### 多種圖表類型
93 |
94 | 你可以通過更改配置入面嘅 `type` 屬性來創建唔同類型嘅圖表:
95 |
96 | ```swift
97 | // 折線圖
98 | let lineConfigJson = """
99 | {
100 | "type": "line",
101 | "options": {
102 | "responsive": true,
103 | "plugins": {
104 | "title": {
105 | "display": true,
106 | "text": "折線圖"
107 | }
108 | }
109 | }
110 | }
111 | """
112 |
113 | // 圓餅圖
114 | let pieConfigJson = """
115 | {
116 | "type": "pie",
117 | "options": {
118 | "responsive": true,
119 | "plugins": {
120 | "title": {
121 | "display": true,
122 | "text": "圓餅圖"
123 | }
124 | }
125 | }
126 | }
127 | """
128 | ```
129 |
130 | ### 響應式布局
131 |
132 | 要獲得最佳嘅響應式體驗,請使用 GeometryReader:
133 |
134 | ```swift
135 | GeometryReader { geometry in
136 | Charts(dataJson: dataJson, configJson: configJson)
137 | .frame(height: geometry.size.width > geometry.size.height ?
138 | geometry.size.height : // 橫向
139 | geometry.size.height * 0.3) // 縱向
140 | .padding()
141 | }
142 | ```
143 |
144 | ### 自定義 JavaScript
145 |
146 | 如果需要添加自定義 JavaScript 初始化,請使用 `scriptSetup` 參數:
147 |
148 | ```swift
149 | let scriptSetup = """
150 |
157 | """
158 |
159 | Charts(dataJson: dataJson, configJson: configJson, scriptSetup: scriptSetup)
160 | ```
161 |
162 | ## 平台支援
163 |
164 | - **iOS**:完全支援
165 | - **macOS**:即將推出
166 | - **tvOS**:(唔支援 WebKit)
167 | - **watchOS**:(唔支援 WebKit)
168 |
169 | ## 疑難排解
170 |
171 | 如果遇到任何問題:
172 |
173 | 1. 確保你嘅 JSON 係有效嘅
174 | 2. 檢查你嘅數據結構係咪符合 Chart.js 嘅預期
175 | 3. 對於複雜圖表,請先喺 Chart.js 網站上測試你嘅配置
176 |
177 | ## 許可證
178 |
179 | 呢個項目係基於 MIT 許可證可用。有關更多資訊,請參閱 LICENSE 文件。
180 |
181 | ## 致謝
182 |
183 | - [Chart.js](https://www.chartjs.org/) - 簡單而靈活嘅 JavaScript 圖表庫
184 |
185 | ---
186 |
187 | ## 翻譯
188 |
189 | 呢個文檔仲有以下語言版本:
190 |
191 | [English](../README.md) | [繁中](README.zh-TW.md) / [简中](README.zh-CN.md) / [粵語](README.zh-HK.md) | [日本語](README.ja.md) | [Español](README.es.md)
192 |
193 | 歡迎透過 pull request 添加新嘅語言翻譯或者修正任何錯誤。
--------------------------------------------------------------------------------
/README/README.ja.md:
--------------------------------------------------------------------------------
1 | # ChartJS for Swift
2 |
3 | Chart.js のための SwiftUI ラッパーで、iOS ~~および macOS~~ アプリケーションで美しいレスポンシブチャートを簡単に作成できます。
4 |
5 | 
6 |
7 | ## 特徴
8 |
9 | - Chart.js がサポートする様々なチャートタイプ(棒グラフ、折れ線グラフ、円グラフ、ドーナツグラフなど)を作成可能
10 | - Chart.js の設定オプションで完全にカスタマイズ可能
11 | - iOS と macOS で動作(tvOS と watchOS はフォールバックメッセージを表示)
12 | - `Charts` ビューによる SwiftUI 統合
13 | - 様々な画面サイズに適応するレスポンシブデザイン
14 |
15 | ## 要件
16 |
17 | - iOS 13.0+ / ~~macOS 10.15+~~(近日公開)
18 | - Swift 5.9+
19 | - Xcode 16.0+
20 |
21 | ## インストール
22 |
23 | ### Swift Package Manager
24 |
25 | `Package.swift` ファイルに以下を追加して、このパッケージをプロジェクトに追加します:
26 |
27 | ```swift
28 | dependencies: [
29 | .package(url: "https://github.com/1998code/ChartJS-for-Swift", from: "1.0.0")
30 | ]
31 | ```
32 |
33 | または Xcode から直接追加することもできます:
34 | 1. ファイル > Swift Packages > パッケージ依存関係を追加
35 | 2. リポジトリ URL を入力:`https://github.com/1998code/ChartJS-for-Swift`
36 |
37 | ## 使用方法
38 |
39 | ### 基本的な例
40 |
41 | ```swift
42 | import SwiftUI
43 | import ChartJS
44 |
45 | struct ContentView: View {
46 | let dataJson = """
47 | {
48 | "labels": ["1月", "2月", "3月", "4月", "5月", "6月"],
49 | "datasets": [{
50 | "label": "2025年の売上",
51 | "data": [12, 19, 3, 5, 2, 3],
52 | "backgroundColor": "rgba(75, 192, 192, 0.2)",
53 | "borderColor": "rgba(75, 192, 192, 1)",
54 | "borderWidth": 1
55 | }]
56 | }
57 | """
58 |
59 | let configJson = """
60 | {
61 | "type": "bar",
62 | "options": {
63 | "responsive": true,
64 | "plugins": {
65 | "title": {
66 | "display": true,
67 | "text": "月次売上"
68 | }
69 | },
70 | "scales": {
71 | "y": {
72 | "beginAtZero": true
73 | }
74 | }
75 | }
76 | }
77 | """
78 |
79 | var body: some View {
80 | VStack {
81 | Charts(dataJson: dataJson, configJson: configJson)
82 | .frame(height: 300)
83 | .padding()
84 |
85 | Text("月次売上チャート")
86 | .font(.caption)
87 | }
88 | }
89 | }
90 | ```
91 |
92 | ### 複数のチャートタイプ
93 |
94 | 設定の `type` プロパティを変更することで、異なるチャートタイプを作成できます:
95 |
96 | ```swift
97 | // 折れ線グラフ
98 | let lineConfigJson = """
99 | {
100 | "type": "line",
101 | "options": {
102 | "responsive": true,
103 | "plugins": {
104 | "title": {
105 | "display": true,
106 | "text": "折れ線グラフ"
107 | }
108 | }
109 | }
110 | }
111 | """
112 |
113 | // 円グラフ
114 | let pieConfigJson = """
115 | {
116 | "type": "pie",
117 | "options": {
118 | "responsive": true,
119 | "plugins": {
120 | "title": {
121 | "display": true,
122 | "text": "円グラフ"
123 | }
124 | }
125 | }
126 | }
127 | """
128 | ```
129 |
130 | ### レスポンシブレイアウト
131 |
132 | 最適なレスポンシブ体験を得るには、GeometryReaderを使用します:
133 |
134 | ```swift
135 | GeometryReader { geometry in
136 | Charts(dataJson: dataJson, configJson: configJson)
137 | .frame(height: geometry.size.width > geometry.size.height ?
138 | geometry.size.height : // 横向き
139 | geometry.size.height * 0.3) // 縦向き
140 | .padding()
141 | }
142 | ```
143 |
144 | ### カスタムJavaScript
145 |
146 | カスタムJavaScript初期化を追加する必要がある場合は、`scriptSetup`パラメータを使用します:
147 |
148 | ```swift
149 | let scriptSetup = """
150 |
157 | """
158 |
159 | Charts(dataJson: dataJson, configJson: configJson, scriptSetup: scriptSetup)
160 | ```
161 |
162 | ## プラットフォームサポート
163 |
164 | - **iOS**:完全対応
165 | - **macOS**:近日公開
166 | - **tvOS**:(WebKit非対応)
167 | - **watchOS**:(WebKit非対応)
168 |
169 | ## トラブルシューティング
170 |
171 | 問題が発生した場合:
172 |
173 | 1. JSONが有効であることを確認する
174 | 2. データ構造がChart.jsの期待するものと一致していることを確認する
175 | 3. 複雑なチャートの場合は、先にChart.jsのウェブサイトで設定をテストする
176 |
177 | ## ライセンス
178 |
179 | このプロジェクトはMITライセンスの下で利用可能です。詳細はLICENSEファイルをご覧ください。
180 |
181 | ## 謝辞
182 |
183 | - [Chart.js](https://www.chartjs.org/) - シンプルで柔軟なJavaScriptチャートライブラリ
184 |
185 | ---
186 |
187 | ## 翻訳
188 |
189 | このドキュメントは以下の言語でもご利用いただけます:
190 |
191 | [English](../README.md) | [繁中](README.zh-TW.md) / [简中](README.zh-CN.md) / [粵語](README.zh-HK.md) | [日本語](README.ja.md) | [Español](README.es.md)
192 |
193 | 新しい言語の追加や誤字・間違いの修正は、プルリクエストでお気軽にご貢献ください。
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ChartJS for Swift
2 |
3 | A SwiftUI wrapper for Chart.js that allows you to easily create beautiful, responsive charts in your iOS ~~and macOS~~ applications.
4 |
5 | 
6 |
7 | ## Features
8 |
9 | - Create various chart types supported by Chart.js (bar, line, pie, doughnut, etc.)
10 | - Fully customizable with Chart.js configuration options
11 | - Works on iOS and macOS (fallback message for tvOS and watchOS)
12 | - SwiftUI integration with `Charts` view
13 | - Responsive design that adapts to different screen sizes
14 |
15 | ## Requirements
16 |
17 | - iOS 13.0+ / ~~macOS 10.15+~~(Coming Soon)
18 | - Swift 5.9+
19 | - Xcode 16.0+
20 |
21 | ## Installation
22 |
23 | ### Swift Package Manager
24 |
25 | Add this package to your project by adding the following to your `Package.swift` file:
26 |
27 | ```swift
28 | dependencies: [
29 | .package(url: "https://github.com/1998code/ChartJS-for-Swift", from: "1.0.0")
30 | ]
31 | ```
32 |
33 | Or add it directly from Xcode:
34 | 1. File > Swift Packages > Add Package Dependency
35 | 2. Enter the repository URL: `https://github.com/1998code/ChartJS-for-Swift`
36 |
37 | ## Usage
38 |
39 | ### Basic Example
40 |
41 | ```swift
42 | import SwiftUI
43 | import ChartJS
44 |
45 | struct ContentView: View {
46 | let dataJson = """
47 | {
48 | "labels": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
49 | "datasets": [{
50 | "label": "Sales 2025",
51 | "data": [12, 19, 3, 5, 2, 3],
52 | "backgroundColor": "rgba(75, 192, 192, 0.2)",
53 | "borderColor": "rgba(75, 192, 192, 1)",
54 | "borderWidth": 1
55 | }]
56 | }
57 | """
58 |
59 | let configJson = """
60 | {
61 | "type": "bar",
62 | "options": {
63 | "responsive": true,
64 | "plugins": {
65 | "title": {
66 | "display": true,
67 | "text": "Monthly Sales"
68 | }
69 | },
70 | "scales": {
71 | "y": {
72 | "beginAtZero": true
73 | }
74 | }
75 | }
76 | }
77 | """
78 |
79 | var body: some View {
80 | VStack {
81 | Charts(dataJson: dataJson, configJson: configJson)
82 | .frame(height: 300)
83 | .padding()
84 |
85 | Text("Monthly Sales Chart")
86 | .font(.caption)
87 | }
88 | }
89 | }
90 | ```
91 |
92 | ### Multiple Chart Types
93 |
94 | You can create different chart types by changing the `type` property in the configuration:
95 |
96 | ```swift
97 | // Line chart
98 | let lineConfigJson = """
99 | {
100 | "type": "line",
101 | "options": {
102 | "responsive": true,
103 | "plugins": {
104 | "title": {
105 | "display": true,
106 | "text": "Line Chart"
107 | }
108 | }
109 | }
110 | }
111 | """
112 |
113 | // Pie chart
114 | let pieConfigJson = """
115 | {
116 | "type": "pie",
117 | "options": {
118 | "responsive": true,
119 | "plugins": {
120 | "title": {
121 | "display": true,
122 | "text": "Pie Chart"
123 | }
124 | }
125 | }
126 | }
127 | """
128 | ```
129 |
130 | ### Responsive Layout
131 |
132 | For the best responsive experience, use GeometryReader:
133 |
134 | ```swift
135 | GeometryReader { geometry in
136 | Charts(dataJson: dataJson, configJson: configJson)
137 | .frame(height: geometry.size.width > geometry.size.height ?
138 | geometry.size.height : // landscape
139 | geometry.size.height * 0.3) // portrait
140 | .padding()
141 | }
142 | ```
143 |
144 | ### Custom JavaScript
145 |
146 | If you need to add custom JavaScript initialization, use the `scriptSetup` parameter:
147 |
148 | ```swift
149 | let scriptSetup = """
150 |
157 | """
158 |
159 | Charts(dataJson: dataJson, configJson: configJson, scriptSetup: scriptSetup)
160 | ```
161 |
162 | ## Platform Support
163 |
164 | - **iOS**: Fully supported
165 | - **macOS**: Coming Soon
166 | - **tvOS**: (WebKit not supported)
167 | - **watchOS**: (WebKit not supported)
168 |
169 | ## Troubleshooting
170 |
171 | If you encounter any issues:
172 |
173 | 1. Make sure your JSON is valid
174 | 2. Check that your data structure matches what Chart.js expects
175 | 3. For complex charts, test your configuration on the Chart.js website first
176 |
177 | ## License
178 |
179 | This project is available under the MIT license. See the LICENSE file for more info.
180 |
181 | ## Acknowledgements
182 |
183 | - [Chart.js](https://www.chartjs.org/) - Simple yet flexible JavaScript charting library
184 |
185 | ---
186 |
187 | ## Translations
188 |
189 | This doc is also available in:
190 |
191 | [English](README.md) | [繁中](README/README.zh-TW.md) / [简中](README/README.zh-CN.md) / [粵語](README/README.zh-HK.md) | [日本語](README/README.ja.md) | [Español](README/README.es.md)
192 |
193 | Please feel free to open a pull request and add new language(s) or fix any typos/mistakes.
194 |
--------------------------------------------------------------------------------
/README/README.es.md:
--------------------------------------------------------------------------------
1 | # ChartJS para Swift
2 |
3 | Un envoltorio SwiftUI para Chart.js que te permite crear fácilmente gráficos hermosos y responsivos en tus aplicaciones iOS ~~y macOS~~.
4 |
5 | 
6 |
7 | ## Características
8 |
9 | - Crea varios tipos de gráficos soportados por Chart.js (barras, líneas, circular, anillo, etc.)
10 | - Completamente personalizable con opciones de configuración de Chart.js
11 | - Funciona en iOS y macOS (mensaje alternativo para tvOS y watchOS)
12 | - Integración con SwiftUI mediante la vista `Charts`
13 | - Diseño responsivo que se adapta a diferentes tamaños de pantalla
14 |
15 | ## Requisitos
16 |
17 | - iOS 13.0+ / ~~macOS 10.15+~~(Próximamente)
18 | - Swift 5.9+
19 | - Xcode 16.0+
20 |
21 | ## Instalación
22 |
23 | ### Swift Package Manager
24 |
25 | Añade este paquete a tu proyecto agregando lo siguiente a tu archivo `Package.swift`:
26 |
27 | ```swift
28 | dependencies: [
29 | .package(url: "https://github.com/1998code/ChartJS-for-Swift", from: "1.0.0")
30 | ]
31 | ```
32 |
33 | O añádelo directamente desde Xcode:
34 | 1. Archivo > Swift Packages > Añadir dependencia de paquete
35 | 2. Introduce la URL del repositorio: `https://github.com/1998code/ChartJS-for-Swift`
36 |
37 | ## Uso
38 |
39 | ### Ejemplo básico
40 |
41 | ```swift
42 | import SwiftUI
43 | import ChartJS
44 |
45 | struct ContentView: View {
46 | let dataJson = """
47 | {
48 | "labels": ["Ene", "Feb", "Mar", "Abr", "May", "Jun"],
49 | "datasets": [{
50 | "label": "Ventas 2025",
51 | "data": [12, 19, 3, 5, 2, 3],
52 | "backgroundColor": "rgba(75, 192, 192, 0.2)",
53 | "borderColor": "rgba(75, 192, 192, 1)",
54 | "borderWidth": 1
55 | }]
56 | }
57 | """
58 |
59 | let configJson = """
60 | {
61 | "type": "bar",
62 | "options": {
63 | "responsive": true,
64 | "plugins": {
65 | "title": {
66 | "display": true,
67 | "text": "Ventas Mensuales"
68 | }
69 | },
70 | "scales": {
71 | "y": {
72 | "beginAtZero": true
73 | }
74 | }
75 | }
76 | }
77 | """
78 |
79 | var body: some View {
80 | VStack {
81 | Charts(dataJson: dataJson, configJson: configJson)
82 | .frame(height: 300)
83 | .padding()
84 |
85 | Text("Gráfico de ventas mensuales")
86 | .font(.caption)
87 | }
88 | }
89 | }
90 | ```
91 |
92 | ### Múltiples tipos de gráficos
93 |
94 | Puedes crear diferentes tipos de gráficos cambiando la propiedad `type` en la configuración:
95 |
96 | ```swift
97 | // Gráfico de líneas
98 | let lineConfigJson = """
99 | {
100 | "type": "line",
101 | "options": {
102 | "responsive": true,
103 | "plugins": {
104 | "title": {
105 | "display": true,
106 | "text": "Gráfico de Líneas"
107 | }
108 | }
109 | }
110 | }
111 | """
112 |
113 | // Gráfico circular
114 | let pieConfigJson = """
115 | {
116 | "type": "pie",
117 | "options": {
118 | "responsive": true,
119 | "plugins": {
120 | "title": {
121 | "display": true,
122 | "text": "Gráfico Circular"
123 | }
124 | }
125 | }
126 | }
127 | """
128 | ```
129 |
130 | ### Diseño responsivo
131 |
132 | Para la mejor experiencia responsiva, usa GeometryReader:
133 |
134 | ```swift
135 | GeometryReader { geometry in
136 | Charts(dataJson: dataJson, configJson: configJson)
137 | .frame(height: geometry.size.width > geometry.size.height ?
138 | geometry.size.height : // paisaje
139 | geometry.size.height * 0.3) // retrato
140 | .padding()
141 | }
142 | ```
143 |
144 | ### JavaScript personalizado
145 |
146 | Si necesitas añadir inicialización JavaScript personalizada, usa el parámetro `scriptSetup`:
147 |
148 | ```swift
149 | let scriptSetup = """
150 |
157 | """
158 |
159 | Charts(dataJson: dataJson, configJson: configJson, scriptSetup: scriptSetup)
160 | ```
161 |
162 | ## Soporte de plataformas
163 |
164 | - **iOS**: Totalmente soportado
165 | - **macOS**: Próximamente
166 | - **tvOS**: (WebKit no soportado)
167 | - **watchOS**: (WebKit no soportado)
168 |
169 | ## Solución de problemas
170 |
171 | Si encuentras problemas:
172 |
173 | 1. Asegúrate de que tu JSON sea válido
174 | 2. Comprueba que tu estructura de datos coincida con lo que Chart.js espera
175 | 3. Para gráficos complejos, prueba tu configuración en el sitio web de Chart.js primero
176 |
177 | ## Licencia
178 |
179 | Este proyecto está disponible bajo la licencia MIT. Consulta el archivo LICENSE para más información.
180 |
181 | ## Agradecimientos
182 |
183 | - [Chart.js](https://www.chartjs.org/) - Librería JavaScript de gráficos simple y flexible
184 |
185 | ---
186 |
187 | ## Traducciones
188 |
189 | Esta documentación está disponible también en:
190 |
191 | [English](../README.md) | [繁中](README.zh-TW.md) / [简中](README.zh-CN.md) / [粵語](README.zh-HK.md) | [日本語](README.ja.md) | [Español](README.es.md)
192 |
193 | No dudes en abrir un pull request para añadir nuevos idiomas o corregir cualquier error.
--------------------------------------------------------------------------------
/ChartJS Demo/ChartJS Demo/Charts/Line.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Line.swift
3 | // ChartJS
4 | //
5 | // Created by Ming on 21/5/2025.
6 | //
7 |
8 | import SwiftUI
9 | import ChartJS
10 |
11 | #Preview("Simple Line Chart") {
12 | let dataJson = """
13 | {
14 | "labels": ["January", "February", "March", "April", "May", "June", "July"],
15 | "datasets": [{
16 | "label": "My First Dataset",
17 | "data": [65, 59, 80, 81, 56, 55, 40],
18 | "fill": false,
19 | "borderColor": "rgb(75, 192, 192)",
20 | "tension": 0.3
21 | }]
22 | }
23 | """
24 |
25 | let configJson = """
26 | {
27 | "type": "line",
28 | "options": {
29 | "responsive": true,
30 | "plugins": {
31 | "title": {
32 | "display": true,
33 | "text": "Chart.js Line Chart"
34 | }
35 | }
36 | }
37 | }
38 | """
39 |
40 | GeometryReader { geometry in
41 | Charts(dataJson: dataJson, configJson: configJson)
42 | .frame(height: geometry.size.width > geometry.size.height ?
43 | geometry.size.height : // landscape
44 | geometry.size.height * 0.3) // portrait
45 | .padding()
46 | .frame(maxWidth: .infinity, maxHeight: .infinity)
47 | .position(x: geometry.size.width/2, y: geometry.size.height/2)
48 | }
49 | }
50 |
51 | #Preview("Line Chart with Gradient") {
52 | let dataJson = """
53 | {
54 | "labels": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
55 | "datasets": [{
56 | "label": "Monthly Data",
57 | "data": [45, 55, 65, 75, 95, 105, 95, 75, 55, 45, 35, 25],
58 | "fill": true,
59 | "borderColor": "rgb(75, 192, 192)",
60 | "tension": 0.35,
61 | "backgroundColor": "GRADIENT"
62 | }]
63 | }
64 | """
65 |
66 | let configJson = """
67 | {
68 | "type": "line",
69 | "options": {
70 | "responsive": true,
71 | "plugins": {
72 | "title": {
73 | "display": true,
74 | "text": "Chart.js Line Chart with Vertical Gradient"
75 | }
76 | },
77 | "scales": {
78 | "y": {
79 | "beginAtZero": true
80 | }
81 | }
82 | }
83 | }
84 | """
85 |
86 | let scriptSetup = """
87 |
106 | """
107 |
108 | GeometryReader { geometry in
109 | Charts(dataJson: dataJson, configJson: configJson, scriptSetup: scriptSetup)
110 | .frame(height: geometry.size.width > geometry.size.height ?
111 | geometry.size.height : // landscape
112 | geometry.size.height * 0.3) // portrait
113 | .padding()
114 | .frame(maxWidth: .infinity, maxHeight: .infinity)
115 | .position(x: geometry.size.width/2, y: geometry.size.height/2)
116 | }
117 | }
118 |
119 | #Preview("Multi-Dataset Line Chart with Gradients") {
120 | let dataJson = """
121 | {
122 | "labels": ["January", "February", "March", "April", "May", "June", "July"],
123 | "datasets": [
124 | {
125 | "label": "Dataset 1",
126 | "data": [65, 59, 80, 81, 56, 55, 40],
127 | "borderColor": "rgb(255, 99, 132)",
128 | "backgroundColor": "GRADIENT1",
129 | "tension": 0.3,
130 | "fill": true
131 | },
132 | {
133 | "label": "Dataset 2",
134 | "data": [28, 48, 40, 19, 45, 35, 30],
135 | "borderColor": "rgb(35, 253, 152)",
136 | "backgroundColor": "GRADIENT2",
137 | "tension": 0.3,
138 | "fill": true
139 | }
140 | ]
141 | }
142 | """
143 |
144 | let configJson = """
145 | {
146 | "type": "line",
147 | "options": {
148 | "responsive": true,
149 | "plugins": {
150 | "title": {
151 | "display": true,
152 | "text": "Chart.js Multi-Line Chart with Gradients"
153 | }
154 | }
155 | }
156 | }
157 | """
158 |
159 | let scriptSetup = """
160 |
187 | """
188 |
189 | GeometryReader { geometry in
190 | Charts(dataJson: dataJson, configJson: configJson, scriptSetup: scriptSetup)
191 | .frame(height: geometry.size.width > geometry.size.height ?
192 | geometry.size.height : // landscape
193 | geometry.size.height * 0.3) // portrait
194 | .padding()
195 | .frame(maxWidth: .infinity, maxHeight: .infinity)
196 | .position(x: geometry.size.width/2, y: geometry.size.height/2)
197 | }
198 | }
199 |
200 | #Preview("Stacked Bar/Line Chart") {
201 | let dataJson = """
202 | {
203 | "labels": ["January", "February", "March", "April", "May", "June", "July"],
204 | "datasets": [
205 | {
206 | "label": "Dataset 1",
207 | "data": [65, 59, 80, 81, 56, 55, 40],
208 | "borderColor": "rgb(255, 99, 132)",
209 | "backgroundColor": "rgba(255, 99, 132, 0.5)",
210 | "stack": "combined",
211 | "type": "bar"
212 | },
213 | {
214 | "label": "Dataset 2",
215 | "data": [28, 48, 40, 19, 86, 27, 90],
216 | "borderColor": "rgb(54, 162, 235)",
217 | "backgroundColor": "rgba(54, 162, 235, 0.5)",
218 | "stack": "combined"
219 | }
220 | ]
221 | }
222 | """
223 |
224 | let configJson = """
225 | {
226 | "type": "line",
227 | "options": {
228 | "plugins": {
229 | "title": {
230 | "display": true,
231 | "text": "Chart.js Stacked Line/Bar Chart"
232 | }
233 | },
234 | "scales": {
235 | "y": {
236 | "stacked": true
237 | }
238 | }
239 | }
240 | }
241 | """
242 |
243 | return GeometryReader { geometry in
244 | Charts(dataJson: dataJson, configJson: configJson)
245 | .frame(height: geometry.size.width > geometry.size.height ?
246 | geometry.size.height : // landscape
247 | geometry.size.height * 0.3) // portrait
248 | .padding()
249 | .frame(maxWidth: .infinity, maxHeight: .infinity)
250 | .position(x: geometry.size.width/2, y: geometry.size.height/2)
251 | }
252 | }
253 |
--------------------------------------------------------------------------------
/Sources/ChartJS/ChartJS.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartJS.swift
3 | // ChartJS
4 | //
5 | // Created by Ming on 21/5/2025.
6 | //
7 |
8 | import SwiftUI
9 | import WebKit
10 |
11 | /// A SwiftUI view that renders charts using Chart.js
12 | public struct Charts: View {
13 | var dataJson: String
14 | var configJson: String
15 | var height: CGFloat?
16 | var scriptSetup: String?
17 |
18 | /// Initialize a new Charts view
19 | /// - Parameters:
20 | /// - dataJson: JSON string containing chart data
21 | /// - configJson: JSON string containing chart configuration
22 | /// - height: Optional height for the chart
23 | /// - scriptSetup: Optional JavaScript for additional chart setup
24 | public init(dataJson: String, configJson: String, height: CGFloat? = nil, scriptSetup: String? = nil) {
25 | self.dataJson = dataJson
26 | self.configJson = configJson
27 | self.height = height
28 | self.scriptSetup = scriptSetup
29 | }
30 |
31 | public var body: some View {
32 | ChartView(dataJson: dataJson, configJson: configJson, height: height, scriptSetup: scriptSetup)
33 | }
34 | }
35 |
36 | /// The underlying UIViewRepresentable that renders Chart.js content
37 | struct ChartView: UIViewRepresentable {
38 | // Support for JSON configuration
39 | var dataJson: String
40 | var configJson: String
41 |
42 | // Optional height parameter
43 | var height: CGFloat?
44 |
45 | // Optional script setup for advanced customization
46 | var scriptSetup: String?
47 |
48 | init(dataJson: String, configJson: String, height: CGFloat? = nil, scriptSetup: String? = nil) {
49 | self.dataJson = dataJson
50 | self.configJson = configJson
51 | self.height = height
52 | self.scriptSetup = scriptSetup
53 | }
54 |
55 | func makeUIView(context: Context) -> WKWebView {
56 | let webView = WKWebView()
57 | webView.navigationDelegate = context.coordinator
58 |
59 | // Configure webView for transparency
60 | webView.isOpaque = false
61 | webView.backgroundColor = UIColor.clear
62 | webView.scrollView.backgroundColor = UIColor.clear
63 |
64 | return webView
65 | }
66 |
67 | func updateUIView(_ webView: WKWebView, context: Context) {
68 | webView.scrollView.isScrollEnabled = true
69 | webView.translatesAutoresizingMaskIntoConstraints = true
70 | let htmlContent = generateChartHTMLWithJSON(dataJson: dataJson, configJson: configJson)
71 | if let chartJsBundleUrl = chartJSBundle.url(forResource: "chart", withExtension: "js") {
72 | let tempDir = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("chartjs-local")
73 | let tempChartJsUrl = tempDir.appendingPathComponent("chart.js")
74 | if !FileManager.default.fileExists(atPath: tempChartJsUrl.path) {
75 | try? FileManager.default.createDirectory(at: tempDir, withIntermediateDirectories: true)
76 | do {
77 | try FileManager.default.copyItem(at: chartJsBundleUrl, to: tempChartJsUrl)
78 | print("[ChartJS] Copied chart.js to temp: \(tempChartJsUrl.path)")
79 | } catch {
80 | print("[ChartJS] Error copying chart.js: \(error)")
81 | }
82 | } else {
83 | print("[ChartJS] chart.js already exists at temp: \(tempChartJsUrl.path)")
84 | }
85 | print("[ChartJS] baseURL for WKWebView: \(tempDir)")
86 | webView.loadHTMLString(htmlContent, baseURL: tempDir)
87 | context.coordinator.previousDataJson = dataJson
88 | context.coordinator.previousConfigJson = configJson
89 | webView.evaluateJavaScript("console.log('Chart loaded with data');", completionHandler: nil)
90 | } else {
91 | print("[ChartJS] Error: chart.js file not found in the bundle")
92 | webView.loadHTMLString(htmlContent, baseURL: nil)
93 | }
94 | }
95 |
96 | func makeCoordinator() -> Coordinator {
97 | Coordinator(self)
98 | }
99 |
100 | class Coordinator: NSObject, WKNavigationDelegate {
101 | var parent: ChartView
102 | var previousDataJson: String = ""
103 | var previousConfigJson: String = ""
104 |
105 | init(_ parent: ChartView) {
106 | self.parent = parent
107 | self.previousDataJson = parent.dataJson
108 | self.previousConfigJson = parent.configJson
109 | }
110 | }
111 |
112 | private func generateChartHTMLWithJSON(dataJson: String, configJson: String) -> String {
113 | // Always use local chart.js, never CDN
114 | let chartJsScriptTag = ""
115 | return """
116 |
117 |
118 |
119 |
120 | \(chartJsScriptTag)
121 |
130 | \(scriptSetup ?? "")
131 |
132 |
133 |
134 |
135 |
136 |
164 |
165 |
166 | """
167 | }
168 | }
169 |
170 | // Extension to get the correct bundle for resources
171 | private extension ChartView {
172 | var chartJSBundle: Bundle {
173 | #if SWIFT_PACKAGE
174 | return Bundle.module
175 | #else
176 | let candidates = [
177 | Bundle(for: Coordinator.self),
178 | Bundle.main,
179 | ]
180 | for bundle in candidates {
181 | if bundle.path(forResource: "chart", ofType: "js") != nil {
182 | return bundle
183 | }
184 | }
185 | return Bundle.main
186 | #endif
187 | }
188 | }
189 |
190 | #Preview("Simple Chart") {
191 | let dataJson = """
192 | {
193 | "labels": ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
194 | "datasets": [{
195 | "label": "Data",
196 | "data": [12, 19, 3, 5, 2, 3],
197 | "backgroundColor": "rgba(75, 192, 192, 0.2)",
198 | "borderColor": "rgba(75, 192, 192, 1)",
199 | "borderWidth": 1
200 | }]
201 | }
202 | """
203 |
204 | let dataJson2 = """
205 | {
206 | "labels": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
207 | "datasets": [
208 | {
209 | "label": "Sales",
210 | "data": [12, 19, 3, 5, 2, 3],
211 | "backgroundColor": "rgba(255, 99, 132, 0.2)",
212 | "borderColor": "rgba(255, 99, 132, 1)",
213 | "borderWidth": 1
214 | },
215 | {
216 | "label": "Revenue",
217 | "data": [7, 11, 5, 8, 3, 7],
218 | "backgroundColor": "rgba(54, 162, 235, 0.2)",
219 | "borderColor": "rgba(54, 162, 235, 1)",
220 | "borderWidth": 1
221 | }
222 | ]
223 | }
224 | """
225 |
226 | let configJson = """
227 | {
228 | "type": "bar",
229 | "options": {
230 | "responsive": true,
231 | "plugins": {
232 | "title": {
233 | "display": true,
234 | "text": "ChartJS for Swift"
235 | }
236 | },
237 | "scales": {
238 | "y": {
239 | "beginAtZero": true
240 | }
241 | }
242 | }
243 | }
244 | """
245 |
246 | return GeometryReader { geometry in
247 | VStack{
248 | Charts(dataJson: dataJson, configJson: configJson)
249 | .frame(height: geometry.size.width > geometry.size.height ?
250 | geometry.size.height : // landscape
251 | geometry.size.height * 0.3) // portrait
252 | .padding()
253 | .frame(maxWidth: .infinity, maxHeight: .infinity)
254 |
255 | Charts(dataJson: dataJson2, configJson: configJson)
256 | .frame(height: geometry.size.width > geometry.size.height ?
257 | geometry.size.height : // landscape
258 | geometry.size.height * 0.3) // portrait
259 | .padding()
260 | .frame(maxWidth: .infinity, maxHeight: .infinity)
261 | }
262 | }
263 | }
264 |
--------------------------------------------------------------------------------
/ChartJS Demo/ChartJS Demo/Charts/Bar.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Bar.swift
3 | // ChartJS
4 | //
5 | // Created by Ming on 21/5/2025.
6 | //
7 |
8 | import SwiftUI
9 | import ChartJS
10 |
11 | #Preview("Border Radius Chart") {
12 | let dataJson = """
13 | {
14 | "labels": ["January", "February", "March", "April", "May", "June", "July"],
15 | "datasets": [
16 | {
17 | "label": "Fully Rounded",
18 | "data": [65, -59, 80, -81, 56, -55, 40],
19 | "borderColor": "rgb(255, 99, 132)",
20 | "backgroundColor": "rgba(255, 99, 132, 0.5)",
21 | "borderWidth": 2,
22 | "borderRadius": 999,
23 | "borderSkipped": false
24 | },
25 | {
26 | "label": "Small Radius",
27 | "data": [28, -48, 40, -19, 86, -27, 90],
28 | "borderColor": "rgb(54, 162, 235)",
29 | "backgroundColor": "rgba(54, 162, 235, 0.5)",
30 | "borderWidth": 2,
31 | "borderRadius": 5,
32 | "borderSkipped": false
33 | }
34 | ]
35 | }
36 | """
37 |
38 | let configJson = """
39 | {
40 | "type": "bar",
41 | "options": {
42 | "responsive": true,
43 | "plugins": {
44 | "legend": {
45 | "position": "top"
46 | },
47 | "title": {
48 | "display": true,
49 | "text": "Bar Chart Border Radius"
50 | }
51 | }
52 | }
53 | }
54 | """
55 |
56 | return GeometryReader { geometry in
57 | Charts(dataJson: dataJson, configJson: configJson)
58 | .frame(height: geometry.size.width > geometry.size.height ?
59 | geometry.size.height : // landscape
60 | geometry.size.height * 0.3) // portrait
61 | .padding()
62 | .frame(maxWidth: .infinity, maxHeight: .infinity)
63 | .position(x: geometry.size.width/2, y: geometry.size.height/2)
64 | }
65 | }
66 |
67 | #Preview("Floating Bar Chart") {
68 | let dataJson = """
69 | {
70 | "labels": ["January", "February", "March", "April", "May", "June", "July"],
71 | "datasets": [
72 | {
73 | "label": "Dataset 1",
74 | "data": [
75 | [-65, 30],
76 | [-25, 59],
77 | [-30, 80],
78 | [-10, 81],
79 | [-25, 56],
80 | [-45, 55],
81 | [-15, 40]
82 | ],
83 | "backgroundColor": "rgba(255, 99, 132, 0.5)"
84 | },
85 | {
86 | "label": "Dataset 2",
87 | "data": [
88 | [-45, 28],
89 | [-80, 48],
90 | [-25, 40],
91 | [-60, 19],
92 | [-15, 86],
93 | [-50, 27],
94 | [-30, 90]
95 | ],
96 | "backgroundColor": "rgba(54, 162, 235, 0.5)"
97 | }
98 | ]
99 | }
100 | """
101 |
102 | let configJson = """
103 | {
104 | "type": "bar",
105 | "options": {
106 | "responsive": true,
107 | "plugins": {
108 | "legend": {
109 | "position": "top"
110 | },
111 | "title": {
112 | "display": true,
113 | "text": "Chart.js Floating Bar Chart"
114 | }
115 | }
116 | }
117 | }
118 | """
119 |
120 | return GeometryReader { geometry in
121 | Charts(dataJson: dataJson, configJson: configJson)
122 | .frame(height: geometry.size.width > geometry.size.height ?
123 | geometry.size.height : // landscape
124 | geometry.size.height * 0.3) // portrait
125 | .padding()
126 | .frame(maxWidth: .infinity, maxHeight: .infinity)
127 | .position(x: geometry.size.width/2, y: geometry.size.height/2)
128 | }
129 | }
130 |
131 | #Preview("Horizontal Bar Chart") {
132 | let dataJson = """
133 | {
134 | "labels": ["January", "February", "March", "April", "May", "June", "July"],
135 | "datasets": [
136 | {
137 | "label": "Dataset 1",
138 | "data": [65, -59, 80, -81, 56, -55, 40],
139 | "borderColor": "rgb(255, 99, 132)",
140 | "backgroundColor": "rgba(255, 99, 132, 0.5)",
141 | "borderWidth": 2
142 | },
143 | {
144 | "label": "Dataset 2",
145 | "data": [28, -48, 40, -19, 86, -27, 90],
146 | "borderColor": "rgb(54, 162, 235)",
147 | "backgroundColor": "rgba(54, 162, 235, 0.5)",
148 | "borderWidth": 2
149 | }
150 | ]
151 | }
152 | """
153 |
154 | let configJson = """
155 | {
156 | "type": "bar",
157 | "options": {
158 | "indexAxis": "y",
159 | "elements": {
160 | "bar": {
161 | "borderWidth": 2
162 | }
163 | },
164 | "responsive": true,
165 | "plugins": {
166 | "legend": {
167 | "position": "right"
168 | },
169 | "title": {
170 | "display": true,
171 | "text": "Chart.js Horizontal Bar Chart"
172 | }
173 | }
174 | }
175 | }
176 | """
177 |
178 | return GeometryReader { geometry in
179 | Charts(dataJson: dataJson, configJson: configJson)
180 | .frame(height: geometry.size.width > geometry.size.height ?
181 | geometry.size.height : // landscape
182 | geometry.size.height * 0.3) // portrait
183 | .padding()
184 | .frame(maxWidth: .infinity, maxHeight: .infinity)
185 | .position(x: geometry.size.width/2, y: geometry.size.height/2)
186 | }
187 | }
188 |
189 | #Preview("Stacked Bar Chart") {
190 | let dataJson = """
191 | {
192 | "labels": ["January", "February", "March", "April", "May", "June", "July"],
193 | "datasets": [
194 | {
195 | "label": "Dataset 1",
196 | "data": [65, -59, 80, -81, 56, -55, 40],
197 | "backgroundColor": "rgb(255, 99, 132)"
198 | },
199 | {
200 | "label": "Dataset 2",
201 | "data": [28, -48, 40, -19, 86, -27, 90],
202 | "backgroundColor": "rgb(54, 162, 235)"
203 | },
204 | {
205 | "label": "Dataset 3",
206 | "data": [35, -25, 60, -35, 45, -40, 70],
207 | "backgroundColor": "rgb(75, 192, 192)"
208 | }
209 | ]
210 | }
211 | """
212 |
213 | let configJson = """
214 | {
215 | "type": "bar",
216 | "options": {
217 | "plugins": {
218 | "title": {
219 | "display": true,
220 | "text": "Chart.js Bar Chart - Stacked"
221 | }
222 | },
223 | "responsive": true,
224 | "scales": {
225 | "x": {
226 | "stacked": true
227 | },
228 | "y": {
229 | "stacked": true
230 | }
231 | }
232 | }
233 | }
234 | """
235 |
236 | return GeometryReader { geometry in
237 | Charts(dataJson: dataJson, configJson: configJson)
238 | .frame(height: geometry.size.width > geometry.size.height ?
239 | geometry.size.height : // landscape
240 | geometry.size.height * 0.3) // portrait
241 | .padding()
242 | .frame(maxWidth: .infinity, maxHeight: .infinity)
243 | .position(x: geometry.size.width/2, y: geometry.size.height/2)
244 | }
245 | }
246 |
247 | #Preview("Stacked Bar Chart with Groups") {
248 | let dataJson = """
249 | {
250 | "labels": ["January", "February", "March", "April", "May", "June", "July"],
251 | "datasets": [
252 | {
253 | "label": "Dataset 1",
254 | "data": [65, -59, 80, -81, 56, -55, 40],
255 | "backgroundColor": "rgb(255, 99, 132)",
256 | "stack": "Stack 0"
257 | },
258 | {
259 | "label": "Dataset 2",
260 | "data": [28, -48, 40, -19, 86, -27, 90],
261 | "backgroundColor": "rgb(54, 162, 235)",
262 | "stack": "Stack 0"
263 | },
264 | {
265 | "label": "Dataset 3",
266 | "data": [35, -25, 60, -35, 45, -40, 70],
267 | "backgroundColor": "rgb(75, 192, 192)",
268 | "stack": "Stack 1"
269 | }
270 | ]
271 | }
272 | """
273 |
274 | let configJson = """
275 | {
276 | "type": "bar",
277 | "options": {
278 | "plugins": {
279 | "title": {
280 | "display": true,
281 | "text": "Chart.js Bar Chart - Stacked with Groups"
282 | }
283 | },
284 | "responsive": true,
285 | "interaction": {
286 | "intersect": false
287 | },
288 | "scales": {
289 | "x": {
290 | "stacked": true
291 | },
292 | "y": {
293 | "stacked": true
294 | }
295 | }
296 | }
297 | }
298 | """
299 |
300 | return GeometryReader { geometry in
301 | Charts(dataJson: dataJson, configJson: configJson)
302 | .frame(height: geometry.size.width > geometry.size.height ?
303 | geometry.size.height : // landscape
304 | geometry.size.height * 0.3) // portrait
305 | .padding()
306 | .frame(maxWidth: .infinity, maxHeight: .infinity)
307 | .position(x: geometry.size.width/2, y: geometry.size.height/2)
308 | }
309 | }
310 |
311 | #Preview("Vertical Bar Chart") {
312 | let dataJson = """
313 | {
314 | "labels": ["January", "February", "March", "April", "May", "June", "July"],
315 | "datasets": [
316 | {
317 | "label": "Dataset 1",
318 | "data": [65, -59, 80, -81, 56, -55, 40],
319 | "borderColor": "rgb(255, 99, 132)",
320 | "backgroundColor": "rgba(255, 99, 132, 0.5)"
321 | },
322 | {
323 | "label": "Dataset 2",
324 | "data": [28, -48, 40, -19, 86, -27, 90],
325 | "borderColor": "rgb(54, 162, 235)",
326 | "backgroundColor": "rgba(54, 162, 235, 0.5)"
327 | }
328 | ]
329 | }
330 | """
331 |
332 | let configJson = """
333 | {
334 | "type": "bar",
335 | "options": {
336 | "responsive": true,
337 | "plugins": {
338 | "legend": {
339 | "position": "top"
340 | },
341 | "title": {
342 | "display": true,
343 | "text": "Chart.js Bar Chart"
344 | }
345 | }
346 | }
347 | }
348 | """
349 |
350 | return GeometryReader { geometry in
351 | Charts(dataJson: dataJson, configJson: configJson)
352 | .frame(height: geometry.size.width > geometry.size.height ?
353 | geometry.size.height : // landscape
354 | geometry.size.height * 0.3) // portrait
355 | .padding()
356 | .frame(maxWidth: .infinity, maxHeight: .infinity)
357 | .position(x: geometry.size.width/2, y: geometry.size.height/2)
358 | }
359 | }
360 |
--------------------------------------------------------------------------------
/ChartJS Demo/ChartJS Demo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 77;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 3A988AE92DDE12BD00632266 /* ChartJS in Frameworks */ = {isa = PBXBuildFile; productRef = 3A988AE82DDE12BD00632266 /* ChartJS */; };
11 | 3A988AEC2DDE12FA00632266 /* ChartJS in Frameworks */ = {isa = PBXBuildFile; productRef = 3A988AEB2DDE12FA00632266 /* ChartJS */; };
12 | 3A988B0A2DDE193200632266 /* ChartJS in Frameworks */ = {isa = PBXBuildFile; productRef = 3A988B092DDE193200632266 /* ChartJS */; };
13 | /* End PBXBuildFile section */
14 |
15 | /* Begin PBXContainerItemProxy section */
16 | 3A988ACB2DDE12AB00632266 /* PBXContainerItemProxy */ = {
17 | isa = PBXContainerItemProxy;
18 | containerPortal = 3A988AB42DDE12A900632266 /* Project object */;
19 | proxyType = 1;
20 | remoteGlobalIDString = 3A988ABB2DDE12A900632266;
21 | remoteInfo = "ChartJS Demo";
22 | };
23 | 3A988AD52DDE12AB00632266 /* PBXContainerItemProxy */ = {
24 | isa = PBXContainerItemProxy;
25 | containerPortal = 3A988AB42DDE12A900632266 /* Project object */;
26 | proxyType = 1;
27 | remoteGlobalIDString = 3A988ABB2DDE12A900632266;
28 | remoteInfo = "ChartJS Demo";
29 | };
30 | /* End PBXContainerItemProxy section */
31 |
32 | /* Begin PBXFileReference section */
33 | 3A988ABC2DDE12A900632266 /* ChartJS Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ChartJS Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; };
34 | 3A988ACA2DDE12AB00632266 /* ChartJS DemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "ChartJS DemoTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
35 | 3A988AD42DDE12AB00632266 /* ChartJS DemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "ChartJS DemoUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
36 | /* End PBXFileReference section */
37 |
38 | /* Begin PBXFileSystemSynchronizedRootGroup section */
39 | 3A988ABE2DDE12A900632266 /* ChartJS Demo */ = {
40 | isa = PBXFileSystemSynchronizedRootGroup;
41 | path = "ChartJS Demo";
42 | sourceTree = "";
43 | };
44 | 3A988ACD2DDE12AB00632266 /* ChartJS DemoTests */ = {
45 | isa = PBXFileSystemSynchronizedRootGroup;
46 | path = "ChartJS DemoTests";
47 | sourceTree = "";
48 | };
49 | 3A988AD72DDE12AB00632266 /* ChartJS DemoUITests */ = {
50 | isa = PBXFileSystemSynchronizedRootGroup;
51 | path = "ChartJS DemoUITests";
52 | sourceTree = "";
53 | };
54 | /* End PBXFileSystemSynchronizedRootGroup section */
55 |
56 | /* Begin PBXFrameworksBuildPhase section */
57 | 3A988AB92DDE12A900632266 /* Frameworks */ = {
58 | isa = PBXFrameworksBuildPhase;
59 | buildActionMask = 2147483647;
60 | files = (
61 | 3A988B0A2DDE193200632266 /* ChartJS in Frameworks */,
62 | 3A988AEC2DDE12FA00632266 /* ChartJS in Frameworks */,
63 | 3A988AE92DDE12BD00632266 /* ChartJS in Frameworks */,
64 | );
65 | runOnlyForDeploymentPostprocessing = 0;
66 | };
67 | 3A988AC72DDE12AB00632266 /* Frameworks */ = {
68 | isa = PBXFrameworksBuildPhase;
69 | buildActionMask = 2147483647;
70 | files = (
71 | );
72 | runOnlyForDeploymentPostprocessing = 0;
73 | };
74 | 3A988AD12DDE12AB00632266 /* Frameworks */ = {
75 | isa = PBXFrameworksBuildPhase;
76 | buildActionMask = 2147483647;
77 | files = (
78 | );
79 | runOnlyForDeploymentPostprocessing = 0;
80 | };
81 | /* End PBXFrameworksBuildPhase section */
82 |
83 | /* Begin PBXGroup section */
84 | 3A988AB32DDE12A900632266 = {
85 | isa = PBXGroup;
86 | children = (
87 | 3A988ABE2DDE12A900632266 /* ChartJS Demo */,
88 | 3A988ACD2DDE12AB00632266 /* ChartJS DemoTests */,
89 | 3A988AD72DDE12AB00632266 /* ChartJS DemoUITests */,
90 | 3A988ABD2DDE12A900632266 /* Products */,
91 | );
92 | sourceTree = "";
93 | };
94 | 3A988ABD2DDE12A900632266 /* Products */ = {
95 | isa = PBXGroup;
96 | children = (
97 | 3A988ABC2DDE12A900632266 /* ChartJS Demo.app */,
98 | 3A988ACA2DDE12AB00632266 /* ChartJS DemoTests.xctest */,
99 | 3A988AD42DDE12AB00632266 /* ChartJS DemoUITests.xctest */,
100 | );
101 | name = Products;
102 | sourceTree = "";
103 | };
104 | /* End PBXGroup section */
105 |
106 | /* Begin PBXNativeTarget section */
107 | 3A988ABB2DDE12A900632266 /* ChartJS Demo */ = {
108 | isa = PBXNativeTarget;
109 | buildConfigurationList = 3A988ADE2DDE12AB00632266 /* Build configuration list for PBXNativeTarget "ChartJS Demo" */;
110 | buildPhases = (
111 | 3A988AB82DDE12A900632266 /* Sources */,
112 | 3A988AB92DDE12A900632266 /* Frameworks */,
113 | 3A988ABA2DDE12A900632266 /* Resources */,
114 | );
115 | buildRules = (
116 | );
117 | dependencies = (
118 | );
119 | fileSystemSynchronizedGroups = (
120 | 3A988ABE2DDE12A900632266 /* ChartJS Demo */,
121 | );
122 | name = "ChartJS Demo";
123 | packageProductDependencies = (
124 | 3A988AE82DDE12BD00632266 /* ChartJS */,
125 | 3A988AEB2DDE12FA00632266 /* ChartJS */,
126 | 3A988B092DDE193200632266 /* ChartJS */,
127 | );
128 | productName = "ChartJS Demo";
129 | productReference = 3A988ABC2DDE12A900632266 /* ChartJS Demo.app */;
130 | productType = "com.apple.product-type.application";
131 | };
132 | 3A988AC92DDE12AB00632266 /* ChartJS DemoTests */ = {
133 | isa = PBXNativeTarget;
134 | buildConfigurationList = 3A988AE12DDE12AB00632266 /* Build configuration list for PBXNativeTarget "ChartJS DemoTests" */;
135 | buildPhases = (
136 | 3A988AC62DDE12AB00632266 /* Sources */,
137 | 3A988AC72DDE12AB00632266 /* Frameworks */,
138 | 3A988AC82DDE12AB00632266 /* Resources */,
139 | );
140 | buildRules = (
141 | );
142 | dependencies = (
143 | 3A988ACC2DDE12AB00632266 /* PBXTargetDependency */,
144 | );
145 | fileSystemSynchronizedGroups = (
146 | 3A988ACD2DDE12AB00632266 /* ChartJS DemoTests */,
147 | );
148 | name = "ChartJS DemoTests";
149 | packageProductDependencies = (
150 | );
151 | productName = "ChartJS DemoTests";
152 | productReference = 3A988ACA2DDE12AB00632266 /* ChartJS DemoTests.xctest */;
153 | productType = "com.apple.product-type.bundle.unit-test";
154 | };
155 | 3A988AD32DDE12AB00632266 /* ChartJS DemoUITests */ = {
156 | isa = PBXNativeTarget;
157 | buildConfigurationList = 3A988AE42DDE12AB00632266 /* Build configuration list for PBXNativeTarget "ChartJS DemoUITests" */;
158 | buildPhases = (
159 | 3A988AD02DDE12AB00632266 /* Sources */,
160 | 3A988AD12DDE12AB00632266 /* Frameworks */,
161 | 3A988AD22DDE12AB00632266 /* Resources */,
162 | );
163 | buildRules = (
164 | );
165 | dependencies = (
166 | 3A988AD62DDE12AB00632266 /* PBXTargetDependency */,
167 | );
168 | fileSystemSynchronizedGroups = (
169 | 3A988AD72DDE12AB00632266 /* ChartJS DemoUITests */,
170 | );
171 | name = "ChartJS DemoUITests";
172 | packageProductDependencies = (
173 | );
174 | productName = "ChartJS DemoUITests";
175 | productReference = 3A988AD42DDE12AB00632266 /* ChartJS DemoUITests.xctest */;
176 | productType = "com.apple.product-type.bundle.ui-testing";
177 | };
178 | /* End PBXNativeTarget section */
179 |
180 | /* Begin PBXProject section */
181 | 3A988AB42DDE12A900632266 /* Project object */ = {
182 | isa = PBXProject;
183 | attributes = {
184 | BuildIndependentTargetsInParallel = 1;
185 | LastSwiftUpdateCheck = 1630;
186 | LastUpgradeCheck = 1630;
187 | TargetAttributes = {
188 | 3A988ABB2DDE12A900632266 = {
189 | CreatedOnToolsVersion = 16.3;
190 | };
191 | 3A988AC92DDE12AB00632266 = {
192 | CreatedOnToolsVersion = 16.3;
193 | TestTargetID = 3A988ABB2DDE12A900632266;
194 | };
195 | 3A988AD32DDE12AB00632266 = {
196 | CreatedOnToolsVersion = 16.3;
197 | TestTargetID = 3A988ABB2DDE12A900632266;
198 | };
199 | };
200 | };
201 | buildConfigurationList = 3A988AB72DDE12A900632266 /* Build configuration list for PBXProject "ChartJS Demo" */;
202 | developmentRegion = en;
203 | hasScannedForEncodings = 0;
204 | knownRegions = (
205 | en,
206 | Base,
207 | );
208 | mainGroup = 3A988AB32DDE12A900632266;
209 | minimizedProjectReferenceProxies = 1;
210 | packageReferences = (
211 | 3A988B082DDE193200632266 /* XCLocalSwiftPackageReference "../../ChartJS-for-Swift" */,
212 | );
213 | preferredProjectObjectVersion = 77;
214 | productRefGroup = 3A988ABD2DDE12A900632266 /* Products */;
215 | projectDirPath = "";
216 | projectRoot = "";
217 | targets = (
218 | 3A988ABB2DDE12A900632266 /* ChartJS Demo */,
219 | 3A988AC92DDE12AB00632266 /* ChartJS DemoTests */,
220 | 3A988AD32DDE12AB00632266 /* ChartJS DemoUITests */,
221 | );
222 | };
223 | /* End PBXProject section */
224 |
225 | /* Begin PBXResourcesBuildPhase section */
226 | 3A988ABA2DDE12A900632266 /* Resources */ = {
227 | isa = PBXResourcesBuildPhase;
228 | buildActionMask = 2147483647;
229 | files = (
230 | );
231 | runOnlyForDeploymentPostprocessing = 0;
232 | };
233 | 3A988AC82DDE12AB00632266 /* Resources */ = {
234 | isa = PBXResourcesBuildPhase;
235 | buildActionMask = 2147483647;
236 | files = (
237 | );
238 | runOnlyForDeploymentPostprocessing = 0;
239 | };
240 | 3A988AD22DDE12AB00632266 /* Resources */ = {
241 | isa = PBXResourcesBuildPhase;
242 | buildActionMask = 2147483647;
243 | files = (
244 | );
245 | runOnlyForDeploymentPostprocessing = 0;
246 | };
247 | /* End PBXResourcesBuildPhase section */
248 |
249 | /* Begin PBXSourcesBuildPhase section */
250 | 3A988AB82DDE12A900632266 /* Sources */ = {
251 | isa = PBXSourcesBuildPhase;
252 | buildActionMask = 2147483647;
253 | files = (
254 | );
255 | runOnlyForDeploymentPostprocessing = 0;
256 | };
257 | 3A988AC62DDE12AB00632266 /* Sources */ = {
258 | isa = PBXSourcesBuildPhase;
259 | buildActionMask = 2147483647;
260 | files = (
261 | );
262 | runOnlyForDeploymentPostprocessing = 0;
263 | };
264 | 3A988AD02DDE12AB00632266 /* Sources */ = {
265 | isa = PBXSourcesBuildPhase;
266 | buildActionMask = 2147483647;
267 | files = (
268 | );
269 | runOnlyForDeploymentPostprocessing = 0;
270 | };
271 | /* End PBXSourcesBuildPhase section */
272 |
273 | /* Begin PBXTargetDependency section */
274 | 3A988ACC2DDE12AB00632266 /* PBXTargetDependency */ = {
275 | isa = PBXTargetDependency;
276 | target = 3A988ABB2DDE12A900632266 /* ChartJS Demo */;
277 | targetProxy = 3A988ACB2DDE12AB00632266 /* PBXContainerItemProxy */;
278 | };
279 | 3A988AD62DDE12AB00632266 /* PBXTargetDependency */ = {
280 | isa = PBXTargetDependency;
281 | target = 3A988ABB2DDE12A900632266 /* ChartJS Demo */;
282 | targetProxy = 3A988AD52DDE12AB00632266 /* PBXContainerItemProxy */;
283 | };
284 | /* End PBXTargetDependency section */
285 |
286 | /* Begin XCBuildConfiguration section */
287 | 3A988ADC2DDE12AB00632266 /* Debug */ = {
288 | isa = XCBuildConfiguration;
289 | buildSettings = {
290 | ALWAYS_SEARCH_USER_PATHS = NO;
291 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
292 | CLANG_ANALYZER_NONNULL = YES;
293 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
294 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
295 | CLANG_ENABLE_MODULES = YES;
296 | CLANG_ENABLE_OBJC_ARC = YES;
297 | CLANG_ENABLE_OBJC_WEAK = YES;
298 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
299 | CLANG_WARN_BOOL_CONVERSION = YES;
300 | CLANG_WARN_COMMA = YES;
301 | CLANG_WARN_CONSTANT_CONVERSION = YES;
302 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
303 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
304 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
305 | CLANG_WARN_EMPTY_BODY = YES;
306 | CLANG_WARN_ENUM_CONVERSION = YES;
307 | CLANG_WARN_INFINITE_RECURSION = YES;
308 | CLANG_WARN_INT_CONVERSION = YES;
309 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
310 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
311 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
312 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
313 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
314 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
315 | CLANG_WARN_STRICT_PROTOTYPES = YES;
316 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
317 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
318 | CLANG_WARN_UNREACHABLE_CODE = YES;
319 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
320 | COPY_PHASE_STRIP = NO;
321 | DEBUG_INFORMATION_FORMAT = dwarf;
322 | ENABLE_STRICT_OBJC_MSGSEND = YES;
323 | ENABLE_TESTABILITY = YES;
324 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
325 | GCC_C_LANGUAGE_STANDARD = gnu17;
326 | GCC_DYNAMIC_NO_PIC = NO;
327 | GCC_NO_COMMON_BLOCKS = YES;
328 | GCC_OPTIMIZATION_LEVEL = 0;
329 | GCC_PREPROCESSOR_DEFINITIONS = (
330 | "DEBUG=1",
331 | "$(inherited)",
332 | );
333 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
334 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
335 | GCC_WARN_UNDECLARED_SELECTOR = YES;
336 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
337 | GCC_WARN_UNUSED_FUNCTION = YES;
338 | GCC_WARN_UNUSED_VARIABLE = YES;
339 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
340 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
341 | MTL_FAST_MATH = YES;
342 | ONLY_ACTIVE_ARCH = YES;
343 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
344 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
345 | };
346 | name = Debug;
347 | };
348 | 3A988ADD2DDE12AB00632266 /* Release */ = {
349 | isa = XCBuildConfiguration;
350 | buildSettings = {
351 | ALWAYS_SEARCH_USER_PATHS = NO;
352 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
353 | CLANG_ANALYZER_NONNULL = YES;
354 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
355 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
356 | CLANG_ENABLE_MODULES = YES;
357 | CLANG_ENABLE_OBJC_ARC = YES;
358 | CLANG_ENABLE_OBJC_WEAK = YES;
359 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
360 | CLANG_WARN_BOOL_CONVERSION = YES;
361 | CLANG_WARN_COMMA = YES;
362 | CLANG_WARN_CONSTANT_CONVERSION = YES;
363 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
364 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
365 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
366 | CLANG_WARN_EMPTY_BODY = YES;
367 | CLANG_WARN_ENUM_CONVERSION = YES;
368 | CLANG_WARN_INFINITE_RECURSION = YES;
369 | CLANG_WARN_INT_CONVERSION = YES;
370 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
371 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
372 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
373 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
374 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
375 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
376 | CLANG_WARN_STRICT_PROTOTYPES = YES;
377 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
378 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
379 | CLANG_WARN_UNREACHABLE_CODE = YES;
380 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
381 | COPY_PHASE_STRIP = NO;
382 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
383 | ENABLE_NS_ASSERTIONS = NO;
384 | ENABLE_STRICT_OBJC_MSGSEND = YES;
385 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
386 | GCC_C_LANGUAGE_STANDARD = gnu17;
387 | GCC_NO_COMMON_BLOCKS = YES;
388 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
389 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
390 | GCC_WARN_UNDECLARED_SELECTOR = YES;
391 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
392 | GCC_WARN_UNUSED_FUNCTION = YES;
393 | GCC_WARN_UNUSED_VARIABLE = YES;
394 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
395 | MTL_ENABLE_DEBUG_INFO = NO;
396 | MTL_FAST_MATH = YES;
397 | SWIFT_COMPILATION_MODE = wholemodule;
398 | };
399 | name = Release;
400 | };
401 | 3A988ADF2DDE12AB00632266 /* Debug */ = {
402 | isa = XCBuildConfiguration;
403 | buildSettings = {
404 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
405 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
406 | CODE_SIGN_ENTITLEMENTS = "ChartJS Demo/ChartJS_Demo.entitlements";
407 | CODE_SIGN_STYLE = Automatic;
408 | CURRENT_PROJECT_VERSION = 1;
409 | ENABLE_PREVIEWS = YES;
410 | GENERATE_INFOPLIST_FILE = YES;
411 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
412 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
413 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
414 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES;
415 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES;
416 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES;
417 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault;
418 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
419 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
420 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
421 | IPHONEOS_DEPLOYMENT_TARGET = 18.4;
422 | LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
423 | "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
424 | MACOSX_DEPLOYMENT_TARGET = 15.4;
425 | MARKETING_VERSION = 1.0;
426 | PRODUCT_BUNDLE_IDENTIFIER = "media.1998.ChartJS-Demo";
427 | PRODUCT_NAME = "$(TARGET_NAME)";
428 | REGISTER_APP_GROUPS = YES;
429 | SDKROOT = auto;
430 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
431 | SWIFT_EMIT_LOC_STRINGS = YES;
432 | SWIFT_VERSION = 5.0;
433 | TARGETED_DEVICE_FAMILY = "1,2,7";
434 | XROS_DEPLOYMENT_TARGET = 2.4;
435 | };
436 | name = Debug;
437 | };
438 | 3A988AE02DDE12AB00632266 /* Release */ = {
439 | isa = XCBuildConfiguration;
440 | buildSettings = {
441 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
442 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
443 | CODE_SIGN_ENTITLEMENTS = "ChartJS Demo/ChartJS_Demo.entitlements";
444 | CODE_SIGN_STYLE = Automatic;
445 | CURRENT_PROJECT_VERSION = 1;
446 | ENABLE_PREVIEWS = YES;
447 | GENERATE_INFOPLIST_FILE = YES;
448 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
449 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
450 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
451 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES;
452 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES;
453 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES;
454 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault;
455 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
456 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
457 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
458 | IPHONEOS_DEPLOYMENT_TARGET = 18.4;
459 | LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
460 | "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
461 | MACOSX_DEPLOYMENT_TARGET = 15.4;
462 | MARKETING_VERSION = 1.0;
463 | PRODUCT_BUNDLE_IDENTIFIER = "media.1998.ChartJS-Demo";
464 | PRODUCT_NAME = "$(TARGET_NAME)";
465 | REGISTER_APP_GROUPS = YES;
466 | SDKROOT = auto;
467 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
468 | SWIFT_EMIT_LOC_STRINGS = YES;
469 | SWIFT_VERSION = 5.0;
470 | TARGETED_DEVICE_FAMILY = "1,2,7";
471 | XROS_DEPLOYMENT_TARGET = 2.4;
472 | };
473 | name = Release;
474 | };
475 | 3A988AE22DDE12AB00632266 /* Debug */ = {
476 | isa = XCBuildConfiguration;
477 | buildSettings = {
478 | BUNDLE_LOADER = "$(TEST_HOST)";
479 | CODE_SIGN_STYLE = Automatic;
480 | CURRENT_PROJECT_VERSION = 1;
481 | GENERATE_INFOPLIST_FILE = YES;
482 | IPHONEOS_DEPLOYMENT_TARGET = 18.4;
483 | MACOSX_DEPLOYMENT_TARGET = 15.4;
484 | MARKETING_VERSION = 1.0;
485 | PRODUCT_BUNDLE_IDENTIFIER = "media.1998.ChartJS-DemoTests";
486 | PRODUCT_NAME = "$(TARGET_NAME)";
487 | SDKROOT = auto;
488 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
489 | SWIFT_EMIT_LOC_STRINGS = NO;
490 | SWIFT_VERSION = 5.0;
491 | TARGETED_DEVICE_FAMILY = "1,2,7";
492 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ChartJS Demo.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/ChartJS Demo";
493 | XROS_DEPLOYMENT_TARGET = 2.4;
494 | };
495 | name = Debug;
496 | };
497 | 3A988AE32DDE12AB00632266 /* Release */ = {
498 | isa = XCBuildConfiguration;
499 | buildSettings = {
500 | BUNDLE_LOADER = "$(TEST_HOST)";
501 | CODE_SIGN_STYLE = Automatic;
502 | CURRENT_PROJECT_VERSION = 1;
503 | GENERATE_INFOPLIST_FILE = YES;
504 | IPHONEOS_DEPLOYMENT_TARGET = 18.4;
505 | MACOSX_DEPLOYMENT_TARGET = 15.4;
506 | MARKETING_VERSION = 1.0;
507 | PRODUCT_BUNDLE_IDENTIFIER = "media.1998.ChartJS-DemoTests";
508 | PRODUCT_NAME = "$(TARGET_NAME)";
509 | SDKROOT = auto;
510 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
511 | SWIFT_EMIT_LOC_STRINGS = NO;
512 | SWIFT_VERSION = 5.0;
513 | TARGETED_DEVICE_FAMILY = "1,2,7";
514 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ChartJS Demo.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/ChartJS Demo";
515 | XROS_DEPLOYMENT_TARGET = 2.4;
516 | };
517 | name = Release;
518 | };
519 | 3A988AE52DDE12AB00632266 /* Debug */ = {
520 | isa = XCBuildConfiguration;
521 | buildSettings = {
522 | CODE_SIGN_STYLE = Automatic;
523 | CURRENT_PROJECT_VERSION = 1;
524 | GENERATE_INFOPLIST_FILE = YES;
525 | IPHONEOS_DEPLOYMENT_TARGET = 18.4;
526 | MACOSX_DEPLOYMENT_TARGET = 15.4;
527 | MARKETING_VERSION = 1.0;
528 | PRODUCT_BUNDLE_IDENTIFIER = "media.1998.ChartJS-DemoUITests";
529 | PRODUCT_NAME = "$(TARGET_NAME)";
530 | SDKROOT = auto;
531 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
532 | SWIFT_EMIT_LOC_STRINGS = NO;
533 | SWIFT_VERSION = 5.0;
534 | TARGETED_DEVICE_FAMILY = "1,2,7";
535 | TEST_TARGET_NAME = "ChartJS Demo";
536 | XROS_DEPLOYMENT_TARGET = 2.4;
537 | };
538 | name = Debug;
539 | };
540 | 3A988AE62DDE12AB00632266 /* Release */ = {
541 | isa = XCBuildConfiguration;
542 | buildSettings = {
543 | CODE_SIGN_STYLE = Automatic;
544 | CURRENT_PROJECT_VERSION = 1;
545 | GENERATE_INFOPLIST_FILE = YES;
546 | IPHONEOS_DEPLOYMENT_TARGET = 18.4;
547 | MACOSX_DEPLOYMENT_TARGET = 15.4;
548 | MARKETING_VERSION = 1.0;
549 | PRODUCT_BUNDLE_IDENTIFIER = "media.1998.ChartJS-DemoUITests";
550 | PRODUCT_NAME = "$(TARGET_NAME)";
551 | SDKROOT = auto;
552 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
553 | SWIFT_EMIT_LOC_STRINGS = NO;
554 | SWIFT_VERSION = 5.0;
555 | TARGETED_DEVICE_FAMILY = "1,2,7";
556 | TEST_TARGET_NAME = "ChartJS Demo";
557 | XROS_DEPLOYMENT_TARGET = 2.4;
558 | };
559 | name = Release;
560 | };
561 | /* End XCBuildConfiguration section */
562 |
563 | /* Begin XCConfigurationList section */
564 | 3A988AB72DDE12A900632266 /* Build configuration list for PBXProject "ChartJS Demo" */ = {
565 | isa = XCConfigurationList;
566 | buildConfigurations = (
567 | 3A988ADC2DDE12AB00632266 /* Debug */,
568 | 3A988ADD2DDE12AB00632266 /* Release */,
569 | );
570 | defaultConfigurationIsVisible = 0;
571 | defaultConfigurationName = Release;
572 | };
573 | 3A988ADE2DDE12AB00632266 /* Build configuration list for PBXNativeTarget "ChartJS Demo" */ = {
574 | isa = XCConfigurationList;
575 | buildConfigurations = (
576 | 3A988ADF2DDE12AB00632266 /* Debug */,
577 | 3A988AE02DDE12AB00632266 /* Release */,
578 | );
579 | defaultConfigurationIsVisible = 0;
580 | defaultConfigurationName = Release;
581 | };
582 | 3A988AE12DDE12AB00632266 /* Build configuration list for PBXNativeTarget "ChartJS DemoTests" */ = {
583 | isa = XCConfigurationList;
584 | buildConfigurations = (
585 | 3A988AE22DDE12AB00632266 /* Debug */,
586 | 3A988AE32DDE12AB00632266 /* Release */,
587 | );
588 | defaultConfigurationIsVisible = 0;
589 | defaultConfigurationName = Release;
590 | };
591 | 3A988AE42DDE12AB00632266 /* Build configuration list for PBXNativeTarget "ChartJS DemoUITests" */ = {
592 | isa = XCConfigurationList;
593 | buildConfigurations = (
594 | 3A988AE52DDE12AB00632266 /* Debug */,
595 | 3A988AE62DDE12AB00632266 /* Release */,
596 | );
597 | defaultConfigurationIsVisible = 0;
598 | defaultConfigurationName = Release;
599 | };
600 | /* End XCConfigurationList section */
601 |
602 | /* Begin XCLocalSwiftPackageReference section */
603 | 3A988B082DDE193200632266 /* XCLocalSwiftPackageReference "../../ChartJS-for-Swift" */ = {
604 | isa = XCLocalSwiftPackageReference;
605 | relativePath = "../../ChartJS-for-Swift";
606 | };
607 | /* End XCLocalSwiftPackageReference section */
608 |
609 | /* Begin XCSwiftPackageProductDependency section */
610 | 3A988AE82DDE12BD00632266 /* ChartJS */ = {
611 | isa = XCSwiftPackageProductDependency;
612 | productName = ChartJS;
613 | };
614 | 3A988AEB2DDE12FA00632266 /* ChartJS */ = {
615 | isa = XCSwiftPackageProductDependency;
616 | productName = ChartJS;
617 | };
618 | 3A988B092DDE193200632266 /* ChartJS */ = {
619 | isa = XCSwiftPackageProductDependency;
620 | productName = ChartJS;
621 | };
622 | /* End XCSwiftPackageProductDependency section */
623 | };
624 | rootObject = 3A988AB42DDE12A900632266 /* Project object */;
625 | }
626 |
--------------------------------------------------------------------------------