Trang chủ Kiến Thức Công Nghệ React Native – Hướng dẫn làm việc với Polyline và Animated-Polyline trên Map
Công Nghệ

React Native – Hướng dẫn làm việc với Polyline và Animated-Polyline trên Map

Chia sẻ
Chia sẻ

Vẽ đường đi trên bản đồ là một nghiệp vụ vô cùng quan trọng. Các ứng dụng gọi xe, giao hàng, đặt món ăn trên thị trường hiện nay, có thể kể đến Grab, Now, Baemin, Be… đều đang sử dụng chức năng này. Bài viết này sẽ hướng dẫn mọi người sử dụng React Native để vẽ đường đi trên bản đồ (Google Map) và tối ưu ứng dụng khi vẽ đường đi đó cùng với Animation (diễn hoạt).

Polyline là gì?

Polyline (đường đa tuyến) trong bản đồ (Google Map) là một tập hợp bao gồm nhiều điểm (point) và các đoạn thẳng nối các điểm liền kề. Mặc định, Polyline thường không được đóng hay khép kín. Để tạo thành một Polyline khép kín, điểm đầu và điểm cuối phải giống nhau.

Trong Google Maps, Polyline được sử dụng để vẽ lên bản đồ nhằm diễn đạt chỉ đường, phương hướng để đi được từ điểm này đến điểm khác.

Cách vẽ Polyline trong React Native:

Để vẽ được 1 đường đi trên bản đồ, ta phải có danh sách các toạ độ. Đường đi ấy được tạo thành bởi nhiều đoạn thẳng nhỏ nối các điểm liền kề trên danh sách tọa độ này.

Ví dụ: chúng ta có một mảng 16 điểm, và khi nối 16 điểm này lại (bằng 15 đoạn thẳng), ta có được đường đi. Lưu ý: bài viết sử dụng react-native và react-native-maps để code mẫu.
Code React Native mẫu:

JS

render() {
    const coordinates = [
      { latitude: 10.77309, longitude: 106.69835 },
      { latitude: 10.77281, longitude: 106.69853 },
      { latitude: 10.7731, longitude: 106.69882 },
      { latitude: 10.77371, longitude: 106.69944 },
      { latitude: 10.7734, longitude: 106.69978 },
      { latitude: 10.7736, longitude: 106.7 },
      { latitude: 10.77082, longitude: 106.70122 },
      { latitude: 10.77056, longitude: 106.70618 },
      { latitude: 10.76835, longitude: 106.7056 },
      { latitude: 10.76246, longitude: 106.70838 },
      { latitude: 10.75702, longitude: 106.71797 },
      { latitude: 10.75184, longitude: 106.72482 },
      { latitude: 10.75248, longitude: 106.72661 },
      { latitude: 10.75263, longitude: 106.728 },
      { latitude: 10.75238, longitude: 106.7284 },
      { latitude: 10.74475, longitude: 106.72915 },
    ];
    return (
      <MapView>
        <MapView.Polyline coordinates={coordinates} />
      </MapView>
    );
  }

Kết quả:

react-native-anmated-polyline

Cách vẽ Polyline với Animation (diễn hoạt):

Bây giờ để Polyline đó có Animation khi xuất hiện, rất đơn giản: ta chỉ cần cho các đoạn thẳng xuất hiện tuần tự nhau, đoạn này xong, tiếp đến đoạn khác, không xuất hiện cùng lúc, là ta sẽ có 1 Animation đơn giản.

Code React Native mẫu:

JS

componentDidMount() {
    this._animate();
  }

  _animate = () => {
    if (this._index >= this._coords.length) return;

    this.setState(
      ({ renderedCoords }) => ({ renderedCoords: [...renderedCoords, this._coords[this._index]] }),
      () => {
        this._index++;
        setTimeout(this._animate, 200);
      }
    );
  };
  
  render() {
    return (
      <MapView>
        <MapView.Polyline coordinates={this.state.renderedCoords} />
      </MapView>
    );
  }

Kết quả:

react-native-anmated-polyline

Phân tích code một chút, ở đây chúng ta có hàm _animate thực hiện thêm 1 toạ độ vào state, sau đó đợi 200ms và gọi lại chính mình. Từ đó ta có một vòng lặp và tất cả các điểm được thêm một cách tuần tự vào state. Kết quả nhận được có thể xem là tạm ổn, tuy nhiên chúng ta có thể làm nó tốt hơn nữa.

Có thể nhận thấy, chúng ta chỉ thêm tuần tự các điểm, mà chưa quan tâm đến độ dài của đoạn thẳng nối từ điểm cuối cùng đến điểm chúng ta sắp thêm vào.
Ví thế, đối với các đoạn thẳng ngắn thì animation ổn, nhưng đối với những đoạn thẳng dài thì chưa được vì chúng xuất hiện ngay lập tức.

Để giải quyết vấn đề này, ta có thể chia các đoạn thẳng dài thành các đoạn thẳng nhỏ hơn, và thay thế một đoạn dài bằng nhiều đoạn nhỏ tương ứng.
Chúng ta sẽ biến đổi mảng toạ độ ban đầu, thành một mảng toạ độ mới, với khoảng cách của các điểm liền kề luôn nhỏ hơn hoặc bằng một giá trị bất kỳ nào đó.

Code React Native mẫu sẽ như sau:

JS

componentDidMount() {
    // giá trị tối đa của một đoạn thẳng
    const MAX_DISTANCE = 100;

    // lưu danh sách độ sau khi biến đổi
    const newCoords = [];
    // ban đầu ta có toạ độ đầu tiên của danh sách toạ độ mới
    newCoords.push(this._coords[0]);

    // lặp qua tất cả các toạ độ
    for (let i = 1; i < this._coords.length; i++) {
      const lastIndex = newCoords.length - 1;
      const lastCoord = newCoords[lastIndex];
      const targetCoord = this._coords[i];

      // tính khoảng cách giữa toạ độ cuối cùng của danh sách toạ độ mới và toạ độ ban đầu đang xét
      // công thức tính có thể tìm ở đây: https://www.movable-type.co.uk/scripts/latlong.html
      const distance = calculateDistanceBetweenTwoPoints(lastCoord, targetCoord); 

      // nếu khoảng cách đó bé hơn hoặc bằng giá trị tối đa thì ta không cần biến đổi, thêm toạ độ gốc và danh sách
      if (distance <= MAX_DISTANCE) {
        newCoords.push(targetCoord);
        continue;
      }
      
      // ngược lại, nếu khoảng cách đó lớn hơn giá trị tối đa thì ta cần phải biến đổi
      // chia đoạn thẳng thành các đoạn nhỏ hơn, với số phần bằng tổng khoảng cách chia cho giá trị tối đa của một đoạn
      // ví dụ ta có khoảng cách = 500 và giá trị tối đa = 100 thì ta sẽ chia thành 5 phần nhỏ hơn
      const numberOfSegments = Math.ceil(distance / MAX_DISTANCE);

      // lần lượt tính toạ độ của các đoạn thẳng nhỏ hơn
      for (let j = 1; j < numberOfSegments; j++) {
        // tính phần trăm của đoạn nhỏ thứ j
        // ví dụ ta đang tính đoạn thứ 2, thì đoạn thứ 2 sẽ có chiều dài 200 và bằng 40% tổng khoảng cách
        const fraction = (MAX_DISTANCE * j) / distance;

        // tính toạ độ dựa trên điểm đầu, điểm cuối và phần trăm vừa tính
        // công thức tính có thể tìm ở đây: https://www.movable-type.co.uk/scripts/latlong.html
        const intermediatePoint = calculateIntermediatePoint(lastCoord, targetCoord, fraction);
        
        newCoords.push(intermediatePoint);
      }

      newCoords.push(targetCoord);
    }

    this._coords = newCoords;

    this._animate();
  }
  
  _animate = () => {
    if (this._index >= this._coords.length) return;

    this.setState(
      ({ renderedCoords }) => ({ renderedCoords: [...renderedCoords, this._coords[this._index]] }),
      () => {
        this._index++;
        setTimeout(this._animate, 20);
      }
    );
  };
  
  render() {
    return (
      <MapView>
        <MapView.Polyline coordinates={this.state.renderedCoords} />
      </MapView>
    );
  }

Kết quả:

react-native-anmated-polyline
react-native-anmated-polyline

Tác giả: Huỳnh Ngọc Đỉnh – Senior React Native at Foody.

Chia sẻ

Để lại bình luận

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

Bài viết cùng chuyên mục
Tối ưu ứng dụng với cấu trúc dữ liệu cơ bản và bitwise
Công Nghệ

Tối ưu ứng dụng với cấu trúc dữ liệu cơ bản và bitwise

Trong bài viết này, 200Lab sẽ chia sẻ những trường hợp dễ...

Công Nghệ

So sánh Flutter vs React Native: Framework nào đáng học năm 2021

Điểm chung của Flutter, React Native đều là Cross-platform Mobile, build native...

HTTP/2 là gì? So sánh HTTP/2 và HTTP/1
Công Nghệ

HTTP/2 là gì? So sánh HTTP/2 và HTTP/1

Từ khi Internet ra đời, sự phát triển về các giao thức...

Upload File từ Frontend đến Backend mà rất nhiều bạn vẫn đang làm sai!!
Công Nghệ

Upload File từ Frontend đến Backend mà rất nhiều bạn vẫn đang làm sai!!

1. Client encode file (base64) rồi gởi về backend 200Lab đã từng...

Công Nghệ

Hybrid App và Native App: Những khác biệt to lớn

Bất cứ khi nào một công ty quyết định làm ứng dụng...

Web/System Architecture 101 – Kiến trúc web/hệ thống cơ bản cho người mới
Công Nghệ

Web/System Architecture 101 – Kiến trúc web/hệ thống cơ bản cho người mới

Đây là một kiến trúc cơ bản mà bất kì một người...

Công Nghệ

Tư duy kiến trúc thông qua các trò chơi mà rất nhiều bạn không biết

Tư duy kiến trúc là gì? Tư duy kiến trúc có thể...

HTTP/3 là gì – Giao thức đột phá để tăng tải website
Công Nghệ

HTTP/3 là gì – Giao thức đột phá để tăng tải website

Nhắc lại một chút về HTTP/2 ở bài trước, từ khi giao...

Chiến lược leo lương: >= 1000$ NET (thậm chí > 3000$ NET)
Công Nghệ

Chiến lược leo lương: >= 1000$ NET (thậm chí > 3000$ NET)

Một ngàn đô Mỹ (1000$) là mức lương thường thấy cho vị...

Công Nghệ

Flutter vs React Native: Lựa chọn nào tốt nhất hiện nay

Flutter vs React Native? Có bao giờ bạn thắc mắc liệu sử...

Digital Ocean: Hướng dẫn tạo Droplet cùng 100$ FREE credit
Công Nghệ

Digital Ocean: Hướng dẫn tạo Droplet cùng 100$ FREE credit

Nếu bạn đang là người học lập trình, đặc biệt về backend,...

Công Nghệ

4 nguồn thu nhập thụ động dễ dàng cho lập trình viên

Cơ hội kiếm từ $ 500 đến $ 50.000 mỗi tháng Ai...