-
-
Notifications
You must be signed in to change notification settings - Fork 848
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support edgePadding with camera, set initial frame to fullscreen #1057
Conversation
Updated testcase: import React from 'react';
import {View, Button} from 'react-native';
import MapboxGL from '@react-native-mapbox-gl/maps';
const latitude = 40.723279;
const longitude = -73.970895;
const boundsEdge = 0.002;
const aLine = {
type: 'LineString',
coordinates: [
[longitude-boundsEdge, latitude-boundsEdge],
[longitude-boundsEdge, latitude+boundsEdge],
[longitude+boundsEdge, latitude+boundsEdge],
[longitude+boundsEdge, latitude-boundsEdge],
[longitude-boundsEdge, latitude-boundsEdge],
],
};
/*
The error is:
Mapbox error [event]:General [code]:-1 [message]:Unable to calculate
appropriate zoom level for bounds. Vertical or horizontal padding is
greater than map's height or width.
Tested on:
- iOS Simulator, iPhone 11
- iOS Simulator, iPhone SE
- Android Emulator, Pixel 3 (API 30)
*/
// iOS: No error, but padding has no effect.
// Android: No error, and padding works.
const padding1 = {
paddingTop: 0,
paddingBottom: 0,
};
// iOS: No error, but padding has no effect.
// Android: No error, and padding works.
const padding2 = {
paddingTop: 0,
paddingBottom: 663,
};
// iOS: Error, and padding has no effect.
// Android: No error, and padding works.
const padding3 = {
paddingTop: 0,
paddingBottom: 664,
};
// iOS: Error, and padding has no effect.
// Android: No error, and padding works.
const padding4 = {
paddingTop: 1,
paddingBottom: 663,
};
// iOS: No error, but padding has no effect.
// Android: No error, and padding works.
const padding5 = {
paddingTop: 31,
paddingBottom: 32,
};
// iOS: Error, and padding has no effect.
// Android: No error, and padding works.
const padding6 = {
paddingTop: 32,
paddingBottom: 32,
};
const initialPadding = padding3;
class MapView extends React.Component {
static propTypes = {
};
state = {
padding: initialPadding,
}
constructor(props) {
super(props);
}
renderContents = () => {
const point = {
"type": "Point",
"coordinates": [longitude, latitude]
};
return (
<MapboxGL.ShapeSource
id={'source'}
shape={point}
>
<MapboxGL.CircleLayer
id={'circle-big'}
style={{
circleRadius: 20,
circleColor: 'white',
circleStrokeColor: 'black',
circleStrokeWidth: 1,
iconAllowOverlap: true,
circlePitchScale: 'viewport',
}}
/>
</MapboxGL.ShapeSource>
);
};
render() {
let {padding} = this.state;
return (
<View style={{flex: 1}}>
<View style={{flexDirection: 'row'}}>
<Button title="p1" onPress={() => this.setState({padding: padding1})} />
<Button title="p2" onPress={() => this.setState({padding: padding2})} />
<Button title="p3" onPress={() => this.setState({padding: padding3})} />
<Button title="p4" onPress={() => this.setState({padding: padding4})} />
</View>
<MapboxGL.MapView
ref={(c) => (this._map = c)}
onPress={this.onPress}
style={{flex: 1}}
>
{/* zoomLevel={9} */}
<MapboxGL.Camera
bounds={{
ne: [longitude - boundsEdge, latitude + boundsEdge],
sw: [longitude + boundsEdge, latitude - boundsEdge],
...padding,
}}
/>
{this.renderContents()}
<MapboxGL.ShapeSource id="idStreetLayer" shape={aLine}>
<MapboxGL.LineLayer id="idStreetLayer" />
</MapboxGL.ShapeSource>
</MapboxGL.MapView>
</View>
);
}
}
export default MapView; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is working great, thank you! The padding works perfectly, and I left a note about the one issue I was having.
ios/RCTMGL/CameraUpdateItem.m
Outdated
- (UIEdgeInsets)_clippedPadding:(UIEdgeInsets)padding forView:(RCTMGLMapView*)mapView | ||
{ | ||
UIEdgeInsets result = padding; | ||
if ((result.top + result.bottom) > mapView.frame.size.height) { | ||
double extra = mapView.frame.size.height / 4.0 + (result.top + result.bottom) - mapView.frame.size.height; | ||
if (result.top == 0.0) { | ||
result.bottom -= extra; | ||
} else if (result.bottom == 0.0) { | ||
result.top -= extra; | ||
} else { | ||
result.top -= extra/2.0; | ||
result.bottom -= extra/2.0; | ||
} | ||
} | ||
if ((result.left + result.right) > mapView.frame.size.width) { | ||
double extra = mapView.frame.size.width / 4.0 + (result.left + result.right) - mapView.frame.size.width; | ||
if (result.left == 0.0) { | ||
result.right -= extra; | ||
} else if (result.right == 0.0) { | ||
result.left -= extra; | ||
} else { | ||
result.left -= extra/2.0; | ||
result.right -= extra/2.0; | ||
} | ||
} | ||
return result; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mfazekas I was still getting the overflow error, and I did a little investigation - it looks like the error occurs if the cumulative padding along one axis is equal to the map dimension (as well as if it exceeds it).
Here's the code I got working correctly - I believe it's a little simpler, but feel free to integrate it however you like.
- (UIEdgeInsets)_clippedPadding:(UIEdgeInsets)padding forView:(RCTMGLMapView*)mapView
{
UIEdgeInsets result = padding;
if (result.top + result.bottom >= mapView.frame.size.height) {
double overflow = result.top + result.bottom - mapView.frame.size.height;
result.top -= overflow / 2.0 + 1;
result.bottom -= overflow / 2.0 + 1;
}
if (result.left + result.right >= mapView.frame.size.width) {
double overflow = result.left + result.right - mapView.frame.size.width;
result.left -= overflow / 2.0 + 1;
result.right -= overflow / 2.0 + 1;
}
return result;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@naftalibeder I'm ambivalent about this. It's hard to correct padding in a sensible way once they are over the size of bounds.
Maybe it's correct for the framework to just complain.
I think this correction is something the app is also capable of doing. Eg get the diemnsion of map before setting up padding, and correct padding, if it's too large.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mfazekas I'd like to try to make the case for it, if you don't mind.
Other layout examples I can think of tend to fail silently, and just try to intelligently guess what the best outcome would be. For example, 'illegal' CSS configurations still allow a page to render, and even ScrollView edge insets that sum to greater than the view dimension in iOS only throw a warning.
And regarding the app handling this, I think a declarative UI is a worse place to need to do it. Callbacks are asynchronous so it requires handling a number of edge cases that this library would not need to handle. I did attempt to do this, and it required a surprising amount of code just to avoid this crash, and I still wasn't confident that I had prevented it completely. The clipped
method above, by contrast, actually guarantees the error will never be thrown.
I'm certainly open to working out a slightly different way for the overflow inset to distribute across the two edges, but I feel pretty strongly the app should not crash because of out-of-bounds layout configuration. Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, I'm a bit out of my element here - would have to trust you and @naftalibeder on this one 👍
As I understood it you're adjusting the padding just for iOS - this isn't an issue on Android (did we already adjust for this there)?
Sometimes I wonder why things like this aren't unified by the upstream SDKs 😅
@ferdicus That's correct, this would only affect iOS. I actually just opened up a PR that fixes the same issue on Android, which you can see linked above. |
123ad52
to
9ff2da7
Compare
@naftalibeder i've update padding code, pls review:
The only way it's improvement on yours is that it will not make paddings negative. |
Nice, good catch!
These tweaks are up to you though. if it works, it works! |
First we need some minimal delta because of floating point math. Then mapbox alert might use int conversion, not sure but using some extra 0.1 was not enough. Using 1.0 seems to worked so changed to that.
Agree refactored code. |
Looks great! I'll bring this logic into the PR I opened for Android. |
@@ -757,6 +757,7 @@ | |||
"FB_SONARKIT_ENABLED=1", | |||
); | |||
INFOPLIST_FILE = RNMapboxGLExample/Info.plist; | |||
IPHONEOS_DEPLOYMENT_TARGET = 10.0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this in this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lazyness. Because travis builds are slow.
iOS in travis is broken i assume since the RN 63.3 upgrade, it was an attempt to fix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:)
Does this also explain why there are no checks in the PRs, or is that unrelated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ferdicus i think that should improve now, with travis-ci.org => travis-ci.com migration
Fixes: #1032, #841
Test code: