I've been trying pretty hard to add an onClick function on my clusters that zooms a bit on the map, but I can't figure out how to do so, and I can't find any help on the documentation.
I've been trying to work with controller.onCircleTappedand controller.onFeatureTapped but I don't understand how it's working, or how to link the callback to a particular cluster.
Thank you all!
Here's my current code:
`
Future<void> addGeojsonCluster() async {
var geojson = {
"type": "FeatureCollection",
"crs": { "type": "name", "properties": { "name": "pois" } },
"features": [
for(var marker in markers){
"type" : "Feature", "properties" : {"id" : marker.title}, "geometry": {"type" : "Point", "coordinates" : [marker.longitude, marker.latitude] }
},
]
};
await controller.addSource(
"poi",
GeojsonSourceProperties(
data: geojson,
cluster: true,
clusterMaxZoom: 14, // Max zoom to cluster points on
clusterRadius:
50, // Radius of each cluster when clustering points (defaults to 50)
)
);
await controller.addLayer(
"poi",
"poi-circles",
const CircleLayerProperties(
circleColor: [
Expressions.step,
[Expressions.get, 'point_count'],
'#51bbd6', //blue
100,
'#f1f075', //yellow
750,
'#f28cb1' //pink
],
circleRadius: [
Expressions.step,
[Expressions.get, 'point_count'],
20,
100,
30,
750,
40
]),
);
await controller.addSymbolLayer(
"poi",
"unclustered-point",
const SymbolLayerProperties(
textField: [Expressions.get, "id"],
textHaloWidth: 1,
textSize: 12.5,
textHaloColor: '#ffffff',
textOffset: [
Expressions.literal,
[0, 2]
],
iconImage: "images/mapbox_circle_marker.png",
iconSize: 2,
iconAllowOverlap: true,
textAllowOverlap: true,
textColor: '#000000',
textHaloBlur: 1,
),
filter: [
'!',
['has', 'point_count']
],
enableInteraction: true,
);
await controller.addLayer(
"poi",
"poi-count",
const SymbolLayerProperties(
textField: [Expressions.get, 'point_count_abbreviated'],
textFont: ['DIN Offc Pro Medium', 'Arial Unicode MS Bold'],
textSize: 12,
));
}
`
You need to register a OnTapListener on the whole map and query all the features on the map.
MapWidget(
onTapListener: _clickMap,
)
And in _clickMap you query for everything displayed on the map and decide depending on the return what to do. Here I zoom in to the next cluster step. Keep in mind, that there is currently a confirmed bug in the sdk. OnTapListener is not return ScreenCoordinates but geographical coordinates. So you need to convert them first with pixelForCoordinate.
void _clickMap(ScreenCoordinate coordinate) async {
ScreenCoordinate coordin = await mapboxMap!.pixelForCoordinate({
"coordinates": [coordinate.y, coordinate.x]
});
List<QueriedFeature?> features = await mapboxMap!.queryRenderedFeatures(
RenderedQueryGeometry(
type: Type.SCREEN_COORDINATE, value: json.encode(coordin.encode())),
RenderedQueryOptions(
layerIds: ['clusters', "unclustered-point"], filter: null));
if (features.isNotEmpty) {
if ((features[0]!.feature["properties"] as Map)['cluster'] != null) {
FeatureExtensionValue cluster = await mapboxMap!
.getGeoJsonClusterExpansionZoom(
'earthquakes', features[0]!.feature);
mapboxMap?.easeTo(
CameraOptions(
center: Point(
coordinates: Position(
(features[0]!.feature['geometry'] as Map)["coordinates"][0],
(features[0]!.feature['geometry'] as Map)["coordinates"][1],
)).toJson(),
zoom: double.parse(cluster.value!),
bearing: 0,
pitch: 0),
MapAnimationOptions(duration: 500, startDelay: 0));
}}}
Hope that helps :)
Related
I am using Reanimated2 on my React Native app in an Android emulator. I am trying to rotate a component using useAnimatedStyle. Here's my code. It works on iOS, but on Android I get an error.
const animatedStyle = useAnimatedStyle(() => {
let rotate = interpolate(x.value, [-150, 0, 150], [-Math.PI / 36, 0, Math.PI / 36], Extrapolate.CLAMP);
return {
transform: [{ translateY: y.value }, { translateX: x.value }, { rotate }],
}
});
I'm getting the following error on Android only: Transform with key of "rotate" must be a string: {"rotate":0}]
Then I change the code to a string:
const animatedStyle = useAnimatedStyle(() => {
let rotate = interpolate(x.value, [-150, 0, 150], ["-10deg", "0deg", "10deg"], Extrapolate.CLAMP);
return {
transform: [{ translateY: y.value }, { translateX: x.value }, { rotate }],
}
});
Then I get this error:
Error while updating property 'transform' of a view managed by: RTCView
null
For input string: "-10degNaN"
Can anyone help me fix this?
https://docs.swmansion.com/react-native-reanimated/docs/1.x.x/nodes/interpolate/
The documentation states, that you should use your first approach. Interpolate the numbers and then add the deg afterwards.
This should do the trick:
const animatedStyle = useAnimatedStyle(() => {
let rotate = interpolate(x.value, [-150, 0, 150], [-Math.PI / 36, 0, Math.PI / 36], Extrapolate.CLAMP);
return {
transform: [{ translateY: y.value }, { translateX: x.value }, { rotate: `${rotate}deg` }],
}
});
I am doing a contacts app using expo-contacts, I can see contacts but the problem comes when I need to add one.
This is the code I am using, the thing is that in some phones works and in other doesn't. Just to let you know, the permissions to write and read are already attached in app.json.
<Button
title="Guardar"
onPress={async () => {
const contact = {
[Contacts.Fields.FirstName]: "Test",
[Contacts.Fields.LastName]: "McTest",
[Contacts.Fields.PhoneNumbers]: [
{
number: "(123) 456-7890",
isPrimary: true,
digits: "1234567890",
countryCode: "PA",
id: "1",
label: "main",
},
],
[Contacts.Fields.Emails]: [
{
email: "test#gmail.com",
isPrimary: true,
id: "2",
label: "main",
},
],
};
await Contacts.addContactAsync(contact)
.then((contactId) => {
alert("Se creó exitosamente");
})
.catch((err) => {
alert(err);
console.log(err);
});
}}
The error I am getting is this: Error: insert into content://com.android.contacts/data returned no result.
To finish its important to say that I am using apk already built and not doing in debugging mode in expo.
I will appreciate your answers.
Solved: it was how i organiced data structure to push contact details.
[Contacts.Fields.PhoneNumbers]: [
{
number: "(123) 456-7890",
isPrimary: true,
digits: "1234567890",
countryCode: "PA",
id: "1",
label: "main",
},
]
Changing label from 'main' to 'mobile' worked for me.
I am working on an AR application using ARCore Sceneform. I was trying to add normal map to a face mesh texture. But there is no documentation or demo available on that.
Texture.builder()
.setSource(this, R.drawable.cartoon)
.setUsage(Texture.Usage.COLOR)
.build()
.thenAccept(texture -> faceMeshTexture = texture);
addOnUpdateListener:
for (AugmentedFace face: faceList) {
if (!faceNodeMap.containsKey(face)) {
AugmentedFaceNode faceNode = new AugmentedFaceNode(face);
faceNode.setParent(scene);
// faceNode.setFaceRegionsRenderable(faceRegionsRenderable);
faceNode.setFaceMeshTexture(faceMeshTexture);
faceNodeMap.put(face, faceNode);
}
}
Check out this article about using custom materials in ARCore.
I do not know your case, but you might need to create a custom material as described in the article and for that you need a dummy object.
Sceneform framework provides you with a default material definitions that allow developers to get plausibly looking materials. So, you can add a normal map for your canonical face mesh using JSONish code in .sfa or .mat file.
Look at this example at GitHub.
Here's code snippet:
{
materials: [
{
name: 'Planet_Mat',
parameters: [
{ baseColorFactor: [ 1, 1, 1, 1, ], },
{ baseColor: 'Planet_Mat_baseColor', },
{ normal: 'Planet_Mat_normal', },
{ metallicFactor: 1, },
{ metallicRoughness: 'Planet_Mat_occlusionRoughnessMetallic', },
{ emissiveFactor: [ 0, 0, 0, 1, ], },
],
source: 'build/sceneform_sdk/default_materials/gltf_material.sfm',
},
],
model: {
attributes: [
'Position',
'TexCoord',
'Orientation',
],
collision: {},
file: 'sampledata/models/Planet/Planet.gltf',
name: 'Planet',
recenter: true,
scale: 0.5,
},
samplers: [
{
file: 'sampledata/models/Planet/Planet_Mat_baseColor.png',
name: 'Planet_Mat_baseColor',
pipeline_name: 'Planet_Mat_baseColor.png',
},
{
file: 'sampledata/models/Planet/Planet_Mat_normal.png',
name: 'Planet_Mat_normal',
params: {
usage_type: 'Normal',
},
pipeline_name: 'Planet_Mat_normal.png',
},
],
}
I have a jquery flot with filtering buttons below the graphic , which enable user to show the values on a weekly manner, or daily manner and so on.
The problem happens when the user clicks a filtering button, suddenly another flot chart above the first chart is created and it stays there till I leave the page and come back to the page.
I have the following code to show a graph as soon as user gets to the page ;
And the filtering button calls a function that has the same piece of code but with a different tick size (with week for example).
PS: I'm using Phonegap that prepares the app for the normal Android webview. The engine used depends on the Android version.
WebKit versions; Ref
Android 4.2.2 534.30 ( Another flot chart is created)
Android 4.4.x 537.36 ( Works as expected )
Code:
var plot = $.plot("#placeholder", [{
data: dAlle
}], {
series: {
lines: {
show: true
},
points: {
show: true
}
},
grid: {
hoverable: true,
clickable: true,
markings: [{
yaxis: {
from: 0,
to: 12
},
color: "#F2CDEA"
}, {
yaxis: {
from: rangeMin,
to: rangeMax
},
color: "#D7EEE1"
}]
},
xaxis: {
mode: "time",
minTickSize: [1, "month"],
/*min: theVeryFirstPoint,
max: theVeryLastPoint*/
},
yaxis: {
min: 0,
max: 12
}
});
The weird thing is that same logic works for Android with LG G2 API level 19 (4.4.2), but when I install the app into Samsung S2 with API Level 16 (4.2.2) , this problem occurs. Is there any way of preventing it from occuring?
CSS + JS imports are as follows ;
<link rel="stylesheet" href="css/jquery.mobile-1.4.2.min.css">
<link rel="stylesheet" type="text/css" href="css/main.css" />
<link rel="stylesheet" href="css/jqm-icon-pack-fa.css" />
<script type="text/javascript" src="cordova.js"></script>
<script src="js/jquery-1.11.2.min.js"></script>
<script src="js/jquery.mobile-1.4.5.min.js"></script>
<link href="css/examples.css" rel="stylesheet" type="text/css">
<script language="javascript" type="text/javascript" src="js/flot/jquery.flot.js"></script>
<script language="javascript" type="text/javascript" src="js/flot/jquery.flot.threshold.js"></script>
<script language="javascript" type="text/javascript" src="js/flot/jquery.flot.time.js"></script>
<script language="javascript" type="text/javascript" src="js/flot/jquery.flot.areamarkings.js"></script>
Filter function that is called ;
$("#a-uke").click(function() {
console.log("a dag filtering will be applied...");
var newDataSer = window.localStorage.getItem("storedData");
if (newDataSer != null) {
newDataSer = JSON.parse(newDataSer);
// Just convert into a new array object for the FIRST time
//if (dagButtonClicked == false) {
$.each(newDataSer, function(index, datapoint) {
datapoint[2] = datapoint[0];
datapoint[0] = (new Date(datapoint[0])).getHours();
console.log("hours created : " + datapoint[0]);
dagButtonClicked = true;
});
//}
if (newDataSer != null && newDataSer.length > 0) {
newDataSer.sort(function(x, y) {
console.log("sorting..");
return x[0] - y[0];
})
}
} else
newDataSer = [];
$.plot("#placeholder", [newDataSer], {
series: {
lines: {
show: true
},
points: {
show: true
}
},
grid: {
hoverable: true,
clickable: true,
areaMarkings: [{
points: [
[7, 12],
[24, 12],
[24, 0],
[7, 0]
],
lineWidth: 0,
fillColor: "#F2CDEA"
}, {
points: [
[7, rangeBr1],
[7, rangeBr2],
[10, rangeBr2],
[10, rangeBr1]
], // Green for breakfast
lineWidth: 0,
fillColor: "#D7EEE1"
}, {
points: [
[7, rangeBr2],
[7, rangeBr3],
[10, rangeBr3],
[10, rangeBr2]
], // Gradient1 Top for breakfast
lineWidth: 0,
fillColor: "#DFE4E3"
}, {
points: [
[7, rangeBr3],
[7, rangeBr4],
[10, rangeBr4],
[10, rangeBr3]
], // Gradient2 Top for breakfast
lineWidth: 0,
fillColor: "#E7DAE6"
}, {
points: [
[7, rangeBrBot2],
[7, rangeBrBot3],
[10, rangeBrBot3],
[10, rangeBrBot2]
], // Gradient1 Bottom for breakfast
lineWidth: 0,
fillColor: "#DFE4E3"
}, {
points: [
[7, rangeBrBot1],
[7, rangeBrBot2],
[10, rangeBrBot2],
[10, rangeBrBot1]
], // Gradient2 Bottom for breakfast
lineWidth: 0,
fillColor: "#E7DAE6"
}, {
points: [
[10, rangeMin],
[10, rangeMaxGrad],
[24, rangeMaxGrad],
[24, rangeMin]
], // Green for the rest
lineWidth: 0,
fillColor: "#D7EEE1"
}, {
points: [
[10, rangeMaxGrad],
[10, rangeMaxGrad2],
[24, rangeMaxGrad2],
[24, rangeMaxGrad]
], // Gradient1 top for the rest
lineWidth: 0,
fillColor: "#DFE4E3"
}, {
points: [
[10, rangeMaxGrad2],
[10, rangeMaxGrad3],
[24, rangeMaxGrad3],
[24, rangeMaxGrad2]
], // Gradient2 top for the rest
lineWidth: 0,
fillColor: "#E7DAE6"
}, {
points: [
[10, rangeMinGrad2],
[10, rangeMin],
[24, rangeMin],
[24, rangeMinGrad2]
], // Gradient1 bottom for the rest
lineWidth: 0,
fillColor: "#DFE4E3"
}, {
points: [
[10, rangeMinGrad3],
[10, rangeMinGrad2],
[24, rangeMinGrad2],
[24, rangeMinGrad3]
], // Gradient2 bottom for the rest
lineWidth: 0,
fillColor: "#E7DAE6"
}]
},
xaxis: {
tickFormatter: getAmPmHour,
min: 7,
max: 24
},
yaxis: {
min: 0,
max: 12
}
});
});
Not sure what is causing that bug, but there are two possible solutions you can try:
1) You can clear the old plot before creating the new one:
$('#placeholder').empty();
$.plot("#placeholder", [newDataSer], { /* your new options */ });
2) You can use the existing plot instead of creating a new one (which is the recommended way):
plot.setData([newDataSer]);
plot.getOptions().grid.areaMarkings = [ /* your new markings / options */ ];
plot.getOptions().xaxis = { /* your new options */ };
plot.setupGrid();
plot.draw();
Ext.define('Video.view.video', {
extend: 'Ext.Container',
requires: [
'Ext.Video'
],
config: {
layout: 'fit',
items: [{
xtype: 'video',
url: ['aa.mp4'],
loop: true,
posterUrl: 'resources/images/cover.jpg'
}]
}
});
this is my code, but not display video
Please #Amit kumar can you try something like this,
Ext.define('myapp.view.Video', {
extend: 'Ext.Container',
xtype: 'myvideo',
requires: [
'Ext.Video'
],
config: {
layout: 'fit',
items: [
{
xtype: 'video',
enableControls: false,
x : 600,
y : 300,
width : 300,
height : 250,
url: 'app/images/VID.3GP',
loop: true,
posterUrl: 'app/images/transfers.png'
},
]
}
});
I hope this helps. :)