G9.js: Otomatik Etkileşimli Grafikler
(omrelli.ug)- g9.js, sayısal anahtar-değer verilerini bir render fonksiyonuna bağlayan; kullanıcı grafik öğelerini sürüklediğinde yeni veri değerlerini bulup tüm sahneyi yeniden çizen etkileşimli bir grafik kütüphanesidir
- Temel API yalnızca
g9(initialData, render[, onChange])şeklindedir;initialDatave çizim bağlamınırender(data, ctx)içine aktararak nokta, çizgi, daire, görüntü vb. çizer - Sürükleme gibi bir etkileşim gerçekleştiğinde g9, amaçlanan değişime en yakın değerleri bulmak için olası veri değerleri uzayını optimize eder ve gerekirse yeni veriyi
onChangeile iletir - Galeri, temel nokta aynalamadan Bézier eğrilerine, üç noktayla tanımlanan daireye, küpe, dragon eğrisine, görüntülere, saate, LOGO Turtle’a, Grid Warp’a ve Crank and Piston’a kadar örnekleri aşamalı olarak gösterir
affects,ctx.pure,getData,setData,isManipulating,Math.max/Math.mingibi kalıplarla manipüle edilebilir değişken aralıkları, yeniden render etme ve animasyon sırasında kullanıcı girdisini işleme kurgulanabilir
g9.js’in çalışma akışı
- g9.js tek bir fonksiyon sunar:
g9(initialData, render[, onChange]) - Önce sayısal değerlere sahip anahtar-değer verisi oluşturulur
- Örnekte
foo: 10gibi birinitialDatanesnesi kullanılır - İlgili belge dokümanlardaki initialData bölümündedir
- Örnekte
- Veri ve çizim bağlamı
render(data, ctx)içine aktarılır; render fonksiyonu veri değerlerine göre ne çizileceğine karar verir- Örnekte
ctx.point(data.foo, 17)ile bir nokta çizilir - İlgili belge dokümanlardaki render bölümündedir
- Örnekte
- Kullanıcı bir öğeyi yeni bir konuma sürüklediğinde g9, olası veri değerleri uzayında en yakın değişimi üreten değeri bulur
- Daire sola sürüklenirse örnekte
{foo: 8}gibi yeni bir veri ortaya çıkabilir
- Daire sola sürüklenirse örnekte
- Yeni veri belirlendiğinde tutarlılığı korumak için tüm sahne yeniden render edilir
onChangecallback’i sağlanmışsa g9, sayfanın diğer bölümlerinin güncellenebilmesi için yeni veriyi aktarır
- API’nin tamamı Docs içinde görülebilir
Temel şekiller ve veri kısıtları
- Basic örneği yalnızca iki nokta kullanan en küçük örnektir
- Render fonksiyonu bir noktayı
(x, y)konumuna, diğerini(y, x)konumuna çizer - Bir nokta sürüklendiğinde diğer nokta, birbirlerini aynalıyormuş gibi hareket eder
- Render fonksiyonu bir noktayı
- Rings,
radiusveangleverilerini trigonometrik fonksiyonlara vererek noktaları iki daire biçiminde yerleştirir- İç noktalar kırmızı çizilir
- Yorum satırına alınmış
ctx.line(...)açılırsa iki dairenin noktaları arasına çizgi eklenebilir
- The affects option, g9’un temel şekillerinin aldığı
affectsseçeneğini gösteriraffects, şeklin verinin hangi bölümünü değiştirebileceğini belirtir- Üç çizgi farklı
affectsdeğerleri kullanır - Bir çizgi yalnızca
l2_start_x,l2_start_ydeğerlerini değiştirirken, başka bir çizgil3_start_x,l3_end_ydeğerlerini değiştirir
- Using Max and Min to limit a point's range of motion,
Math.max(Math.min(...))ile bir noktanın hareket aralığını sınırlar- Ortadaki noktanın konumu
x1 + 20ilex3 - 20arasında sınırlandırılır - Ayrı bir nokta
data.x2değerini olduğu gibi gösterir
- Ortadaki noktanın konumu
Eğriler, geometri ve 3D örnekleri
- Bézier Curve, Wikipedia’daki quadratic Bézier curve animasyonunu etkileşimli bir sürüme dönüştüren örnektir
- Veri olarak
start,middle,endkoordinatları vetdeğeri kullanılır tween=etiketi gösterilir ve çeşitli aşamalardaki çizgi parçalarıyla yumuşak bir eğri oluşturulur- Ara yardımcı çizgilere ve eğri parçalarına
affects: ['t']atanır
- Veri olarak
- Three points define a circle, üç noktayla bir daire tanımlar
- Üç nokta arasındaki çizgi parçalarını, orta noktaları ve dik doğrultulu çizgileri hesaplar
- Hesaplanan merkeze bir nokta koyar ve birinci noktaya olan mesafeyi yarıçap alan yeşil bir daire çizer
- cube, küpün köşelerini ve kenarlarını oluşturup 3D döndürme, taşıma ve projeksiyon işlemlerinden geçirerek 2D çizgiler olarak çizer
rx,ry,rzfonksiyonlarıyla eksen döndürmeleri hesaplanırprojectfonksiyonu300 * p[0] / p[2],300 * p[1] / p[2]yöntemiyle projeksiyon yapar- Kenarlar, sürükleyerek döndürme değerlerini değiştirebilmek için
affects: ['ax', 'ay']kullanır
Fraktallar, prosedürel çizim ve görüntüler
- dragon,
dragon(...)özyinelemeli fonksiyonuyla dragon eğrisini çizer- Veri
squareness,fromX,fromY,toX,toYdeğerlerini içerir - Çizgi seçenekleri, eğri biçimini manipüle etmek için
affects: ['squareness']kullanır - Başlangıç ve bitiş noktaları yarıçapı
5olan noktalarla gösterilir
- Veri
- tree, ağacı özyinelemeli olarak çizer
- Veri
deltaAngle,attenuation,startLengthdeğerleridir - Dal uçları ve çizgiler
affects: ['deltaAngle', 'attenuation']kullanır n > 3ise çizgi rengi kahverengi, aksi durumda yeşil çizilironChangecallback’i değişen veriyi konsola yazdırır
- Veri
- LOGO Turtle simulator,
make_turtle(ctx)ile basit bir Turtle arayüzü oluşturur ve çizgileri tekrarlı olarak çizer- Veri
rvethetadeğerleridir forwardmevcut yönde ilerleyerek çizgi çizer;dturnderece cinsinden dönüşü radyana çevirir
- Veri
- Grid Warp, ızgara noktalarını büken bir dönüşüm uygular
- Veri
spinvescaledeğerleridir - Her noktanın uzaklığı
rve açısıthetahesaplandıktan sonra dönüş miktarıtheta + data.spin * rile değiştirilir -10ile10arasındakii,jkombinasyonlarıyla noktalar çizilir
- Veri
- image,
ctx.imageile görüntü çizer- Görüntü URL’si,
x,y, genişlik200ve yükseklik200belirtilir
- Görüntü URL’si,
Mekanik düzenekler ve zaman tabanlı etkileşim
- Kevin Clock,
timeverisini kullanarak saat biçimli bir çizim yapar- Dakika ibresi
data.time / 60, saniye ibresidata.timekullanılarakMath.cos,Math.sinile uç noktaları hesaplar setInterval, her 50 ms’de birtimedeğerini0.01artırır- Yalnızca
graphics.isManipulatingdoğru değilkengetData()vesetData(data)ile zamanı günceller
- Dakika ibresi
- Crank and Piston, krank ve piston yapısını çizer
- Veri yalnızca
timedeğeridir - Gövde rengi,
Math.cos(data.time)ile oluşturulan HSL değerine göre değişir - Krank, mil ve piston çizgiler, dikdörtgenler ve dairelerle çizilir
- Animasyon bloğu yorum satırına alınmıştır; açılırsa her 10 ms’de bir
timedeğerini0.05artıracak şekilde düzenlenmiştir
- Veri yalnızca
- tongs, döndürme ve tekrarlanan çizgi parçalarıyla maşa biçimli bir yapı oluşturur
- Veri
a,bdeğerleridir rotate(x, y, a)ile koordinatları döndürür ve dört tekrar ile iki sıra çizgi parçası çizeronChangecallback’i değişen veriyi konsola yazdırır
- Veri
1 yorum
Hacker News yorumları
Özyinelemeli ağacın 5-6 seviye derinliğinde render edilmiş bir düğümü tutup hareket ettirdiğinizde, ağacın geri kalanının tepki vermesi sihir gibi görünüyor.
Herhangi bir yaprak düğüm konumundan ağacın başlangıç parametrelerini açıkça çıkaran bir fonksiyon olmadan da çalışıyor.
Bunun nasıl uygulandığını ve noktaların konumları makul ölçüde düzgün bir fonksiyonla bağlı olmadığında ne kadar iyi çalıştığını merak ediyorum.
Ya da hazır bir optimizasyon çözücüyü koymak da mümkün olabilir.
Ters kinematik problemini modellemenin ve çözmenin birçok yolu var.
Bunların en esnek olanları genellikle yinelemeli optimizasyonla yaklaşık çözümler bulur; çünkü ileri kinematik denklemlerini tersine çözmek zordur ve çözüm uzayı boş da olabilir.
Birçok yöntemin özünde, ileri kinematik denklemlerini Taylor serisi açılımı ile modellemek vardır; bu, tersine çözmesi özgün sisteme göre daha kolay olabilir.
İlk başta bunun havalı ve temiz, basit bir API olduğunu düşündüm; aynı işi yapmak için d3'ten daha çok hoşuma giderdi.
Ama “Birisi grafikle etkileşime geçtiğinde, örneğin bir öğeyi yeni bir konuma sürüklemeye çalıştığında, g9 olası veri değerleri uzayında optimizasyon yaparak bu değişime en yakın değeri bulur” kısmını okuyunca, bu bana epey sihirli bir DOM manipülasyonu gibi geldi.
Bir grafiği manipüle edip veriyi değiştirmesi gereken uygulamaların çoğu oldukça özel görünüyor; ama eğlence amaçlı kullanım evrensel.
Böyle bir kullanım senaryosu gelirse çok keyifli olur.
Sayfadaki diğer örnekleri de doğrudan kurcalayıp kurcalamadığını merak ediyorum.
Sürükleme olayının ilk birkaç karesinde hızı ve vektörü ortalayıp, daha fazla kareyle ortalamayı güncellemeye devam ettikten sonra, tahmin edilen bitiş noktasına doğru her şeyi yumuşak bir ease-in-out ile hareket ettirmeye başlarsanız, bu “olası değerler uzayında optimizasyon”a epey yaklaşır.
Bu daha önce HN'de tartışıldığında ilginç yorumlar vardı: https://news.ycombinator.com/item?id=12572412
Nasıl çalıştığına dair bir açıklama görmek isterim. Bana kara büyü gibi geliyor.
Örneğin iki nokta var; biri (0, 10), diğeri (10, 0) konumunda. Arkadaki noktayı (20, 0)'a sürüklersem, sistem ilk noktanın da aynı mesafe kadar yansıtılması gerektiğini nasıl anlıyor?
Tekrar edeyim, bu sihir ve yapan kişi gerçekten iyi iş çıkarmış.
Bu fonksiyonun veri değişkenlerine göre kısmi türevini alıyor, fonksiyonu minimize ederek yeni veri değerini buluyor ve ardından her şeyi yeni optimum veri değeriyle tekrar render ediyor.
Biraz kafa karıştırıcı olmasının nedeni, burada genelde “veri” dediğimiz şeyin matematiksel optimizasyonda parametre, istatistik/makine öğrenmesinde ise ağırlık diye adlandırılabilecek şey olması.
Makine öğrenmesinde sabit olana “veri” denirdi; dolayısıyla burada sürüklenen öğenin konumu veriye karşılık geliyor.
Oldukça havalı görünüyor.
Bir eksik yanı, işaretçi ya da seçim göstergesi olmaması; açıklamayı önce okumazsanız nesnelerin sürüklenebildiği pek anlaşılmıyor.
Nesne konumunu yeniden ayarlama biçimi de biraz kafa karıştırıcı.
Normalde bir pointer handler tanımlar ve girdiye göre dönüşüm uygularsınız; doğru anladıysam motor bunu otomatikleştirmek için en iyi tahminini yapmaya çalışıyor.
Birkaç yıl önce bunu görüp heyecanlanmıştım; tarayıcıda PyTorch benzeri bir kütüphaneyle birlikte çalışması için Pyodide'a port etmiştim: https://srush.github.io/g9py/
JavaScript'ten biraz daha takılıyor, ama en başta çalışıyor olması bile şaşırtıcı.
Bu cadılık gibi hissettiriyor. Son derece etkileyici.
2D CAD'deki kısıt tabanlı çizim araçlarıyla ortak noktaları var gibi görünüyor.
Nerede kullanılması gerektiğinden pek emin değilim, ama gerçekten zekice yapılmış.
Probleme bakış biçimi o kadar farklı ki, kavrayabilmek için bir şeyde bizzat kullanmam gerekecek.
Eğitim ortamlarında trigonometri veya diğer matematik kavramlarını aktarmak için çok faydalı olabilir.
Formülleri görsel uzamla eşleştirmekte zorlanan çok sayıda görsel öğrenen var; biraz etkileşim eklemek, anlayışı pekiştirmede büyük yardımcı olur.