react-native mapbox symbol layer render icons from URI dynamically - android

I need to show custom icons in my places, that icons are loaded from a specific URL dynamically. Here is my code.
const PlacesMarker = props => {
const { places } = props
const [geoJson, setGeoJson] = useState([])
useEffect(() => {
if (places)
renderPlaces(places)
}, [places])
const renderPlaces = (places) => {
let features = places.content.map((item) => {
return {
type: "Feature",
id: item.id,
properties: {
id: item.id,
icon: item.type.iconUri,
name: item.name,
type: item.type.name
},
geometry: {
type: "Point",
coordinates: [item.location.lon, item.location.lat],
},
}
})
setGeoJson(features)
}
return (
<View>
{geoJson.length > 0 ?
<MapboxGL.ShapeSource id={'places-map'}
shape={{ type: "FeatureCollection", features: geoJson }}>
<MapboxGL.SymbolLayer
id={Math.random().toString()}
style={{
iconImage: ['get', 'icon']
iconAllowOverlap: true,
// iconSize: 0.80,
iconIgnorePlacement: true,
textField: ['get', 'icon']
}}
/>
</MapboxGL.ShapeSource> : null
}
</View >
)
}
export default PlacesMarker
In the style, I used the expression 'get', and it works, because I set the textField with Icon URI value and it shows the uri. However if I set the iconImage property with the URI, then the icon appear successfully

In react-native-mapbox-gl 7.0 if iconImage is constant then you can use url-s. But if it's an expression it should be a key in images dict of Images, <Images images={images} />.
See https://github.com/react-native-mapbox-gl/maps/issues/652

Related

Re-creating touch-based gestures with Playwright to test mobile viewports

Can someone help me re-create touch-based gestures(swipe, zoom, pinch, etc.) in Playwright to test emulated mobile devices? It has only a tap method out of the box, which works perfectly, but I need a whole set of functionality to test the mobile viewports of our web application.
I have tried so far a couple of scripts that I found online, which are not failing my tests but rather don't work for me for some reason:
await page.evaluate(() => {
const target = document.querySelector("#abc");
target.addEventListener('touchstart', (e) => {
console.log('touch start');
});
function simulateTouchEvent(element, type, touches) {
const touchEvents = [];
touches.forEach((touch) => {
touchEvents.push(new Touch({
clientX: touch.x,
clientY: touch.y,
identifier: touch.id,
target: element,
}));
});
element.dispatchEvent(new TouchEvent(type, {
touches: touchEvents,
view: window,
cancelable: true,
bubbles: true,
}));
}
simulateTouchEvent(target, 'touchstart', [{
id: "123",
x: 10,
y: 10,
}]);
simulateTouchEvent(target, 'touchend', [{
id: "123",
x: 10,
y: 10,
}]);
})
also this
const el = await page.locator(
".selector"
);
const dataTransfer = await page.evaluateHandle(
() => new DataTransfer()
);
await el.dispatchEvent("touchstart", { dataTransfer, steps: 5 });
await el.dispatchEvent("touchend", { dataTransfer, steps: 5 });
and
async function dispatchTouchEvent(
playWright: Page,
type: 'touchstart' | 'touchend' | 'touchcancel' | 'touchmove',
selector: string,
page?: Position,
screen?: Position,
client?: Position,
options?: PageExtraTouchOptions,
) {
await playWright.$eval(
selector,
(el, options) => {
const rect = el.getBoundingClientRect();
const {
client = {},
page = {},
screen = {},
type,
options: touchOpt,
} = options;
const touchObj = new Touch({
clientX: client.x,
clientY: client.y,
identifier: Date.now(),
pageX:
page.x || (client.x !== undefined ? rect.left + client.x : undefined),
pageY:
page.y || (client.y !== undefined ? rect.top + client.y : undefined),
screenX: screen.x,
screenY: screen.y,
target: el,
});
const touchEvent = new TouchEvent(type, {
bubbles: true,
cancelable: true,
...touchOpt,
changedTouches: [touchObj],
targetTouches: [touchObj],
touches: [touchObj],
});
return el.dispatchEvent(touchEvent);
},
{ client, options, page, screen, type },
);
}
await dispatchTouchEvent(
page,
"touchstart",
".selector"
);
await dispatchTouchEvent(
page,
"touchend",
".selector"
);
I recently have been also looking into Playwrights experimental android emulation feature, in the hopes that it might help me to emulate at least an android device, but haven't even been able to even run it because of ECONNREFUSED error.
Would appreciate any help, because I`m completely stuck in here.
Playwright version: 1.23;
OS: Ubuntu Neon KDE 20.04;

How to draw a navigation line on a mapbox map in react-native?

I am trying to get navigation directions using mapbox-sdk for react-native from npm package:
"#mapbox/mapbox-sdk": "^0.11.0"
And for rendering the directions returned by mapbox-sdk I am using the below npm package:
"#react-native-mapbox-gl/maps": "^8.1.0-rc.8",
Code I am using for retrieving directions:
import MapboxGL from '#react-native-mapbox-gl/maps'
// Mapbox SDK related package
import MapboxDirectionsFactory from '#mapbox/mapbox-sdk/services/directions'
import { lineString as makeLineString } from '#turf/helpers'
import GeoLocationService from '../../services/geolocation/GeoLocationService';
import GeoLocationCore from '#react-native-community/geolocation'
const accessToken = "ACESS_TOKEN_FROM_MAPBOX_API_DASHBOARD"
const directionsClient = MapboxDirectionsFactory({accessToken})
constructor(props) {
super(props);
this.state = {
longitude: 0,
latitude: 0,
orderLongitude: 0,
orderLatitude: 0,
route: null,
};
}
async componentDidMount() {
const {route} = this.props
// Lets say route.params contains the below object:
// { "longitude": "33.981982", "latitude": "-6.851599"}
console.log("Params from other screen: ", route.params)
MapboxGL.setAccessToken(accessToken)
MapboxGL.setConnected(true);
MapboxGL.setTelemetryEnabled(true);
const permission = await MapboxGL.requestAndroidLocationPermissions();
let latitude, longitude;
if(Platform.OS == "android") {
GeoLocationService.requestLocationPermission().then(() => {
GeoLocationCore.getCurrentPosition(
info => {
const { coords } = info
latitude = coords.latitude
longitude = coords.longitude
//this.setState({longitude: coords.longitude, latitude: coords.latitude})
this.setState({longitude: -6.873795, latitude: 33.990777, orderLongitude: route.params.longitude, orderLatitude: route.params.latitude})
console.log("your lon: ", longitude)
console.log("your lat", latitude)
this.getDirections([-6.873795, 33.990777], [route.params.longitude, route.params.latitude])
},
error => console.log(error),
{
enableHighAccuracy: false,
//timeout: 2000,
maximumAge: 3600000
}
)
})
}
}
getDirections = async (startLoc, destLoc) => {
const reqOptions = {
waypoints: [
{coordinates: startLoc},
{coordinates: destLoc},
],
profile: 'driving',
geometries: 'geojson',
};
const res = await directionsClient.getDirections(reqOptions).send()
//const route = makeLineString(res.body.routes[0].geometry.coordinates)
const route = makeLineString(res.body.routes[0].geometry.coordinates)
console.log("Route: ", JSON.stringify(route))
this.setState({route: route})
}
Code I am using for rendering road directions fetched by mapbox-sdk:
renderRoadDirections = () => {
const { route } = this.state
return route ? (
<MapboxGL.ShapeSource id="routeSource" shape={route.geometry}>
<MapboxGL.LineLayer id="routeFill" aboveLayerID="customerAnnotation" style={{lineColor: "#ff8109", lineWidth: 3.2, lineCap: MapboxGL.LineJoin.Round, lineOpacity: 1.84}} />
</MapboxGL.ShapeSource>
) : null;
};
Code I am using for rendering map and directions:
render() {
return (
<View style={{ flex: 1 }}>
<MapboxGL.MapView
ref={(c) => this._map = c}
style={{flex: 1, zIndex: -10}}
styleURL={MapboxGL.StyleURL.Street}
zoomLevel={10}
showUserLocation={true}
userTrackingMode={1}
centerCoordinate={[this.state.longitude, this.state.latitude]}
logoEnabled={true}
>
{this.renderRoadDirections()}
<MapboxGL.Camera
zoomLevel={10}
centerCoordinate={[this.state.longitude, this.state.latitude]}
animationMode="flyTo"
animationDuration={1200}
/>
</MapboxGL.MapView>
</View>
)
}
Now when I try to render the GeoJson retreived the road directions line not showing on map, so I thought maybe something wrong with my GeoJson and tested it from here but it looks fine:
https://geojsonlint.com/
GeoJson that I tested and looks okay:
{"type":"Feature","properties":{},"geometry":{"type":"LineString","coordinates":[[-6.880611,33.9916],[-6.882194,33.990166],[-6.882439,33.99015],[-6.882492,33.990028],[-6.882405,33.98991],[-6.878006,33.990299],[-6.87153,33.990978],[-6.871386,33.990925],[-6.871235,33.991016],[-6.869793,33.991165],[-6.870523,33.990292]]}}
Example of what I am trying to achieve:
What could be wrong in my code that makes road directions line not showing on map?
Found what was causing the <LineLayer/> not showing on map, removing the the attribute aboveLayerID from the following line:
<MapboxGL.LineLayer id="routeFill" aboveLayerID="customerAnnotation" style={{lineColor: "#ff8109", lineWidth: 3.2, lineCap: MapboxGL.LineJoin.Round, lineOpacity: 1.84}} />
So it becomes:
<MapboxGL.LineLayer id="routeFill" style={{lineColor: "#ff8109", lineWidth: 3.2, lineCap: MapboxGL.LineJoin.Round, lineOpacity: 1.84}} />
Result:

pass dynamic URLs to require()

I need to loop through my products array then pass the data as props but for my image urls I cant do that and console show me the following:
invalid call at line 21 require(this.props.img)
here is my code:
app.js
export default class App extends React.Component {
state = {
products: [
{
id: 1,
details: 'this is a macbook',
image: '../Images/macbook.jpg',
price: '1000$',
},
{
id: 2,
details: 'this is a PS4 pro',
image: '../Images/ps4pro.jpeg',
price: '500$',
},
{
id: 3,
details: 'this is a beats',
image: '../Images/beats.jpeg',
price: '200$',
},
]
}
showProds = () => {
let prods = [];
for (let i = 0; i <= this.state.products.length - 1; i++) {
prods.push(<Product details={this.state.products[i].details} img={this.state.products[i].image} />)
}
console.log(prods);
return prods;
}
render() {
return <ScrollView>
{this.showProds()}
</ScrollView>
}
}
product component
export default class Product extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<View style={styles.card}>
<View style={styles.prod}>
<Text style={styles.prod_details}>{this.props.details}</Text>
<Image style={styles.img} source={require(this.props.img)} />
</View>
<View style={styles.btn}>
<TouchableOpacity>
<Text style={styles.btn_text}>Delete</Text>
</TouchableOpacity>
</View>
</View >
)
}
}
I'm new to react-native. I also tried to use require in my loop but no luck.
any help would be appreciated.
Change your products.image so their will be in this format:
products: {
...
image: require('.../Images.image.jpeg'),
...
}
And then change image source to this:
<Image style={styles.img} source={this.props.img} />
You cant dynamically require images in react-native. It's a major flaw in react native.
You have two options,
1.Either host the images onany server like cloudinary and send the URI
2.You can require all images at start, and then just include those image components like :
const flower = () => (
<Image source={require('../../)} />
)
const rat = () => (
<Image source={require('../../)} />
)
and (this.props.img == 'flower') ? flower():rat()
Hope you get the gyst. Feel free for doubts

Pdf does not appears on Android

I'm using the library react-native-pdf to show it.
Its frame is okay because I've set the background in blue.
I'm doing a RNFetchBlob.fs.exists(path) just before and the value is true but nothing appears on pdf viewer
Any idea ? I have no log or whatever which tell me there is a problem.
<Pdf source={{uri : filePath}}
style={{backgroundColor: 'grey', flex : 1}}/>
Here is how I show the pdf.
const request = RNFetchBlob
.config(this.getConfig(title, ext))
.fetch('GET', uri, header);
this.setState(
() => {
return {request: request}
},
() => {
this.state.request.then((res) => {
if (Platform.OS === 'android') {
const path = res.path()
const infos = res.info()
console.log(infos)
if (path !== undefined){
this.setState(() => {
return {
filePath : path
}
})
The file path is returned by the res.path()
addAndroidDownloads: {
useDownloadManager: true,
notification: false,
path: filePath,
description: `${title}`,
mediaScannable: true,
}
The variable config is made like this.

How to upload Image on server using ReactNative

I am setting headers and body , Using fetch with Post to upload image on server.I am getting the response code 200 but it is not uploading image but rest of the Data is getting uploaded.
Here is the code of body:
export default function setRequestBody(imagePath){
let boundry = "----WebKitFormBoundaryIOASRrUAgzuadr8l";
let body = new FormData();
body.append("--"+boundry+"\r\n");
body.append("Content-Disposition: form-data; name=imageCaption\r\n\r\n");
body.append("Caption"+"\r\n");
body.append("--"+boundry+"\r\n");
body.append("Content-Disposition: form-data; name=imageFormKey; filename =iimageName.pngg \r\n");
body.append("Content-Type: image/png \r\n\r\n");
body.append({uri : imagePath});
// appened image Data Here
body.append("\r\n");
body.append("--"+boundry+"--\r\n");
return body
}
Please help.What mistake I am making. :(
I've found the solution:
let body = new FormData();
body.append('photo', {uri: imagePath,name: 'photo.png',filename :'imageName.png',type: 'image/png'});
body.append('Content-Type', 'image/png');
fetch(Url,{ method: 'POST',headers:{
"Content-Type": "multipart/form-data",
"otherHeader": "foo",
} , body :body} )
.then((res) => checkStatus(res))
.then((res) => res.json())
.then((res) => { console.log("response" +JSON.stringify(res)); })
.catch((e) => console.log(e))
.done()
** filename is optional...
The problem is body.append({uri : imagePath}); because react native JSC does not support File and Blob, so you have to use libraries.
react-native-fetch-blob has very good support for this, example from its README.md
RNFetchBlob.fetch('POST', 'http://www.example.com/upload-form', {
Authorization : "Bearer access-token",
otherHeader : "foo",
'Content-Type' : 'multipart/form-data',
}, [
// element with property `filename` will be transformed into `file` in form data
{ name : 'avatar', filename : 'avatar.png', data: binaryDataInBase64},
// custom content type
{ name : 'avatar-png', filename : 'avatar-png.png', type:'image/png', data: binaryDataInBase64},
// part file from storage
{ name : 'avatar-foo', filename : 'avatar-foo.png', type:'image/foo', data: RNFetchBlob.wrap(path_to_a_file)},
// elements without property `filename` will be sent as plain text
{ name : 'name', data : 'user'},
{ name : 'info', data : JSON.stringify({
mail : 'example#example.com',
tel : '12345678'
})},
]).then((resp) => {
// ...
}).catch((err) => {
// ...
})
I've found the solution to Upload the Image on server in React Native:
const formdata = new FormData();
formdata.append('image[]', {
name: 'test.' + imageurl?.type?.substr(6),
type: imageurl?.type,
uri:
Platform.OS !== 'android'
? 'file://' + imageurl?.uri
: imageurl?.uri,
});
const res = await axios.post(url, formdata, {
headers: {
Accept: '*/*',
'Content-type': 'multipart/form-data',
},
});
//First Install and import Image-piker
//install
npm i react-native-image-picker
//import
import * as ImagePicker from 'expo-image-picker';
//then
const [image, setImage] = React.useState(null);
const [Type,setType]=React.useState('')
//Get the image
const pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
console.log(result);
if (!result.cancelled) {
// extract the filetype
setType(result.uri.substring(result.uri.lastIndexOf(".") + 1));
setImage(result.uri);
}
};
//show image return
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button title="Ecolher Foto" onPress={pickImage} />
{image && <Image source={{ uri: image }} style={{ width: 150, height: 150 }} />}
</View>
//UpLoad Image
var validatinoApi ='https://seusite.com/OOP/';
var headers={
'Accept':'application/json',
"Content-Type": "multipart/form-data",
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Origin':'*',
'crossDomain': 'true',
'Host': 'https://seusite.com/OOP/',
'Origin': 'https://origem.com',
};
/*'crossDomain': 'true',*/
var Data={
image:image,
namefoto: `photo.${namefoto}`,
type: `image/${Type}`
};
fetch(validatinoApi,
{
method:'POST',
headers:headers,
body:JSON.stringify(Data)
}).then((response)=>response.json())
.then((response)=>{
if(response.statusCode==200){
//Do something
}

Categories

Resources