8 điểm bởi GN⁺ 2023-08-10 | 1 bình luận | Chia sẻ qua WhatsApp
  • g9.js là một thư viện đồ họa tương tác liên kết dữ liệu khóa-giá trị dạng số với hàm render; khi người dùng kéo các phần tử đồ họa, nó tìm ra giá trị dữ liệu mới rồi vẽ lại toàn bộ khung cảnh
  • API cốt lõi chỉ có g9(initialData, render[, onChange]); nó truyền initialData và ngữ cảnh vẽ vào render(data, ctx) để vẽ điểm, đường thẳng, hình tròn, ảnh, v.v.
  • Khi có thao tác như kéo thả, g9 sẽ tối ưu hóa trong không gian các giá trị dữ liệu khả dĩ để tìm giá trị gần nhất với thay đổi mong muốn, và nếu cần thì truyền dữ liệu mới qua onChange
  • Phần gallery trình bày dần các ví dụ từ phản chiếu điểm cơ bản đến đường cong Bézier, đường tròn xác định bởi ba điểm, khối lập phương, đường cong rồng, ảnh, đồng hồ, LOGO Turtle, Grid Warp và Crank and Piston
  • Có thể tổ chức phạm vi biến có thể thao tác, re-render và xử lý đầu vào người dùng trong lúc animation bằng các mẫu như affects, ctx.pure, getData, setData, isManipulating, Math.max/Math.min

Luồng hoạt động của g9.js

  • g9.js cung cấp một hàm duy nhất là g9(initialData, render[, onChange])
  • Trước tiên tạo dữ liệu khóa-giá trị gồm các giá trị số
  • Dữ liệu và ngữ cảnh vẽ được truyền vào render(data, ctx), và hàm render quyết định sẽ vẽ gì dựa trên các giá trị dữ liệu
    • Ví dụ vẽ một điểm bằng ctx.point(data.foo, 17)
    • Tài liệu liên quan có tại render in the docs
  • Khi người dùng kéo một phần tử sang vị trí mới, g9 sẽ tìm giá trị trong không gian dữ liệu khả dĩ tạo ra thay đổi gần nhất
    • Nếu kéo hình tròn sang trái, trong ví dụ có thể sinh ra dữ liệu mới như {foo: 8}
  • Khi dữ liệu mới được xác định, toàn bộ khung cảnh sẽ được render lại để giữ tính nhất quán
    • Nếu có cung cấp callback onChange, g9 sẽ truyền dữ liệu mới để có thể cập nhật các phần khác của trang
  • Toàn bộ API có thể xem trong Docs

Hình cơ bản và ràng buộc dữ liệu

  • Ví dụ Basic là ví dụ tối thiểu chỉ dùng hai điểm
    • Hàm render vẽ một điểm tại (x, y) và điểm còn lại tại (y, x)
    • Khi kéo một điểm, điểm kia sẽ di chuyển như thể phản chiếu lẫn nhau
  • Rings đưa dữ liệu radiusangle vào các hàm lượng giác để bố trí các điểm thành hai vòng tròn
    • Các điểm bên trong được vẽ màu đỏ
    • Nếu bỏ chú thích ctx.line(...) thì có thể thêm các đường nối giữa các điểm của hai vòng tròn
  • The affects option cho thấy tùy chọn affects mà các hình cơ bản của g9 hỗ trợ
    • affects chỉ định một hình có thể thay đổi phần nào của dữ liệu
    • Ba đường thẳng sử dụng các giá trị affects khác nhau
    • Một đường chỉ thay đổi l2_start_x, l2_start_y, còn đường khác thay đổi l3_start_x, l3_end_y
  • Using Max and Min to limit a point's range of motion giới hạn phạm vi di chuyển của điểm bằng Math.max(Math.min(...))
    • Vị trí của điểm ở giữa bị giới hạn trong khoảng từ x1 + 20 đến x3 - 20
    • Một điểm riêng biệt hiển thị nguyên giá trị data.x2

Ví dụ về đường cong, hình học và 3D

  • Bézier Curve là ví dụ biến hoạt ảnh đường cong Bézier bậc hai trên Wikipedia thành phiên bản tương tác
    • Dữ liệu dùng các tọa độ start, middle, end và giá trị t
    • Nó hiển thị nhãn tween= và tạo đường cong mượt bằng nhiều đoạn thẳng theo từng bước
    • Các đường phụ trung gian và các đoạn của đường cong có gắn affects: ['t']
  • Three points define a circle xác định một đường tròn bằng ba điểm
    • Nó tính các đoạn thẳng giữa ba điểm, trung điểm và các đường theo phương vuông góc
    • Nó đặt một điểm tại tâm đã tính được và vẽ một đường tròn màu xanh lá với bán kính là khoảng cách tới điểm đầu tiên
  • cube tạo các đỉnh và cạnh của khối lập phương rồi vẽ chúng thành các đường 2D sau khi xoay, tịnh tiến và chiếu 3D
    • Các hàm rx, ry, rz tính phép quay theo trục
    • Hàm project chiếu theo cách 300 * p[0] / p[2], 300 * p[1] / p[2]
    • Các cạnh dùng affects: ['ax', 'ay'] để thay đổi giá trị góc quay bằng thao tác kéo

Fractal, vẽ thủ tục và hình ảnh

  • dragon vẽ đường cong rồng bằng hàm đệ quy dragon(...)
    • Dữ liệu gồm squareness, fromX, fromY, toX, toY
    • Tùy chọn đường thẳng dùng affects: ['squareness'] để điều khiển hình dạng đường cong
    • Điểm bắt đầu và điểm kết thúc được hiển thị bằng các điểm có bán kính 5
  • tree vẽ cây theo cách đệ quy
    • Dữ liệu gồm deltaAngle, attenuation, startLength
    • Đầu cành và các đường thẳng dùng affects: ['deltaAngle', 'attenuation']
    • Nếu n > 3 thì vẽ đường màu nâu, ngược lại vẽ màu xanh lá
    • Callback onChange in dữ liệu đã thay đổi ra console
  • LOGO Turtle simulator tạo một giao diện Turtle đơn giản bằng make_turtle(ctx) và lặp lại việc vẽ đường
    • Dữ liệu gồm rtheta
    • forward di chuyển theo hướng hiện tại đồng thời vẽ đường, còn dturn đổi góc quay theo độ sang radian
  • Grid Warp áp dụng một phép biến đổi làm bẻ cong các điểm trên lưới
    • Dữ liệu gồm spinscale
    • Sau khi tính khoảng cách r và góc theta của mỗi điểm, nó thay đổi lượng quay bằng theta + data.spin * r
    • Nó vẽ các điểm với mọi tổ hợp i, j từ -10 đến 10
  • image vẽ ảnh bằng ctx.image
    • Nó chỉ định URL ảnh, x, y, chiều rộng 200, chiều cao 200

Cơ cấu cơ khí và tương tác theo thời gian

  • Kevin Clock vẽ một chiếc đồng hồ bằng dữ liệu time
    • Kim phút dùng data.time / 60, còn kim giây dùng data.time để tính điểm cuối bằng Math.cos, Math.sin
    • setInterval tăng time thêm 0.01 mỗi 50ms
    • Chỉ khi graphics.isManipulating không phải true thì thời gian mới được cập nhật bằng getData()setData(data)
  • Crank and Piston vẽ cơ cấu tay quay và pít-tông
    • Dữ liệu chỉ có một giá trị là time
    • Màu của vỏ máy thay đổi theo giá trị HSL tạo bằng Math.cos(data.time)
    • Nó vẽ tay quay, trục và pít-tông bằng đường thẳng, hình chữ nhật và hình tròn
    • Khối animation đang bị chú thích; nếu bỏ chú thích, nó sẽ tăng time thêm 0.05 mỗi 10ms
  • tongs tạo hình chiếc kẹp bằng phép quay và các đoạn thẳng lặp lại
    • Dữ liệu gồm a, b
    • rotate(x, y, a) xoay tọa độ, và qua bốn lần lặp nó vẽ hai hàng đoạn thẳng
    • Callback onChange in dữ liệu đã thay đổi ra console

1 bình luận

 
GN⁺ 2023-08-10
Ý kiến trên Hacker News
  • Khi nhấc một nút được render ở độ sâu khoảng 5–6 tầng trong cây đệ quy rồi di chuyển nó, việc phần còn lại của cây phản ứng trông như phép màu
    Nó vẫn hoạt động dù không có hàm nào suy luận tường minh các tham số ban đầu của cây từ vị trí của một nút lá tùy ý
    Tôi tò mò không biết nó được triển khai thế nào, và hoạt động tốt đến đâu khi vị trí các điểm không được nối với nhau bằng một hàm đủ trơn tru

    • Tôi đoán là với đối tượng bị di chuyển, họ lấy mẫu hàm hai lần để tính đạo hàm riêng cho ảnh hưởng của từng tham số, rồi chạy gradient descent thông thường, sau đó lặp lại cho đến khi hội tụ
      Hoặc cũng có thể chỉ cần ném vào một bộ tối ưu hóa có sẵn là được
    • Có lẽ cách làm tương tự inverse kinematics
      Có nhiều cách để mô hình hóa và giải bài toán inverse kinematics
      Những cách linh hoạt nhất trong số đó thường tìm nghiệm xấp xỉ bằng tối ưu hóa lặp, vì khó giải ngược các phương trình forward kinematics và không gian nghiệm cũng có thể rỗng
      Cốt lõi của nhiều phương pháp là mô hình hóa các phương trình forward kinematics bằng khai triển chuỗi Taylor, thứ có thể dễ đảo ngược để giải hơn hệ ban đầu
  • Ban đầu tôi nghĩ đây là một API đơn giản, hay và gọn gàng; nếu làm cùng một việc thì tôi thích nó hơn d3
    Nhưng sau khi đọc câu “khi ai đó tương tác với đồ họa, ví dụ cố kéo một phần tử sang vị trí mới, g9 sẽ tối ưu hóa trong không gian các giá trị dữ liệu khả dĩ để tìm giá trị gần nhất với thay đổi đó”, tôi thấy đây giống một kiểu thao tác DOM có tính ma thuật khá rõ
    Phần lớn ứng dụng cần thao tác biểu đồ để thay đổi dữ liệu có vẻ khá đặc thù, nhưng dùng để tạo sự thú vị thì lại rất phổ biến
    Nếu gặp đúng use case như vậy thì chắc sẽ rất vui

    • Nó không dành cho biểu đồ, mà dành cho demo tương tác
      Tôi tò mò không biết bạn đã thử trực tiếp các ví dụ khác trên trang chưa
    • Xét về ứng dụng, có rất nhiều khái niệm STEM có thể được truyền đạt hiệu quả nếu cho phép tương tác
    • Tôi sẽ không gọi đó là khoa học cao siêu
      Nếu trong vài frame đầu của sự kiện kéo, bạn lấy trung bình tốc độ và vector, tiếp tục cập nhật trung bình với nhiều frame hơn, rồi bắt đầu di chuyển mọi thứ tới điểm kết thúc dự đoán bằng ease-in-out mượt mà, thì cũng đã khá gần với “tối ưu hóa trong không gian các giá trị khả dĩ” rồi
  • Hồi trước khi cái này được thảo luận trên HN đã có vài bình luận thú vị: https://news.ycombinator.com/item?id=12572412

  • Tôi muốn xem phần giải thích nó hoạt động thế nào. Với tôi nó giống ma thuật hắc ám
    Ví dụ có hai điểm, một điểm ở (0, 10), điểm kia ở (10, 0); nếu kéo điểm sau tới (20, 0), làm sao hệ thống biết rằng điểm đầu cũng phải được phản chiếu cùng một khoảng cách như vậy?
    Nói lại lần nữa, đây là phép màu, và người tạo ra nó đã làm rất tốt

    • Họ định nghĩa một hàm đo sai số giữa vị trí của phần tử được vẽ và vị trí mới mà thao tác kéo yêu cầu
      Lấy đạo hàm riêng của hàm này theo các biến dữ liệu, tối thiểu hóa hàm để tìm giá trị dữ liệu mới, rồi render lại toàn bộ với giá trị dữ liệu tối ưu mới
      Lý do hơi dễ gây nhầm là thứ ở đây thường được gọi là “dữ liệu” thì trong tối ưu hóa toán học lại đáng gọi là tham số, còn trong thống kê/machine learning là trọng số
      Trong machine learning, thứ cố định mới được gọi là “dữ liệu”, nên ở đây vị trí của phần tử bị kéo mới tương ứng với dữ liệu
    • Toán học đủ phát triển thì không thể phân biệt với ma thuật, chỉ là tiêu chuẩn cho “đủ phát triển” ở đây thấp hơn ta tưởng
  • Trông khá ngầu
    Một điểm hơi tiếc là không có marker hay dấu hiệu chọn, nên nếu chưa đọc phần mô tả trước thì không rõ lắm là có thể kéo các đối tượng
    Cách điều chỉnh lại vị trí đối tượng cũng hơi khó hiểu
    Thông thường ta sẽ định nghĩa pointer handler rồi biến đổi theo input, nhưng nếu tôi hiểu đúng thì có vẻ engine đang tự động hóa việc đó bằng phỏng đoán tốt nhất của nó

  • Vài năm trước tôi thấy cái này và hào hứng đến mức đã port nó sang Pyodide để chạy trong trình duyệt cùng một thư viện na ná PyTorch: https://srush.github.io/g9py/
    Nó hơi giật hơn JavaScript một chút, nhưng việc nó chạy được ngay từ đầu đã đáng kinh ngạc rồi

  • Cái này giống phù thủy thuật. Cực kỳ ấn tượng

  • Có vẻ có điểm chung với các công cụ phác thảo dựa trên ràng buộc trong 2D CAD

  • Tôi không rõ nên dùng nó vào đâu, nhưng nó được làm rất thông minh

    • Về tiềm năng thì có vẻ có thể dùng cho bất kỳ giao diện kéo thả nào
      Cách nhìn vấn đề khác quá nhiều, nên chắc tôi phải tự dùng nó vào thứ gì đó để nắm được cảm giác
  • Nó có thể rất hữu ích trong giáo dục để truyền đạt lượng giác hoặc các khái niệm toán học khác
    Có nhiều người học thiên về thị giác gặp khó khăn khi ánh xạ công thức vào không gian trực quan; thêm một chút tương tác sẽ giúp củng cố hiểu biết rất nhiều