我在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
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
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;发布于 2021-01-21 11:34:58
我是如何解决这个问题的:
I将国家/地区json转换为国家/地区-110m.json‘;
删除
并替换为
新的旋转代码是:
如果有任何疑问,请查看我的完整源代码
Github
https://stackoverflow.com/questions/65527693
复制相似问题