Panning을 구현해본다.
다음 링크를 참조해본다.
상기 링크에서는 다음과 같이 이벤트를 할당한다.
// We select the SVG into the page
var svg = document.querySelector('svg');
// If browser supports pointer events
if (window.PointerEvent) {
svg.addEventListener('pointerdown', onPointerDown); // Pointer is pressed
svg.addEventListener('pointerup', onPointerUp); // Releasing the pointer
svg.addEventListener('pointerleave', onPointerUp); // Pointer gets out of the SVG area
svg.addEventListener('pointermove', onPointerMove); // Pointer is moving
} else {
// Add all mouse events listeners fallback
svg.addEventListener('mousedown', onPointerDown); // Pressing the mouse
svg.addEventListener('mouseup', onPointerUp); // Releasing the mouse
svg.addEventListener('mouseleave', onPointerUp); // Mouse gets out of the SVG area
svg.addEventListener('mousemove', onPointerMove); // Mouse is moving
// Add all touch events listeners fallback
svg.addEventListener('touchstart', onPointerDown); // Finger is touching the screen
svg.addEventListener('touchend', onPointerUp); // Finger is no longer touching the screen
svg.addEventListener('touchmove', onPointerMove); // Finger is moving
}
주요 요점으로는, window
의 PointerEvent
를 통하여 장치가 포인터를 사용하는지, 마우스나 터치를 사용하는지 구분할 수 있다는 점이다.
ReactSVG를 사용하여, svg의 beforeInjection(DOM에 로드되기 직전에 호출됨)에서 다음과 같이 설정할 수 있다.
beforeInjection = {(svg) => {
if (window.PointerEvent) {
svg.addEventListener('pointerdown', onPointerDown); // Pointer is pressed
svg.addEventListener('pointerup', onPointerUp); // Releasing the pointer
svg.addEventListener('pointerleave', onPointerUp); // Pointer gets out of the SVG area
svg.addEventListener('pointermove', onPointerMove); // Pointer is moving
} else {
// Add all mouse events listeners fallback
svg.addEventListener('mousedown', onPointerDown); // Pressing the mouse
svg.addEventListener('mouseup', onPointerUp); // Releasing the mouse
svg.addEventListener('mouseleave', onPointerUp); // Mouse gets out of the SVG area
svg.addEventListener('mousemove', onPointerMove); // Mouse is moving
// Add all touch events listeners fallback
svg.addEventListener('touchstart', onPointerDown); // Finger is touching the screen
svg.addEventListener('touchend', onPointerUp); // Finger is no longer touching the screen
svg.addEventListener('touchmove', onPointerMove); // Finger is moving
}
}}
Offset을 계산하기 위하여 viewBox객체를 독립시킨다.
//예시
var viewBox = {
x: 0,
y: 0,
width: 500,
height: 500
};
//변형
class ViewBox {
constructor(x, y, width, height){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
getString(){
return [this.x, this.y, this.width, this.height].join(' ')
}
}
최종적으로, 다음과 같이 구현하였다.
import kr_map from './kr.svg'
import React from 'react'
import { ReactSVG } from 'react-svg'
class ViewBox {
constructor(x, y, width, height){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
getString(){
return [this.x, this.y, this.width, this.height].join(' ')
}
}
export default class map extends React.Component {
constructor(props){
super(props);
this.current_viewbox = new ViewBox(0,0,1200,1080);
this.new_viewbox = new ViewBox(0,0,1200,1080);
this.pointerOrigin = new ViewBox(0,0,0,0);
this.isPointerDown = false;
this.svg = null;
}
// This function returns an object with X & Y values from the pointer event
getPointFromEvent (event) {
var point = {x:0, y:0};
// If event is triggered by a touch event, we get the position of the first finger
if (event.targetTouches) {
point.x = event.targetTouches[0].clientX;
point.y = event.targetTouches[0].clientY;
} else {
point.x = event.clientX;
point.y = event.clientY;
}
return point;
}
onPointerUp() {
// The pointer is no longer considered as down
this.isPointerDown = false;
// We save the viewBox coordinates based on the last pointer offsets
this.current_viewbox.x = this.new_viewbox.x;
this.current_viewbox.y = this.new_viewbox.y;
}
// Function called by the event listeners when user start pressing/touching
onPointerDown(event) {
this.isPointerDown = true; // We set the pointer as down
// We get the pointer position on click/touchdown so we can get the value once the user starts to drag
var pointerPosition = this.getPointFromEvent(event);
this.pointerOrigin.x = pointerPosition.x;
this.pointerOrigin.y = pointerPosition.y;
}
// Function called by the event listeners when user start moving/dragging
onPointerMove (event) {
// Only run this function if the pointer is down
if (!this.isPointerDown) {
return;
}
// This prevent user to do a selection on the page
event.preventDefault();
// Get the pointer position
var pointerPosition = this.getPointFromEvent(event);
// We calculate the distance between the pointer origin and the current position
// The viewBox x & y values must be calculated from the original values and the distances
this.new_viewbox.x = this.current_viewbox.x - (pointerPosition.x - this.pointerOrigin.x);
this.new_viewbox.y = this.current_viewbox.y - (pointerPosition.y - this.pointerOrigin.y);
// We create a string with the new viewBox values
// The X & Y values are equal to the current viewBox minus the calculated distances
var viewBoxString = `${this.new_viewbox.x} ${this.new_viewbox.y} ${this.current_viewbox.width} ${this.current_viewbox.height}`;
// We apply the new viewBox values onto the SVG
this.svg.setAttribute('viewBox', viewBoxString);
}
render(){
return <ReactSVG
beforeInjection = {(svg) => {
this.svg = svg;
svg.setAttribute('width','1000');
svg.setAttribute('height','1300');
svg.setAttribute('viewBox','0 0 1200 1080');
if (window.PointerEvent) {
svg.addEventListener('pointerdown', this.onPointerDown.bind(this)); // Pointer is pressed
svg.addEventListener('pointerup', this.onPointerUp.bind(this)); // Releasing the pointer
svg.addEventListener('pointerleave', this.onPointerUp.bind(this)); // Pointer gets out of the SVG area
svg.addEventListener('pointermove', this.onPointerMove.bind(this)); // Pointer is moving
} else {
// Add all mouse events listeners fallback
svg.addEventListener('mousedown', this.onPointerDown.bind(this)); // Pressing the mouse
svg.addEventListener('mouseup', this.onPointerUp.bind(this)); // Releasing the mouse
svg.addEventListener('mouseleave', this.onPointerUp.bind(this)); // Mouse gets out of the SVG area
svg.addEventListener('mousemove', this.onPointerMove.bind(this)); // Mouse is moving
// Add all touch events listeners fallback
svg.addEventListener('touchstart', this.onPointerDown.bind(this)); // Finger is touching the screen
svg.addEventListener('touchend', this.onPointerUp.bind(this)); // Finger is no longer touching the screen
svg.addEventListener('touchmove', this.onPointerMove.bind(this)); // Finger is moving
}
}}
afterInjection = {(error, svg) => {
if (error) {
console.error(error);
return;
}
svg.classList.add('region');
console.log(svg.classList);
}
}
src = {kr_map}
></ReactSVG>
}
}
상기 기재된 코드에 다음 함수를 추가한다.
onZoom(event){
if(event.deltaY > 0){
this.current_viewbox.width /= .9;
this.current_viewbox.height /= .9;
}
else if(event.deltaY < 0){
this.current_viewbox.width /= 1.10;
this.current_viewbox.height /=1.10;
}
// this.current_viewbox.x -= (this.current_viewbox.width - tempViewBoxWidth) / 2;
// this.current_viewbox.y -= (this.current_viewbox.height - tempViewBoxHeight) / 2;
var viewBoxString = `${this.current_viewbox.x} ${this.current_viewbox.y} ${this.current_viewbox.width} ${this.current_viewbox.height}`;
this.svg.setAttribute('viewBox', viewBoxString);
}
상기 이벤트를 받을 wheel의 zoom을 추가한다.
beforeInjection = {(svg) => {
this.svg = svg;
svg.setAttribute('width','1000');
svg.setAttribute('height','1300');
svg.setAttribute('viewBox','0 0 1200 1080');
if (window.PointerEvent) {
svg.addEventListener('pointerdown', this.onPointerDown.bind(this)); // Pointer is pressed
svg.addEventListener('pointerup', this.onPointerUp.bind(this)); // Releasing the pointer
svg.addEventListener('pointerleave', this.onPointerUp.bind(this)); // Pointer gets out of the SVG area
svg.addEventListener('pointermove', this.onPointerMove.bind(this)); // Pointer is moving
svg.addEventListener('wheel', this.onZoom.bind(this));
} else {
// Add all mouse events listeners fallback
svg.addEventListener('mousedown', this.onPointerDown.bind(this)); // Pressing the mouse
svg.addEventListener('mouseup', this.onPointerUp.bind(this)); // Releasing the mouse
svg.addEventListener('mouseleave', this.onPointerUp.bind(this)); // Mouse gets out of the SVG area
svg.addEventListener('mousemove', this.onPointerMove.bind(this)); // Mouse is moving
// Add all touch events listeners fallback
svg.addEventListener('touchstart', this.onPointerDown.bind(this)); // Finger is touching the screen
svg.addEventListener('touchend', this.onPointerUp.bind(this)); // Finger is no longer touching the screen
svg.addEventListener('touchmove', this.onPointerMove.bind(this)); // Finger is moving
}
}}