maplibre 0.0.2

Native Maps for Web, Mobile and Desktop
Documentation
use super::UpdateState;

use crate::coords::Zoom;
use crate::map_state::MapState;

use cgmath::{Vector2, Vector3};
use std::time::Duration;

pub struct ZoomHandler {
    window_position: Option<Vector2<f64>>,
    zoom_delta: Option<Zoom>,
    sensitivity: f64,
}

impl UpdateState for ZoomHandler {
    fn update_state<W>(&mut self, state: &mut MapState<W>, _dt: Duration) {
        if let Some(zoom_delta) = self.zoom_delta {
            if let Some(window_position) = self.window_position {
                let current_zoom = state.zoom();
                let next_zoom = current_zoom + zoom_delta;

                state.update_zoom(next_zoom);
                self.zoom_delta = None;

                let perspective = &state.perspective();
                let view_proj = state.camera().calc_view_proj(perspective);
                let inverted_view_proj = view_proj.invert();
                let camera = state.camera_mut();

                if let Some(cursor_position) =
                    camera.window_to_world_at_ground(&window_position, &inverted_view_proj)
                {
                    let scale = current_zoom.scale_delta(&next_zoom);

                    let delta = Vector3::new(
                        cursor_position.x * scale,
                        cursor_position.y * scale,
                        cursor_position.z,
                    ) - cursor_position;

                    camera.position += delta;
                }
            }
        }
    }
}

impl ZoomHandler {
    pub fn new(sensitivity: f64) -> Self {
        Self {
            window_position: None,
            zoom_delta: None,
            sensitivity,
        }
    }

    pub fn process_window_position(
        &mut self,
        window_position: &Vector2<f64>,
        _touch: bool,
    ) -> bool {
        self.window_position = Some(*window_position);
        true
    }

    pub fn update_zoom(&mut self, delta: f64) {
        self.zoom_delta = Some(self.zoom_delta.unwrap_or_default() + Zoom::new(delta));
    }

    pub fn process_scroll(&mut self, delta: &winit::event::MouseScrollDelta) {
        self.update_zoom(
            match delta {
                winit::event::MouseScrollDelta::LineDelta(_horizontal, vertical) => {
                    *vertical as f64
                }
                winit::event::MouseScrollDelta::PixelDelta(winit::dpi::PhysicalPosition {
                    y: scroll,
                    ..
                }) => *scroll / 100.0,
            } * self.sensitivity,
        );
    }

    pub fn process_key_press(
        &mut self,
        key: winit::event::VirtualKeyCode,
        state: winit::event::ElementState,
    ) -> bool {
        let amount = if state == winit::event::ElementState::Pressed {
            0.1
        } else {
            0.0
        };

        match key {
            winit::event::VirtualKeyCode::Plus | winit::event::VirtualKeyCode::I => {
                self.update_zoom(amount);
                true
            }
            winit::event::VirtualKeyCode::Minus | winit::event::VirtualKeyCode::K => {
                self.update_zoom(-amount);
                true
            }
            _ => false,
        }
    }
}