首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >React原生d3方位等面积旋转不平滑

问React原生d3方位等面积旋转不平滑
EN

Stack Overflow用户
提问于 2021-01-01 14:25:40
回答 1查看 262关注 0票数 1

我在react-native中做d3方位等面积投影,我用的是

示例

为了这个。它工作得很好,但我使用panGestureHandler更新旋转值,这也是工作,但它不平滑,它需要时间来更新地图。

这是这个的repo。

这是我更新旋转值的代码:

const countryPaths = useMemo(() => { const clipAngle = 150;const projection = d3 .geoAzimuthalEqualArea() // .rotate(

0,-90

) .rotate(

rotateX,rotateY

) .fitSize(

mapExtent,mapExtent

,{ type:'FeatureCollection',features: COUNTRIES,}) .clipAngle(clipAngle) .translate(

dimensions.width / 2、mapExtent /2

);const geoPath =d3.GeoPath().projection(投影);const windowPaths = COUNTRIES.map(geoPath);return windowPaths;},

dimensions、rotateX、rotateY

);

​

​

下面是我的完整代码

App.js

代码语言:javascript
复制
import React, {useState, useMemo, useEffect, useRef} from 'react';
import {
  StyleSheet,
  View,
  Dimensions,
  Animated,
  PanResponder,
  Text,
  SafeAreaView,
} from 'react-native';

import Map from './components/Map';

import COLORS from './constants/Colors';
import movingAverage from './functions/movingAverage';
import * as d3 from 'd3';
import covidData_raw from './assets/data/who_data.json';

export default function App(props) {
  const dimensions = Dimensions.get('window');
  const [stat, setStat] = useState('avg_confirmed');
  const [date, setDate] = useState('2020-04-24');

  //Data Manipulation
  const covidData = useMemo(() => {
    const countriesAsArray = Object.keys(covidData_raw).map((key) => ({
      name: key,
      data: covidData_raw[key],
    }));

    const windowSize = 7;

    const countriesWithAvg = countriesAsArray.map((country) => ({
      name: country.name,
      data: [...movingAverage(country.data, windowSize)],
    }));

    const onlyCountriesWithData = countriesWithAvg.filter(
      (country) => country.data.findIndex((d, _) => d[stat] >= 10) != -1,
    );

    return onlyCountriesWithData;
  }, []);

  const maxY = useMemo(() => {
    return d3.max(covidData, (country) => d3.max(country.data, (d) => d[stat]));
  }, [stat]);

  const colorize = useMemo(() => {
    const colorScale = d3
      .scaleSequentialSymlog(d3.interpolateReds)
      .domain([0, maxY]);

    return colorScale;
  });

  return (
    
      
        
      
    
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: COLORS.primary,
    alignItems: 'center',
    justifyContent: 'center',
  },
  rotateView: {
    width: 300,
    height: 300,
    backgroundColor: 'black',
    shadowOpacity: 0.2,
  },
});

map.js

代码语言:javascript
复制
import React, {useMemo, useState, useEffect} from 'react';
import {StyleSheet, View, Animated, PanResponder} from 'react-native';

//LIBRARIES
import Svg, {G, Path, Circle} from 'react-native-svg';
import * as d3 from 'd3';
import {
  PanGestureHandler,
  PinchGestureHandler,
  State,
} from 'react-native-gesture-handler';

//CONSTANTS
import {COUNTRIES} from '../constants/CountryShapes';
import COLORS from '../constants/Colors';

//COMPONENTS
import Button from './Button';

const Map = (props) => {
  const [countryList, setCountryList] = useState([]);
  const [translateX, setTranslateX] = useState(0);
  const [translateY, setTranslateY] = useState(0);
  const [lastTranslateX, setLastTranslateX] = useState(0);
  const [lastTranslateY, setLastTranslateY] = useState(0);
  const [buttonOpacity, _] = useState(new Animated.Value(0));
  const [scale, setScale] = useState(1);
  const [prevScale, setPrevScale] = useState(1);
  const [lastScaleOffset, setLastScaleOffset] = useState(0);

  const [rotateX, setrotateX] = useState();
  const [rotateY, setrotateY] = useState();

  const {dimensions, data, date, colorize, stat} = props;

  //Gesture Handlers
  const panStateHandler = (event) => {
    if (event.nativeEvent.oldState === State.UNDETERMINED) {
      setLastTranslateX(translateX);
      setLastTranslateY(translateY);
    }

    if (event.nativeEvent.oldState === State.ACTIVE) {
      Animated.timing(buttonOpacity, {
        toValue: 1,
        duration: 1000,
        useNativeDriver: true,
      }).start();
    }
  };

  const panGestureHandler = (event) => {
    console.log('event', event.nativeEvent);
    setrotateX(event.nativeEvent.x);
    setrotateX(event.nativeEvent.y);
    setTranslateX(-event.nativeEvent.translationX / scale + lastTranslateX);
    setTranslateY(-event.nativeEvent.translationY / scale + lastTranslateY);
  };

  const pinchStateHandler = (event) => {
    if (event.nativeEvent.oldState === State.UNDETERMINED) {
      setLastScaleOffset(-1 + scale);
    }

    if (event.nativeEvent.oldState === State.ACTIVE) {
      Animated.timing(buttonOpacity, {
        toValue: 1,
        duration: 1000,
        useNativeDriver: true,
      }).start();
    }
  };

  const pinchGestureHandler = (event) => {
    if (
      event.nativeEvent.scale + lastScaleOffset >= 1 &&
      event.nativeEvent.scale + lastScaleOffset <= 5
    ) {
      setPrevScale(scale);
      setScale(event.nativeEvent.scale + lastScaleOffset);
      setTranslateX(
        translateX -
          (event.nativeEvent.focalX / scale -
            event.nativeEvent.focalX / prevScale),
      );
      setTranslateY(
        translateY -
          (event.nativeEvent.focalY / scale -
            event.nativeEvent.focalY / prevScale),
      );
    }
  };

  //Initialize Map Transforms
  const initializeMap = () => {
    setTranslateX(0);
    setTranslateY(0);
    setScale(1);
    setPrevScale(1);
    setLastScaleOffset(0);
    Animated.timing(buttonOpacity, {
      toValue: 0,
      duration: 1000,
      useNativeDriver: true,
    }).start();
  };

  //Create Map Paths
  const mapExtent = useMemo(() => {
    return dimensions.width > dimensions.height / 2
      ? dimensions.height / 2
      : dimensions.width;
  }, [dimensions]);

    const countryPaths = useMemo(() => {
    const clipAngle = 150;

    const projection = d3
      .geoAzimuthalEqualArea()
      // .rotate([0, -90])
      .rotate([rotateX, rotateY])
      .fitSize([mapExtent, mapExtent], {
        type: 'FeatureCollection',
        features: COUNTRIES,
      })
      .clipAngle(clipAngle)
      .translate([dimensions.width / 2, mapExtent / 2]);

    const geoPath = d3.geoPath().projection(projection);

    const windowPaths = COUNTRIES.map(geoPath);

    return windowPaths;
    }, [dimensions, rotateX, rotateY]);



  useEffect(() => {
    setCountryList(
      countryPaths.map((path, i) => {
        const curCountry = COUNTRIES[i].properties.name;

        const isCountryNameInData = data.some(
          (country) => country.name === curCountry,
        );

        const curCountryData = isCountryNameInData
          ? data.find((country) => country.name === curCountry)['data']
          : null;

        const isDataAvailable = isCountryNameInData
          ? curCountryData.some((data) => data.date === date)
          : false;

        const dateIndex = isDataAvailable
          ? curCountryData.findIndex((x) => x.date === date)
          : null;

        return (
          
        );
      }),
    );
  }, [rotateX, rotateY]);

  return (
    
       panGestureHandler(e)}
        onHandlerStateChange={(e) => panStateHandler(e)}>
         pinchGestureHandler(e)}
          onHandlerStateChange={(e) => pinchStateHandler(e)}>
          
            
              
              {countryList.map((x) => x)}
            
          
        
      
    
  );
};

const styles = StyleSheet.create({
  svg: {},
  rotateView: {
    width: 100,
    height: 400,
    backgroundColor: 'black',
    shadowOffset: {height: 1, width: 1},
    shadowOpacity: 0.2,
  },
});

export default Map;
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-01-21 11:34:58

我是如何解决这个问题的:

I将国家/地区json转换为国家/地区-110m.json‘;

删除

并替换为

新的旋转代码是:

如果有任何疑问,请查看我的完整源代码

Github

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65527693

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档