Skip to content

Instantly share code, notes, and snippets.

@dabbott
Last active July 8, 2020 16:46
Show Gist options
  • Save dabbott/139549a580bcc86b0d097bfb4ef460e6 to your computer and use it in GitHub Desktop.
Save dabbott/139549a580bcc86b0d097bfb4ef460e6 to your computer and use it in GitHub Desktop.
Native Chart Example
package com.priceexplorer
import android.content.Context
import android.graphics.*
import android.util.DisplayMetrics
import android.view.View
class ChartView(context: Context?) : View(context) {
var strokeWidth = 1f
var minimumValue = 0
var maximumValue = 200
var strokeColor = Color.BLACK
var data = FloatArray(0)
set(value) {
field = normalizeData(value)
}
private val stroke = Paint()
private val metrics: DisplayMetrics = resources.displayMetrics
override fun draw(canvas: Canvas) {
super.draw(canvas)
stroke.strokeWidth = strokeWidth * metrics.density
stroke.color = strokeColor
val path = Path()
if (data.size < 2) return
val xStep: Float = width / (data.size - 1).toFloat()
val points = data.mapIndexed { x, y ->
PointF(
x.toFloat() * xStep,
height * (y - minimumValue) / (maximumValue - minimumValue)
)
}
path.moveTo(points[0].x, points[0].y)
for (index in 1 until points.size) {
path.lineTo(points[index].x, points[index].y)
}
canvas.drawPath(path, stroke)
}
init {
stroke.isAntiAlias = true
stroke.isDither = true
stroke.style = Paint.Style.STROKE
}
}
fun normalizeData(input: FloatArray): FloatArray {
val pointCount: Int = 100
val output: ArrayList<Float> = ArrayList()
if (input.isEmpty()) return output.toFloatArray()
if (input.size > pointCount) {
var ratio = input.size / pointCount
input.forEachIndexed { index, point ->
if (index % ratio == 0) {
output.add(point)
}
}
} else {
var ratio = pointCount / input.size
input.forEach { point ->
for (i in 0 until ratio) {
output.add(point)
}
}
}
return output.toFloatArray()
}
//
// ChartView.swift
// PriceExplorer
//
// Created by Devin Abbott on 6/16/20.
//
import Foundation
import UIKit
class ChartView: UIView {
// MARK: Bridged
@objc var minimumValue: CGFloat = 0
@objc var maximumValue: CGFloat = 200
@objc var data: NSArray = [] {
didSet {
let rawPoints = data.map({ item in (item as? CGFloat) ?? 0 })
self.yPoint = normalizeData(rawPoints)
}
}
@objc var strokeWidth: CGFloat = 1 {
didSet {
shapeLayer.lineWidth = strokeWidth
}
}
@objc var strokeColor: UIColor = UIColor.black {
didSet {
shapeLayer.strokeColor = strokeColor.cgColor
}
}
// MARK: Private
private let shapeLayer = CAShapeLayer()
private var yPoint: [CGFloat] = []
// MARK: Lifecycle
override init(frame: CGRect) {
super.init(frame: frame)
setUp()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setUp()
}
func setUp() {
shapeLayer.strokeColor = strokeColor.cgColor
shapeLayer.lineWidth = strokeWidth
shapeLayer.fillColor = nil
shapeLayer.lineCap = .round
shapeLayer.lineJoin = .round
layer.addSublayer(shapeLayer)
}
override func layoutSubviews() {
updatePath()
}
override func didSetProps(_ changedProps: [String]!) {
updatePath()
}
// MARK: Path & Animation
private func updatePath() {
if bounds.height <= 0 { return }
let nextPath = makePath()
if shapeLayer.path == nil {
shapeLayer.path = nextPath
} else {
animate(toPath: nextPath)
}
}
func makePath() -> CGPath {
let path = UIBezierPath()
if yPoint.count < 2 { return path.cgPath }
let xStep: CGFloat = bounds.width / CGFloat(yPoint.count - 1)
let points: [CGPoint] = yPoint.enumerated().map { (x, y) in
CGPoint(
x: CGFloat(x) * xStep,
y: bounds.height * (y - minimumValue) / (maximumValue - minimumValue)
)
}
path.move(to: points[0])
for point in points[1..<points.count] {
path.addLine(to: point)
}
return path.cgPath
}
func animate(toPath: CGPath) {
let animation = CABasicAnimation(keyPath: "path")
animation.toValue = toPath
animation.duration = 0.2
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut)
animation.delegate = self
animation.isRemovedOnCompletion = false
animation.fillMode = .forwards
shapeLayer.add(animation, forKey: animation.keyPath)
}
}
extension ChartView: CAAnimationDelegate {
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
if let presentationLayer = shapeLayer.presentation() {
shapeLayer.path = presentationLayer.path
}
}
}
/**
Interpolate or extrapolate data so that we have about 100 points
*/
func normalizeData(_ input: [CGFloat]) -> [CGFloat] {
let pointCount = 100
var output: [CGFloat] = []
if input.isEmpty { return output }
if input.count > pointCount {
let ratio = input.count / pointCount
input.enumerated().forEach({ (offset, point) in
if (offset % ratio == 0) {
output.append(point)
}
})
} else {
let ratio = pointCount / input.count
input.enumerated().forEach({ (offset, point) in
for _ in 0..<ratio {
output.append(point)
}
})
}
return output
}
export type Currency = {
id: string;
name: string;
symbol: string;
rank: number;
usd: number;
icon: string;
};
export type HistoricalPrice = {
usd: number;
};
export function currencies(): Currency[] {
return data;
}
export function getCurrency(id: string): Currency | undefined {
return currencies().find((currency) => currency.id === id);
}
export function getHistory(id: string): HistoricalPrice[] {
return history;
}
const data: Currency[] = [
{
id: 'NzcucMqj2',
icon:
'https://unpkg.com/cryptocurrency-icons@0.16.1/32@2x/color/btc@2x.png',
name: 'Bitcoin',
rank: 1,
symbol: 'BTC',
usd: 10403.225432572899,
},
{
id: 'UNB33kmPvl',
icon:
'https://unpkg.com/cryptocurrency-icons@0.16.1/32@2x/color/eth@2x.png',
name: 'Ethereum',
rank: 2,
symbol: 'ETH',
usd: 321.0852636071127,
},
{
id: 'Ye9v02h1yB',
icon:
'https://unpkg.com/cryptocurrency-icons@0.16.1/32@2x/color/xrp@2x.png',
name: 'XRP',
rank: 3,
symbol: 'XRP',
usd: 0.031146111168099146,
},
{
id: 'sslKSG8UWc',
icon:
'https://unpkg.com/cryptocurrency-icons@0.16.1/32@2x/color/bch@2x.png',
name: 'Bitcoint Cash',
rank: 4,
symbol: 'BCH',
usd: 95.26885858400416,
},
{
id: 'OzaBu5YrdR',
icon:
'https://unpkg.com/cryptocurrency-icons@0.16.1/32@2x/color/ltc@2x.png',
name: 'Litecoin',
rank: 5,
symbol: 'LTC',
usd: 113.26068241294408,
},
{
id: 'o2qB71E5gA',
icon:
'https://unpkg.com/cryptocurrency-icons@0.16.1/32@2x/color/xlm@2x.png',
name: 'Stellar Lumens',
rank: 6,
symbol: 'XLM',
usd: 0.05643955012041886,
},
{
id: 'Z9lX83lV88',
icon:
'https://unpkg.com/cryptocurrency-icons@0.16.1/32@2x/color/bnb@2x.png',
name: 'Binance Coin',
rank: 7,
symbol: 'BNB',
usd: 17.85464158639072,
},
{
id: 'TE80yFVuas',
icon:
'https://unpkg.com/cryptocurrency-icons@0.16.1/32@2x/color/eos@2x.png',
name: 'EOS',
rank: 8,
symbol: 'EOS',
usd: 3.855903650694415,
},
{
id: 'H5W6_412pI',
icon:
'https://unpkg.com/cryptocurrency-icons@0.16.1/32@2x/color/xtz@2x.png',
name: 'Tezos',
rank: 9,
symbol: 'XTZ',
usd: 4.517382329979666,
},
{
id: 'rToxhn43tt',
icon:
'https://unpkg.com/cryptocurrency-icons@0.16.1/32@2x/color/xmr@2x.png',
name: 'Monero',
rank: 10,
symbol: 'XMR',
usd: 78.09242503655813,
},
];
const history = [
{usd: 10403.225432572899},
{usd: 10726.226606872504},
{usd: 11118.742505961116},
{usd: 11588.231626300778},
{usd: 11565.315276894622},
{usd: 11495.182779678717},
{usd: 11301.06046502138},
{usd: 11179.813512895777},
{usd: 11072.613310741268},
{usd: 11363.51386298342},
{usd: 11074.512410163852},
{usd: 10720.476300037026},
{usd: 10305.807931427296},
{usd: 10229.655225316685},
{usd: 10393.432864771295},
{usd: 10701.276821306672},
{usd: 10798.858825763533},
{usd: 11158.455935821352},
{usd: 10947.376271999421},
{usd: 10866.4089331405},
{usd: 11134.886068290985},
{usd: 11374.184163558648},
{usd: 11746.49194942021},
{usd: 11552.341131505369},
{usd: 11980.086433507751},
{usd: 12251.242051004643},
{usd: 12493.54387228554},
{usd: 12341.672941117293},
{usd: 12417.10177916791},
{usd: 12162.590868702151},
{usd: 12564.663630420322},
{usd: 12304.774948210146},
{usd: 12593.755180198437},
{usd: 12769.867254632702},
{usd: 13138.02575411742},
{usd: 13537.43179523923},
{usd: 13870.71915297907},
{usd: 13532.548916838517},
{usd: 13528.423207111075},
{usd: 13667.266572776905},
{usd: 13290.369396188444},
{usd: 13530.563398378668},
{usd: 13743.31886171278},
{usd: 13478.410239964856},
{usd: 13386.591254433639},
{usd: 13335.194764827305},
{usd: 13047.988162170717},
{usd: 12915.511559261107},
{usd: 13248.029270016732},
{usd: 13434.560486349328},
{usd: 13025.13208798676},
{usd: 12779.752554405484},
{usd: 12357.110980454298},
{usd: 12437.099733536039},
{usd: 12373.883435426576},
{usd: 12035.393192975373},
{usd: 11703.391076068747},
{usd: 11558.709291641495},
{usd: 11215.463043087173},
{usd: 11385.25311489339},
{usd: 11492.763725193165},
{usd: 11443.525474802072},
{usd: 11195.500851095348},
{usd: 11155.531672360174},
{usd: 11476.6498086128},
{usd: 11589.013177852563},
{usd: 11175.752044568722},
{usd: 11148.032843922616},
{usd: 11604.089126395978},
{usd: 11844.5352658886},
{usd: 12211.356559724938},
{usd: 12021.686058267363},
{usd: 11554.713520536168},
{usd: 11280.368025891226},
{usd: 11198.919914059172},
{usd: 11449.079530108638},
{usd: 11030.928602622753},
{usd: 11107.389098542404},
{usd: 10834.198566563766},
{usd: 11069.57266981072},
{usd: 11080.063522283905},
{usd: 11501.95098613861},
{usd: 11964.990838037049},
{usd: 12334.054259845638},
{usd: 12602.85645933127},
{usd: 12622.03153846148},
{usd: 12365.841059310309},
{usd: 12138.04643347591},
{usd: 12452.689500653389},
{usd: 12352.414100489648},
{usd: 12390.490859344294},
{usd: 11918.644416991836},
{usd: 11939.092502644542},
{usd: 11468.147126260015},
{usd: 11732.874395345347},
{usd: 12107.303077030088},
{usd: 12455.517156790427},
{usd: 12014.047044558429},
{usd: 11891.890623419315},
{usd: 11884.926426425534},
{usd: 11997.495679837246},
{usd: 11623.148716430853},
{usd: 11192.757141264894},
{usd: 10849.740820402998},
{usd: 10693.488731595146},
{usd: 10624.106171893305},
{usd: 10219.431654125181},
{usd: 10647.67546380128},
{usd: 10587.906105747004},
{usd: 10814.515554779466},
{usd: 11011.88767309237},
{usd: 11117.75268106489},
{usd: 11269.114378800936},
{usd: 10928.631631706681},
{usd: 10626.321895814615},
{usd: 10350.582617103302},
{usd: 10499.253596053295},
{usd: 10642.352723445403},
{usd: 10738.493460856971},
{usd: 10335.362344036346},
{usd: 10640.719860080668},
{usd: 10926.479649668885},
{usd: 11338.405236532422},
{usd: 10924.051153329561},
{usd: 10569.122260543445},
{usd: 10763.818948293427},
{usd: 10781.961587228561},
{usd: 10393.46963890733},
{usd: 10523.528777476236},
{usd: 10233.414300781684},
{usd: 10528.194992850764},
{usd: 10070.25126370544},
{usd: 10508.096184161393},
{usd: 10435.957257073147},
{usd: 9989.844721119942},
{usd: 10292.523295584419},
{usd: 10723.445683803022},
{usd: 10539.125473102638},
{usd: 10805.049057345088},
{usd: 10903.513519077456},
{usd: 10580.939562541447},
{usd: 10201.6185763784},
{usd: 10341.77882622825},
{usd: 9975.736620514735},
{usd: 10424.875520511754},
{usd: 10669.546175495136},
{usd: 10546.11826599819},
{usd: 10418.94639376895},
{usd: 10858.432664367263},
{usd: 11100.462169300616},
{usd: 11268.37482897761},
{usd: 11594.794555031804},
{usd: 11822.168598998502},
{usd: 12089.83126728238},
{usd: 12480.924711612592},
{usd: 12159.481742661721},
{usd: 11948.033279412364},
{usd: 11731.25767107056},
{usd: 11365.724469181168},
{usd: 11520.008304790557},
{usd: 11799.873814881112},
{usd: 11902.915938906364},
{usd: 12328.158000857826},
{usd: 12534.933739595928},
{usd: 12452.13281030069},
{usd: 12159.48423847248},
{usd: 12340.735677163508},
{usd: 12572.58177039288},
{usd: 12953.925011166042},
{usd: 12576.74797796273},
{usd: 12493.063301001675},
{usd: 12327.856698884665},
{usd: 12080.35179284919},
{usd: 11723.789013082993},
{usd: 11961.627009183749},
{usd: 11734.792321174667},
{usd: 12097.54931142208},
{usd: 12133.545760326062},
{usd: 12500.522073204143},
{usd: 12108.190334460733},
{usd: 11827.96730662036},
{usd: 11797.337164232798},
{usd: 12267.72640976462},
{usd: 12593.605480969125},
{usd: 12157.096754679102},
{usd: 12209.992226261193},
{usd: 11771.437011573014},
{usd: 12093.788079821026},
{usd: 12471.695148832132},
{usd: 12773.906538781072},
{usd: 12729.100012986053},
{usd: 13138.004269713767},
{usd: 13105.612530234675},
{usd: 13337.90896791045},
{usd: 12987.834002014557},
{usd: 12978.90190323421},
{usd: 13379.558968824163},
{usd: 13553.62842138592},
{usd: 13519.243385238082},
{usd: 13304.85771372851},
{usd: 13350.661629339436},
{usd: 13629.244047812628},
{usd: 14075.350095489075},
{usd: 14470.957539905283},
{usd: 14319.114157687585},
{usd: 14034.78873918713},
{usd: 14396.48331918595},
{usd: 14559.834468362433},
{usd: 15031.088092146918},
{usd: 14857.015434100422},
{usd: 14913.936368136543},
{usd: 14620.67763262385},
{usd: 14219.674744151158},
{usd: 14510.484448315328},
{usd: 14180.404140170198},
{usd: 14201.216967294948},
{usd: 14032.475615426556},
{usd: 14349.383838386446},
{usd: 14387.483864844848},
{usd: 14840.12117337317},
{usd: 15232.077563811132},
{usd: 14880.01995101013},
{usd: 14440.10444376753},
{usd: 14114.729539269672},
{usd: 13701.21885299133},
{usd: 13404.969394559106},
{usd: 13368.740157728724},
{usd: 13483.198394851433},
{usd: 13941.88520487125},
{usd: 14067.572514298436},
{usd: 14325.259654448408},
{usd: 14068.877220751809},
{usd: 13659.943414805173},
{usd: 13721.374535193729},
{usd: 13288.210918420436},
{usd: 13064.992316442625},
{usd: 13304.085162482248},
{usd: 12881.057547604454},
{usd: 12486.258228162718},
{usd: 12045.913510696995},
{usd: 11654.578601288928},
{usd: 11199.04462495052},
{usd: 10812.04330754063},
{usd: 10817.44496637475},
{usd: 10402.408898793128},
{usd: 10100.401016378428},
{usd: 10477.918548827498},
{usd: 10933.95386924339},
{usd: 10903.112615062668},
{usd: 10705.562989258151},
{usd: 10656.191704123796},
{usd: 11077.266032873798},
{usd: 11362.720745854096},
{usd: 11729.696648817162},
{usd: 11381.926783750692},
{usd: 11728.467608302375},
{usd: 11563.560431200953},
{usd: 11909.750087199862},
{usd: 12309.365974725508},
{usd: 12066.249096946305},
{usd: 11615.063639987027},
{usd: 11991.63372885613},
{usd: 11797.95502462648},
{usd: 11976.134429012742},
{usd: 12131.849898521621},
{usd: 12493.680579747861},
{usd: 12089.200135303776},
{usd: 11762.923063056827},
{usd: 11758.170540088686},
{usd: 12215.425561945625},
{usd: 11867.73392688389},
{usd: 11419.454318925875},
{usd: 11159.290229388922},
{usd: 11020.48733061045},
{usd: 11471.868758315808},
{usd: 11097.105094264809},
{usd: 10687.374754154336},
{usd: 10436.652680309926},
{usd: 10889.75995717631},
{usd: 10449.139752156907},
{usd: 10887.93547782367},
{usd: 10750.42544314064},
{usd: 10683.938591597163},
{usd: 10638.87231224448},
{usd: 10513.322239862153},
{usd: 10093.17856930125},
{usd: 10146.337483721467},
{usd: 10561.35543293886},
{usd: 10694.366802915627},
{usd: 10424.697843285467},
{usd: 10217.055630420076},
{usd: 9758.43316737953},
{usd: 10078.327620949818},
{usd: 9850.847486441959},
{usd: 9844.161844205533},
{usd: 9961.416014577913},
{usd: 9768.783222244736},
{usd: 9408.198323823373},
{usd: 9767.150808574537},
{usd: 9516.173759066267},
{usd: 9336.803900944475},
{usd: 8977.968933502718},
{usd: 8567.438291922017},
{usd: 8368.093086077804},
{usd: 8760.140644361569},
{usd: 8384.355889782466},
{usd: 8836.626386487378},
{usd: 9112.85753338134},
{usd: 8873.68677841131},
{usd: 8439.101279469456},
{usd: 8693.59634915423},
{usd: 8651.611938549459},
{usd: 8900.807596654762},
{usd: 9298.064548168299},
{usd: 9168.1787947109},
{usd: 8942.515912122484},
{usd: 9063.765932136082},
{usd: 9503.304645844995},
{usd: 9146.55176382189},
{usd: 9423.539935636627},
{usd: 9172.090081517692},
{usd: 8741.139414558113},
{usd: 8605.322362074452},
{usd: 8925.499742924187},
{usd: 8554.239472481418},
{usd: 8699.160347316329},
{usd: 9165.621785728135},
{usd: 9514.182342657778},
{usd: 9577.254730970631},
{usd: 9491.886024478126},
{usd: 9864.867356674466},
{usd: 9987.575142026595},
{usd: 9595.82884334302},
{usd: 9282.39035719181},
{usd: 8862.683316645383},
{usd: 8880.141650721376},
{usd: 9228.774415477852},
{usd: 9590.110422739981},
{usd: 9228.972400095037},
{usd: 9035.89154100658},
{usd: 9095.394897325034},
{usd: 9158.499828831182},
{usd: 9075.453018833987},
{usd: 8627.720925722151},
{usd: 8321.220841210135},
{usd: 8507.525383859418},
{usd: 8231.657586173447},
{usd: 8697.419403006721},
{usd: 8871.816182061859},
{usd: 8478.337049950656},
{usd: 8484.068612221963},
{usd: 8518.357162395283},
{usd: 8195.385913816106},
{usd: 8087.149431969016},
{usd: 8236.238885098774},
{usd: 8182.120349107061},
{usd: 8268.624610597475},
{usd: 8126.431088578624},
{usd: 7872.616666134845},
{usd: 8200.386503782178},
{usd: 8118.096382872036},
{usd: 8434.302248739923},
{usd: 8879.981854705413},
{usd: 9223.685863081557},
{usd: 9654.80767075271},
];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment