React Native’de harici bir kütüphane kullanmadan pasta grafiği (pie chart) nasıl yapılır?

Zafer Ayan
13 min readMay 4, 2020

--

Günlük hayatta uygulama geliştirirken hazır bir şekilde grafik kütüphanelerini kullanabiliyoruz. Fakat React Native’de birçok farklı platformu (android, ios, web) aynı anda destekleyebilen bir chart kütüphanesi bulunmayabiliyor. Bu gibi durumlarda örneğin web için harici olarak chartjs gibi kütüphaneleri de kullanabilirsiniz. Fakat ortak bir kod oluşması ve o kodun üzerinden geliştirim yapılması daha iyi olacaktır. Dolayısıyla bu problemi çözmek ve aynı zamanda grafik kütüphanelerinin en temel halde bir pasta grafiğini nasıl çizdiğini görmek için kendi pasta grafiğimizi çizebiliriz. Bu yazımda da pasta grafiğini nasıl kendiniz çizebilirsiniz buna değineceğim.

Öncelikle projeminizi oluşturalım:

npx react-native init SampleRNPieChart --template react-native-template-typescript
cd SampleRNPieChart

Projemize react-native-svg kütüphanesini ekleyelim, pod’ları yükleyelim, projeyi git’e ekleyelim ve vscode ile açtıktan sonra cihazda çalıştıralım:

yarn add react-native-svg
npx pod-install
git init
git add .
git commit -m "First commit"
code .
npx react-native run-ios

react-native-svg kütüphanesi vektörel grafikler çizmek için kullanışlıdır. Pasta grafikleri ve diğer grafikler bu kütüphane yardımıyla çizilebilir.

SVG’nin çalışma prensipleri

Chart çizimine geçmeden önce en basit haliyle bir SVG nasıl çalışır onu öğrenmemiz gerekiyor. Ekranı baştan başa kaplayacak bir çember çizdirelim:

import React from 'react';
import {SafeAreaView, StyleSheet} from 'react-native';
import Svg, {Circle} from 'react-native-svg';
const App = () => {
return (
<SafeAreaView style={styles.safeAreaView}>
<Svg viewBox="0 0 42 42">
<Circle cx="21" cy="21" r="21" stroke="#1565C0" />
</Svg>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
safeAreaView: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
export default App;

Kodu açıklayacak olursak:

  • viewBox=”0 0 42 42": viewBox özelliği parametre olarak center-x, center-y, width ve height olmak üzere 4 farklı değer alır. viewBox’ın amacı, arayüze çizilecek vektörel görselin belirtilen genişlik/yükseklik değerlerine uydurulmasını sağlar. Yani bir çeşit haritalama işlemi yapar. Örneğin, üstte yar alan iPhone 11 cihazının genişliğinin 414px olduğunu ele alırsak, viewbox kısmında genişlik/yükseklik değerlerine 42 verdiğimizde, SVG elemanı içerisine çizilen elemanların boyutu 414/42 = 9.8 ölçeği ile çarpılarak ekrana çizilecektir.
  • <Circle>: SVG içerisine bir çember/daire çizilmesini sağlar
  • cx, cy: Çizilecek çemberin merkez noktasını belirler. centerX ve centerY gibi düşünebilirsiniz. 42 42 şeklinde genişlik/yükseklik değerleri verdiğimiz için viewBox’ın tam orta noktası da 21, 21 noktasını oluşturmaktadır. Bu sayede çember, viewBox’ın tam ortasına çizilecektir.
  • r: Yarıçapı belirtir. 21 verdiğimiz takdirde, yarıçapı 21 olan (çapı 42 olan) ve ekranı baştan başa kaplayan bir çember çizilecektir:
  • stroke: Çemberin rengini belirtir. Burada farkedeceğiniz üzere bir çember kalınlığı parametresi verilmese dahi viewBox’a göre 1px kalınlıkta bir çember oluşturuluyor. Hesaplamaları yaparken farkettiğimde strokeWidth (çember kalınlığı) değerinin otomatik olarak 1 verildiğini gördüm. Bu nedenle strokeWidth değerini 0 olarak vermediğiniz sürece, stroke özelliği 1 px’lik bir kalınlıkta çember oluşturulmasını sağlayacaktır.

Eğer çember yerine daire çizdireceksek, çemberin içini fill özelliğine verilecek olan renk ile doldurmamız yeterlidir:

<SafeAreaView style={styles.safeAreaView}>
<Svg viewBox="0 0 42 42">
<Circle
cx="21"
cy="21"
r="21"
stroke="#1565C0"
strokeOpacity="0.5"
strokeWidth="5"
fill="#dd0000"
/>
</Svg>
</SafeAreaView>
Farkedileceği gibi dairenin kenarlığı sadece dışa doğru değil aynı zamanda içe doğru da çizilmektedir.

Burada strokeOpacity (çember kalınlığı şeffaflığı) değeri kullanıldığında farkedeceğiniz gibi fill değeri stroke değerine göre daha önce ele alındığı için, öncelikle dairenin iç kısmı kırmızı ile doldurulup, daha sonra mavi ile kalınlık eklenmektedir. Çemberin kalınlığı sadece dışarı değil aynı zamanda içe doğru da etki eder. Bu nedenle 2 px’lik bir kalınlık verdiğinizde bunun 1px’i içeri, 1px’i ise dışarı olacak şekilde taşmaktadır. Çizim yaparken bu hesaplamaları da dahil etmeniz gereklidir.

Bu bilgiden yola çıkarak, strokeWidth özelliği ile ekranı kaplayan bir daire çizmek istediğinizde, belirtilen rengin çemberin hem içine hem de dışına taşacağından dolayı, yarıçap değerini 21 değil 10.5 almanız gereklidir:

<SafeAreaView style={styles.safeAreaView}>
<Svg viewBox="0 0 42 42">
<Circle cx="21" cy="21" r="10.5" stroke="#1565C0" strokeWidth="21" />
</Svg>
</SafeAreaView>

Şimdi piechart’taki gibi bölmelere ayırmak için strokeDashArray özelliğini kullanabiliriz. Bu özellik sayesinde hesaplanan çember kalınlığının kaç parçaya bölüneceği belirtilir. Örneğimizideki viewBox değerlerini biraz değiştirip daha bölünebilir ve üzerinde rahat bir şekilde işlem yapılabilir hale getirelim:

const App = () => {
const perimeter = 2 * Math.PI * 30;
return (
<SafeAreaView style={styles.safeAreaView}>
<Svg viewBox="0 0 120 120">
<Circle
cx="60"
cy="60"
r="30"
stroke="#1565C0"
strokeWidth="60"
strokeDasharray={perimeter / 60} // Yarım daire
/>
</Svg>
</SafeAreaView>
);
};

Örneğimizde yarıçap 30 iken çevre uzunluğu 2 * pi * r ifadesi ile 188.49 olarak hesaplanacaktır. Bu bağlamda strokeDasharray özelliğini 188.49 verdiğimizde tam bir daire, 99 verdiğimizde ise yarım daire elde ederiz. Çevreyi hesaplayarak perimeter değişkenine atadığımızda, üzerinde daha rahat bir şekilde işlem yapabiliriz. Birkaç farklı strokeDasharray değeri için aşağıdaki ekranları elde edebiliriz:

Farklı strokeDashArray özellikleri için farklı görsellerin oluşturulması. Sırasıyla perimeter, perimeter * (3/4), perimeter/2, perimeter/60 şeklinde verildiğinde üstteki görseller elde edilecektir.

Şimdi bu bilgilerden yola çıkarak %60 oranındaki bir ifadeyi göstermek için aşağıdaki gibi bir çizim yapalım:

const App = () => {
const perimeter = 2 * Math.PI * 30;
return (
<SafeAreaView style={styles.safeAreaView}>
<Svg viewBox="0 0 120 120">
<Circle
cx="60"
cy="60"
r="30"
stroke="#1565C0"
strokeWidth="60"
strokeDasharray={(perimeter * 60) / 100}
/>
</Svg>
</SafeAreaView>
);
};

%60'lık grafik aşağıdaki gibi görüntülenecektir:

Fakat burada bir problem var. Grafiğin saat 3 yönünden değil saat 12 yönünden başlaması gerekiyor. Bunun için CSS’in transform özelliğinden yararlanabiliriz. Z ekseninde saat yönünün tersine 90 derece döndürdüğümüzde istediğimiz sonucu alabiliriz:

const App = () => {
const perimeter = 2 * Math.PI * 30;
return (
<SafeAreaView style={styles.safeAreaView}>
<Svg viewBox="0 0 120 120" style={{transform: [{rotateZ: '-90deg'}]}}>
<Circle
cx="60"
cy="60"
r="30"
stroke="#1565C0"
strokeWidth="60"
strokeDasharray={(perimeter * 60) / 100}
/>
</Svg>
</SafeAreaView>
);
};

Ekran görüntüsü aşağıdaki gibi olacaktır:

Boş olan kısım tam olarak belirli değil gibi duruyor ve arkaplanda kayboluyor. Bunun için mavi ve yarı şeffaf bir renkte tam bir daire çizerek, %40'lık boş kısmı görüntüleyebiliriz:

const App = () => {
const perimeter = 2 * Math.PI * 30;
return (
<SafeAreaView style={styles.safeAreaView}>
<Svg viewBox="0 0 120 120" style={{transform: [{rotateZ: '-90deg'}]}}>
<Circle
cx="60"
cy="60"
r="30"
stroke="#1565C0"
strokeOpacity="0.5"
strokeWidth="60"
strokeDasharray={perimeter}
/>
<Circle
cx="60"
cy="60"
r="30"
stroke="#1565C0"
strokeWidth="60"
strokeDasharray={(perimeter * 60) / 100}
/>
</Svg>
</SafeAreaView>
);
};

Daha sonra bu grafiğe ilgili alanların yüzdelik gösterimi için Text elemanı ile metin eklenmesi sağlanabilir:

<Svg viewBox="0 0 120 120" style={{transform: [{rotateZ: '-90deg'}]}}>
<Circle
cx="60"
cy="60"
r="30"
stroke="#1565C0"
strokeOpacity="0.5"
strokeWidth="60"
strokeDasharray={perimeter}
/>
<Circle
cx="60"
cy="60"
r="30"
stroke="#1565C0"
strokeWidth="60"
strokeDasharray={(perimeter * 60) / 100}
/>
<Text x="55" y="20" fill="#fff">
60%
</Text>
<Text x="-5" y="-5" fill="#fff">
40%
</Text>
</Svg>

SVG’yi 90 derece döndürdüğümüz için doğal olarak Text ifadeleri de dönmüş oldu. Bunu düzeltmek için Text bileşeninde transform özelliğini kullanarak ters yönde 90 derece döndürebiliriz:

<Text x="75" y="-40" fill="#fff" transform="rotate(90 0,0)">
60%
</Text>
<Text x="15" y="-65" fill="#fff" transform="rotate(90 0,0)">
40%
</Text>

Bu yöntem ile strokeWidth değerini azaltarak donut grafiği de çizebilirsiniz:

<Svg viewBox="0 0 120 120" style={{transform: [{rotateZ: '-90deg'}]}}>
<Circle
cx="60"
cy="60"
r="30"
stroke="#1565C0"
strokeOpacity="0.5"
strokeWidth="15"
strokeDasharray={perimeter}
/>
<Circle
cx="60"
cy="60"
r="30"
stroke="#1565C0"
strokeWidth="15"
strokeDasharray={(perimeter * 60) / 100}
/>
<Text x="50" y="-55" fill="#1565C0" transform="rotate(90 0,0)">
60%
</Text>
</Svg>

Burada aslında göremediğimiz bir problem var. Oran %50'nin altına düştüğünde, strokeDashArray özelliği artık çift pasta dilimi eklemeye başlıyor:

%50'nin altındaki değerler için ise oranları yer değiştirip (invert ederek) grafiği döndürebiliriz.

const App = () => {
const perimeter = 2 * Math.PI * 30;
const percentageInput = 33;
const isInverted = percentageInput < 50;
const percentage = isInverted ? 100 - percentageInput : percentageInput;
const rotateZ = 90 + (isInverted ? (360 * percentage) / 100 : 0);
const circleColor1 = isInverted ? '#1565C0' : '#87B6ED';
const circleColor2 = isInverted ? '#87B6ED' : '#1565C0';
console.log(rotateZ);
return (
<SafeAreaView style={styles.safeAreaView}>
<Svg
viewBox="0 0 120 120"
style={{
transform: [{rotateZ: `-${rotateZ}deg`}],
}}>
<Circle
cx="60"
cy="60"
r="30"
stroke={circleColor1}
strokeWidth="60"
strokeDasharray={perimeter}
/>
<Circle
cx="60"
cy="60"
r="30"
stroke={circleColor2}
strokeWidth="60"
strokeDasharray={(perimeter * percentage) / 100}
/>
<Text x="50" y="70" fill="#fff" transform={`rotate(${rotateZ} 0,0)`}>
{100 - percentage}
</Text>
<Text x="-10" y="100" fill="#fff" transform={`rotate(${rotateZ} 0,0)`}>
{percentage}
</Text>
</Svg>
</SafeAreaView>
);
};

Circle ile pasta grafiği çizmenin dezavantajları

Bu yöntem ikiden fazla dilim olduğunda çalışmayacaktır. Bu problem ile ilgili araştırma yaptığımda şuradaki yazıya rastladım:
https://medium.com/hackernoon/a-simple-pie-chart-in-svg-dbdd653b6936

Bu yazıdaki gibi Path bileşeni kullanarak pasta dilimi çizebiliriz.

Path ile eğriler çizerek grafik oluşturma

<Path> bileşeni ile eğri çizerek bir pasta dilimi oluşturmak için, Path bileşeninin: M, A ve L olmak üzere sadece 3 komutu kullanmanız yeterli olacaktır. Bu komutların anlamları ise aşağıdaki gibi belirtilmiştir:

Örnek olarak görseldeki pasta dilimini çizecek olursak kodu aşağıdaki gibi olacaktır:

/* eslint-disable react-native/no-inline-styles */
import React from 'react';
import {SafeAreaView, StyleSheet} from 'react-native';
import Svg, {Path} from 'react-native-svg';
const App = () => {
return (
<SafeAreaView style={styles.safeAreaView}>
<Svg
viewBox="-100 -50 200 200"
style={{
transform: [{rotateZ: `-90deg`}],
backgroundColor: '#e5e5e5',
}}>
<Path d="M 100 0 A 100 100 0 0 1 70 70 L 0 0" fill="#1565C0" />
</Svg>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
safeAreaView: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
export default App;

Kodu çalıştırdığınızda %12,5'luk pasta dilimi görünümü aşağıdaki gibi olacaktır:

Kodu açıklamak gerekirse:

  • viewBox=”-100 -50 200 200": 200x200 boyutunda ve (0,0) noktası (-100,-50) olan bir viewBox oluşturmayı sağlar. -100,-50 yazmamın amacı, bu noktayı (0,0) noktası (merkez) olarak kabul ederek, daire üzerinde daha kolay işlem yapabilmek içindir. Hepsinin 100'ün katı olması da aynı sebeple yapılmıştır.

Şimdi de <Path d=”M 100 0 A 100 100 0 0 1 70 70 L 0 0" fill=”#1565C0" /> kısmını açıklayalım:

  • d: bildiğiniz gibi Path elemanının nasıl çizileceğini belirtir.
  • M 100 0: Başlangıç noktasıdır. x: 100 y: 0 noktasına, yani pasta diliminin sol üst köşesine bir nokta koymaya yarar. Bu noktadan başlanarak çizgi çizilecektir.
  • A 100 100 0 0 1 70 70: A komutunun eğri çizmeye yaradığını belirtmiştik. parametrelere değinecek olursak sırasıyla rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x ve y şeklindedir. Bu parametreleri detaylı şekilde ele alalım:
  • rx ry (100 100): Çizilecek eğrinin yarıçapını belirtir. Eğriler genellikle elips şekli baz alınarak çizildiği için, rx ve ry gibi iki farklı eksende yarıçap parametresi bulunmaktadır. Pasta grafiğimiz daire şeklinde olduğu için, rx ve ry’ye eşit değer verdik (100 100).
  • x-axis-rotation(0): Eliptik eğrilerde eğrinin ucunun belirtilen noktaya doğru çekilmesini/gerdirilmesini sağlar. Pasta grafiği dairesel olduğu için 0 değerini verdik.
x-axis-rotation özelliğinin farklı değerler üzerinde uygulanması. Piechart’ta böyle bir özelliğe ihtiyacımız olmadığı için 0 değerini verdik.
  • large-arc-flag(0): Çember üzerinde iki nokta belirtildiğinde, çizilecek olan eğrinin kısa yoldan mı dolaşmasını yoksa uzun yoldan mı dolaşarak çizilmesi gerektiğini belirtir. Kendi uygulamamızda pasta dilimi %50'den büyükse bu değeri 1 olarak ayarlayacağız. Aksi halde küçük bir eğri çizilecektir. Örneğin %60 değeri verildiğinde, large-arc-flag=0 olursa, eğri kısa yoldan dolanacağı için %40'lık bir pasta dilimi çizilir.
  • sweep-flag (1): İki nokta arasında çizilecek olan eğrinin dış bükey olup olmayacağını belirtir. Daire çiziminde dış bükeylik kullanıldığı için 1 alınır.
  • x y (70 70): Eğrinin bittiği noktayı belirtir.

Son olarak da L (Line) özelliğine değinelim:

  • L 0 0: Çemberin merkezine (0,0 noktasına) doğru bir çizgi çizilmesini sağlar.

Buradaki aslında en büyük problem: eğrinin bittiği noktayı bulmak. Bu noktada 8. sınıftaki trigonometrik oranlar bilgilerine dönmemiz gerekiyor.

Bildiğiniz gibi normalde dairenin çevresi 2π olarak belirtilir. Eğer çemberin belirli bir kısmını almak isterseniz bunu ilgili orana bölmeniz yeterlidir.

Örneğin π/4 yani 12.5 derecelik bir açı için x ve y noktaları sırasıyla kosinüs ve sinüs değerleridir. Not: Normalde aklımıza gelen “karşı taraf sinüs, komşu taraf kosinüs” bilgisi aslında x ekseni ile yapılan açılar için geçerlidir. y ekseni ile yapılan açılarda tam tersi olarak kullanılır.

Bu amaçla x ve y noktalarını hesaplayan fonksiyonu aşağıdaki gibi oluşturabiliriz. Buradaki radius parametresi, eğri çizerken A komutuna verdiğimiz 100 değeri olacak.

const getXY = (percent: number, radius: number) => {
const x = Math.cos((2 * Math.PI * percent) / 100) * radius;
const y = Math.sin((2 * Math.PI * percent) / 100) * radius;
return {x, y};
};

Kodu entegre edecek olursak:

const App = () => {
const getXY = (percent: number, radius: number) => {
const x = Math.cos((2 * Math.PI * percent) / 100) * radius;
const y = Math.sin((2 * Math.PI * percent) / 100) * radius;
return {x, y};
};
const percent = 33;
const radius = 100;
const largeArcFlag = percent > 50 ? 1: 0;
const {x, y} = getXY(percent, radius); return (
<SafeAreaView style={styles.safeAreaView}>
<Svg
viewBox="-100 -50 200 200"
style={{
transform: [{rotateZ: '-90deg'}],
backgroundColor: '#e5e5e5',
}}>
<Path d={`M 100 0 A ${radius} ${radius} 0 ${largeArcFlag} 1 ${x} ${y} L 0 0`} fill="#1565C0" />
</Svg>
</SafeAreaView>
);
};

%33'lük ve %66'lık oranlar için ekran çıktıları aşağıdaki gibi olacaktır:

Şimdi bu grafiklerdeki pasta dilimlerini birleştirmemiz gerekiyor. Bunun için bir sonraki grafiğin başlangıç noktasını bir önceki dilimdeki Arc’ın bitiş noktasına ekleyerek yapabiliriz. Dolayısıyla Path data’larını dinamik olarak oluşturmamız gerekiyor.

Gelen veriyi pathDataList dizisine atamak ve ilgili <Path> bileşenlerini oluşturmak suretiyle App.tsx’i aşağıdaki gibi değiştirelim:

/* eslint-disable react-native/no-inline-styles */
import React from 'react';
import {SafeAreaView, StyleSheet} from 'react-native';
import Svg, {Path} from 'react-native-svg';
const colors = [
'#0d47a1',
'#1976D2',
'#2196F3',
'#64B5F6',
'#BBDEFB',
'#E3F2FD',
];
const getXY = (percent: number, radius: number) => {
const x = Math.cos((2 * Math.PI * percent) / 100) * radius;
const y = Math.sin((2 * Math.PI * percent) / 100) * radius;
return {x, y};
};
const slices = [
{percent: 12, id: 1},
{percent: 66, id: 2},
{percent: 5, id: 3},
{percent: 17, id: 4},
].sort((a, b) => b.percent - a.percent);
const App = () => {
const radius = 100;
let tempPercent = 0;
const pathDataList = slices.map((v) => {
const start = getXY(tempPercent, radius);
tempPercent += v.percent;
const end = getXY(tempPercent, radius);
const largeArcFlag = v.percent > 50 ? 1 : 0;
return {
d: `M ${start.x} ${start.y}
A ${radius} ${radius} 0 ${largeArcFlag} 1 ${end.x} ${end.y}
L 0 0`,
id: v.id,
};
});
return (
<SafeAreaView style={styles.safeAreaView}>
<Svg
viewBox="-100 -50 200 200"
style={{
transform: [{rotateZ: '-90deg'}],
}}>
{pathDataList.map((v, i) => (
<Path key={v.id} d={v.d} fill={colors[i]} />
))}
</Svg>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
safeAreaView: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
export default App;

Kodu çalıştırdığınızda aşağıdaki gibi görüntülenecektir.

Yüzdelik metinlerinin yerleştirilmesi

Grafiğimiz bu haliyle yüzdelik bilgiler görüntülenemiyor. Yüzdelik metni pasta diliminin içerisine yerleştirmek için bir çözüm bulamadığımda aşağıdaki gibi kendi yöntemimi geliştirdim. Bu yöntemi açıklayacak olursam: pasta diliminin yarısı kadar yarıçapa sahip bir çember yayı hayal ederek, tam orta kısmına gelecek şekilde koordinata metni eklememiz yeterli olacaktır:

Bunun için, yarıçapın yarısı (radius/2) ve yüzdenin yarısı (percent/2) parametrelerini getXY() metoduna vererek hesaplayabiliriz. Ayrıca bir sonraki dilimin ortasını bulabilmemiz için, önceki dilimin yüzdelik metninin orta kısmının yüzdesini ve metin için ayrılan toplam yüzdelik kısmı ekleyerek ilerlememiz gerekiyor. Bu bilgileri de sırasıyla prevMiddlePercent ve tempTextPercent değişkenlerinde tutabiliriz.

/* eslint-disable react-native/no-inline-styles */
import React from 'react';
import {SafeAreaView, StyleSheet} from 'react-native';
import Svg, {Path, Text, G} from 'react-native-svg';
const colors = [
'#0d47a1',
'#1976D2',
'#2196F3',
'#64B5F6',
'#BBDEFB',
'#E3F2FD',
];
const getXY = (percent: number, radius: number) => {
const x = Math.cos((2 * Math.PI * percent) / 100) * radius;
const y = Math.sin((2 * Math.PI * percent) / 100) * radius;
return {x, y};
};
const slices = [
{percent: 12, id: 1},
{percent: 66, id: 2},
{percent: 5, id: 3},
{percent: 17, id: 4},
].sort((a, b) => b.percent - a.percent);
const App = () => {
const radius = 100;
let tempPercent = 0;
let tempTextPercent = 0;
let prevMiddlePercent = 0;
const pathDataList = slices.map((v) => {
const start = getXY(tempPercent, radius);
tempPercent += v.percent;
const end = getXY(tempPercent, radius);
const largeArcFlag = v.percent > 50 ? 1 : 0;
tempTextPercent += prevMiddlePercent + v.percent / 2;
prevMiddlePercent = v.percent / 2;
return {
d: `M ${start.x} ${start.y}
A ${radius} ${radius} 0 ${largeArcFlag} 1 ${end.x} ${end.y}
L 0 0`,
id: v.id,
textPos: {
x: getXY(tempTextPercent, radius / 2).x,
y: getXY(tempTextPercent, radius / 2).y,
},
percent: v.percent,
};
});
return (
<SafeAreaView style={styles.safeAreaView}>
<Svg
viewBox="-100 -50 200 200"
style={{
transform: [{rotateZ: '-90deg'}],
}}>
{pathDataList.map((v, i) => (
<G key={v.id}>
<Path d={v.d} fill={colors[i]} />
<Text
x={v.textPos.x}
y={v.textPos.y}
fill="#fff"
fontSize="12"
textAnchor="middle"
transform={`rotate(90 ${v.textPos.x},${v.textPos.y})`}>
{v.percent}
</Text>
</G>
))}
</Svg>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
safeAreaView: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
export default App;

Kodu çalıştırdığınızda aşağıdaki gibi görüntülenecektir:

Sonuç olarak

React Native’de chart çizimi için hazır kütüphaneler bulunuyor. Fakat web gibi diğer platformlara da chart çizmek istediğinizde kütüphane desteği bulamayabiliyorsunuz. Bu gibi durumlarda yazıdaki yönergeleri takip ederek React Native uygulamasında piechart oluşturabilirsiniz. Ayrıca d3.js kullanarak daha rahat bir şekilde çizim işlemlerini gerçekleştirebilirsiniz.

Projenin bitmiş halini react-native-piechart-no-library-sample reposunda bulabilirsiniz. Bu yazım hakkında soru ve görüşlerinizi aşağıdaki yorumlar kısmından yazabilirsiniz. Bana destek vermek için alkış simgesine tıklayabilirsiniz. Sonraki yazımda görüşmek üzere…

Kaynaklar:

--

--

No responses yet