Pantrix UI

Bir grafiği dosya olarak dışa aktarma

Bir Pantrix grafiğinin PNG, SVG ve PDF olarak nasıl dışa aktarıldığı, kütüphanenin neyi yapıp neyi uygulamaya bıraktığı, üretilen dosyanın kullanıcıya her platformda nasıl ulaştırılacağı ve üç dosya türünün sınırları.

Grafik dosyayı üretir ve uygulamaya verir; kaydetmez, paylaşmaz, indirmez. Kullanıcıya foundation'ın FileSaver'ı verir, her platformun kaydetme penceresiyle (3. bölüm); paylaşım sayfası uygulamanındır.

Burada kütüphane hakkında söylenen her şey bu depoda koşan testlerde ya da üretilen dosyalara bakılarak görülmüştür; hangisinin nerede görüldüğü 6. bölümde yazılıdır. 3. bölümdeki iki paylaşım parçası demonun eski kodudur ve dört platformda derlenmişti; nerede denendiği 6. bölümdedir.

1. Kullanım

Dışa aktarma parametriktir: export verilmeyen grafikte hiçbir şey görünmez.

PantrixLineChart(
    data = months,
    x = { it.name },
    values = revenue,
    export = ChartExport(fileName = "gelir") { file ->
        // file.name = "gelir.svg", file.mimeType = "image/svg+xml", file.bytes = içerik
        share(file)
    }
)

export verilince grafiğin kendi düğmelerinin arasında (yakınlaştırma düğmeleri varsa onların yanında) bir dışa aktarma düğmesi çıkar. Okuyucu düğmeye basar, türü seçer; grafik dosyayı üretir ve onExport'a verir.

AlanNe söylerVarsayılan
formatsOkuyucunun seçtiği türler, sırasıyla. Tek tür verilirse seçim açılmaz, düğme o dosyayı üretirÜçü de: PNG, SVG, PDF
fileNameDosyanın adı, uzantısız"chart"
scalePNG'nin dp başına piksel sayısı. Ekranın yoğunluğundan bağımsızdır2f
backgroundResmin zemini. Color.Unspecified temanın background'udur; Color.Transparent zemin çizmezTemanın zemini
paddingResmin grafiğin çevresinde, her yanında bıraktığı pay. Zemin payın altında da vardır12.dp
onExportÜretilen ChartExportFile buna verilirZorunlu

export, PantrixChart ile onun üstündeki altı kısa grafikte (çizgi, alan, çubuk, aralık, şelale, mum) ve öteki on dört türün hepsinde vardır: pasta, gauge, ilerleme halkası, meter group, status tracker, sparkline, scatter, radar, polar, heatmap, treemap, huni, sankey ve Gantt. Her birinde imzanın sonundadır; yalnızca PantrixProgressCircle'da content'ten öncedir, sondaki lambda yine halkanın içindeki içerik kalsın diye.

Düğme grafiğin üstünde, satırların bittiği yanda bir satırda durur. Eksenli grafikte yakınlaştırma düğmeleriyle aynı satırdadır. Yüksekliği verilmeyen grafik bu satır kadar uzar; yüksekliği verilen grafik yüksekliğini korur, çizimi o kadar kısalır.

2. Dosyada ne var

Dosya, grafiği ekrandaki hâliyle gösterir:

Üç tür aynı çizimden üretilir; aralarındaki farklar şunlardır:

TürNeYazılarBoyut (on iki aylık iki serili bir grafik)
PNGPiksellerden resim; scale kadar keskinUygulamanın yazı tipiyle, ekrandaki gibiOnlarca kilobayt
SVGÇizgi ve şekil; her boyutta keskinGerçek metin (<text>), dosyayı açanın sans-serif yazı tipiyleBirkaç kilobayt
PDFTek sayfa, çizgi ve şekil; her boyutta keskinHelvetica ile gerçek metin; Helvetica'nın yazamadığı satır resim olarakBirkaç kilobayt

Yazılar neden ekrandakinden farklı

SVG ve PDF uygulamanın yazı tipini taşımaz: kütüphanenin elinde yazı tipinin dosyası yoktur. SVG'de yazılar dosyayı açan programın sans-serif yazı tipiyle, PDF'te her PDF okuyucusunda bulunan Helvetica ile yazılır. Bu yazı tiplerinin harfleri uygulamanınkinden dar ya da geniş olabilir; her satır, ekranda kapladığı yerin ortasına yazılır. Bir eksenin yanındaki sayı bu yüzden eksene bir iki piksel yakın ya da uzak durabilir.

PDF'te Helvetica, Batı Avrupa dillerinin ve Türkçenin harflerini yazar (Türkçenin altı harfi için dosya kendi kodlamasını taşır). İçinde Helvetica'nın yazamadığı bir harf olan satır (Arapça bir ad, ₺ işareti) sayfaya kendi resmi olarak konur: ekran yoğunluğunun dört katı keskinlikte, ama öteki her şey gibi sonsuz keskin değil, ve metin olarak seçilemez.

3. Dosyayı kullanıcıya ulaştırmak

onExport bir ChartExportFile alır: name, mimeType, format, bytes. Onu kullanıcıya foundation'ın FileSaver'ı verir: her platformun kaydetme penceresi (dosyalar rehberi, 3.4).

PlatformAlışılmış yolNe ister
Android"Farklı kaydet" (ACTION_CREATE_DOCUMENT), FileSaver'ın yolu; ya da paylaşım sayfası (Intent.ACTION_SEND)Kaydetmek için bir Activity sonucu; paylaşmak için manifestte bir FileProvider
iOSDosyalar'a aktarma (UIDocumentPickerViewController), FileSaver'ın yolu; ya da paylaşım sayfası (UIActivityViewController)Geçici bir dosya ve pencereyi sunacak bir görünüm denetleyicisi
MasaüstüKaydetme penceresiYok
WebTarayıcının indirmesiYok

FileSaver paylaşım sayfasını açmaz: Android'de paylaşmak bir FileProvider ve bir yol dosyası ister, ve kütüphane onları kendi manifestinde tanımlasa kütüphaneyi kullanan her uygulamaya bir sağlayıcı eklenirdi. Dosyayı bir mesaja ya da bir e-postaya vermek isteyen uygulama sayfayı kendisi açar, aşağıdaki iki parça gibi.

Grafik örneklerindeki dışa aktarma örneği (ChartExported) üretilen dosyayı önce gösterir, "Dosyayı kaydet" düğmesiyle de kütüphanenin kaydedicisine verir:

val saver = rememberFileSaver()
PantrixLineChart(
    // ...
    export = ChartExport { file ->
        saver.save(PantrixFile(file.name, file.bytes, file.mimeType)) { result -> saved = result }
    }
)

Aşağıdaki iki parça, 2026-10-28'e kadar demonun kendi kaydedicisiydi (app/shared'deki com.pantrixui.cmp.demo.platform paketi); demo kütüphanenin kaydedicisine geçince kaldırıldılar, paylaşmak isteyen bir uygulama için burada duruyorlar.

Android: paylaşım sayfası

val context = LocalContext.current
// save:
val folder = File(context.cacheDir, "exports").apply { mkdirs() }
val file = File(folder, name).apply { writeBytes(bytes) }
val uri = FileProvider.getUriForFile(context, context.packageName + ".files", file)
val send = Intent(Intent.ACTION_SEND)
    .setType(mimeType)
    .putExtra(Intent.EXTRA_STREAM, uri)
    .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
context.startActivity(Intent.createChooser(send, name))

Sayfada seçilen uygulama dosyayı FileProvider'ın verdiği adresle okur. Sağlayıcı uygulamanın manifestinde tanımlanır ve önbellekte yalnızca bir klasörü açar:

<!-- AndroidManifest.xml, <application> içinde -->
<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.files"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>
<!-- res/xml/file_paths.xml -->
<paths>
    <cache-path name="exports" path="exports/" />
</paths>

FileProvider, androidx.core kitaplığındadır (androidx.core.ktx, uygulamanın androidMain'ine eklenir). Manifestteki authorities koddaki adresle aynı olmalıdır; değilse getUriForFile hata fırlatır. Dosya klasörün dışındaysa da öyle.

iOS: paylaşım sayfası

val path = NSTemporaryDirectory() + name
val data = if (bytes.isEmpty()) {
    NSData()
} else {
    bytes.usePinned { NSData.create(bytes = it.addressOf(0), length = bytes.size.toULong()) }
}
data.writeToFile(path, atomically = true)
var top = UIApplication.sharedApplication.keyWindow?.rootViewController
while (top?.presentedViewController != null) top = top.presentedViewController
val sheet = UIActivityViewController(listOf(NSURL.fileURLWithPath(path)), null)
sheet.popoverPresentationController?.sourceView = top?.view
top?.presentViewController(sheet, animated = true, completion = null)

"Dosyalara Kaydet" de sayfanın içindedir. Sayfa en üstteki görünüm denetleyicisinden sunulur: başka bir denetleyiciyi sunmakta olan bir denetleyici ikinci bir sunumu reddeder. iPad'de sayfa bir açılır pencere olarak sunulur ve neye bağlanacağını (popoverPresentationController.sourceView) ister. NSData.create'e boş bir dizinin adresi verilemez: boş dosya ayrı yazılır.

4. Bilinmesi gerekenler

5. Otomasyon ve bildirim

Dışa aktarma düğmesinin etiketi grafiğin kendi etiketinin ardından .Export'tur: Chart_<tagKey>.Export, PieChart_<tagKey>.Export, Gantt_<tagKey>.Export ve ötekiler. Tür seçimi açılıyorsa satırlarının etiketleri .Export_png, .Export_svg ve .Export_pdf'tir. Bir dosya üretilince grafiğin kendi bileşen adıyla (Chart, PieChart, Gauge, Gantt …) export olayı bildirilir; format özelliği dosyanın uzantısıdır (png, svg, pdf). Dosyanın adı ve içeriği bildirilmez.

6. Nasıl doğrulandı

NeNerede
Çizimin çizgi, şekil ve söz olarak saklanması; SVG ve PDF'in yazımı; PDF'in parça tablosu ve akış uzunluğuChartExportFilesTest (masaüstü, iOS simülatörü ve iki tarayıcı hedefi)
Düğme, tür seçimi ve kapanması, dosyanın adı ve türü, PNG'nin piksel boyutu, zemin, pay, ekran yoğunluğu, görünen kısım, çıkarılan seri, kesikli çizgiler, işaretler, değer etiketleri, eksen başlığı, Arapça adın PDF'teki resmiChartExportTest (aynı dört hedef)
Resmin lejantı: satırlar, ortalama, örnek ve ad, sağdan sola, en yüksek ada göre satırChartExportLegendTest (aynı dört hedef)
Öteki on dört tür: düğmenin yeri, her türün dosyasının adı, olayı ve yazıları, gösterilen yerin dosyada olmaması, pasta ve gauge ortası, heatmap'in ölçeği ve sağdan sola, düğme satırının yükseklikle ilişkisiChartExportKindsTest (aynı dört hedef)
Öteki türler web'de2026-10-15'te web demosunda pasta, heatmap, gauge, ilerleme halkası, sparkline ve Gantt'ın PNG'si üretilip ekrandakiyle karşılaştırıldı (fare altındaki hücrenin tooltip'i dosyada yoktu); SVG ve PDF'leri bir tarayıcıda açılmadı
PNG'nin pikselleri: çevrede zemin, içeride grafikChartExportDesktopTest (masaüstü, Skia ile geri okunur), ChartExportOnAndroidTest (Android, Robolectric: Android'in kendi bitmap'iyle)
Üç türün görünüşüMasaüstünde üretilen dosyalara macOS'un çizimiyle (Quick Look, sips) bakıldı: ekran yoğunluğu 1 ve 2,75
Android'de üretimEmülatörde (ekran yoğunluğu 3,5) üç tür üretildi; PNG demoda geri gösterildi, üç dosya cihazdan alınıp macOS'ta çizildi
iOS'ta üretimSimülatörde (ekran yoğunluğu 3) üç tür üretildi; PNG demoda geri gösterildi, üç dosya simülatörden alınıp macOS'ta çizildi
Demonun eski kaydedicisi olarak dört platformda derlendi. iOS simülatöründe PDF seçilip "Dosyayı kaydet"e basıldı: paylaşım sayfası dosyanın adıyla, türüyle ve boyutuyla açıldı ("visits", PDF, 5 KB), "Dosyalara Kaydet" sayfadaydı; bir yere kaydedilmedi. Kütüphanenin kaydedicisinin nerede denendiği dosyalar rehberindedir

Doğrulanamayanlar: eksenli grafiğin dosyalarına web'de bakılamadı (tarayıcı paneli ekranda değildi; testler tarayıcıda koşuyor ama üretilen dosya bir tarayıcıda açılmadı); öteki türlerin web'de yalnızca PNG'sine bakıldı, Android ve iOS'ta dosyalarına bakılmadı; PDF'e Adobe Acrobat, Chrome ve Firefox'un çizimiyle bakılmadı (yalnızca macOS'unkiyle); SVG'ye bir tarayıcıda ve bir çizim programında bakılmadı (yalnızca macOS'un Quick Look'uyla); 3. bölümdeki Android paylaşım parçası yalnızca derlendi, denenmedi; basılı çıktıya bakılmadı; gerçek bir telefonda denenmedi.