I am just trying out the SDK Lite API and I am wondering how I can achieve to drag a MapMarker object from one place to another. I suggest, it works somehow with disabling the default onPan gesture, but actually the problem starts with picking an existing object.
Here is my code so far:
public void pickMarker(Point2D p) {
map.getGestures().disableDefaultAction(GestureType.PAN);
map.pickMapItems(p, 20f, pickMapItemsResult -> {
if (pickMapItemsResult != null) {
pickedMarker = pickMapItemsResult.getTopmostMarker();
} else {
map.getGestures().enableDefaultAction(GestureType.PAN);
}
});
}
public void dragMarker(Point2D p) {
if (pickedMarker != null) {
pickedMarker.setCoordinates(map.getCamera().viewToGeoCoordinates(p));
}
}
public boolean releaseMarker(Point2D p) {
map.getGestures().enableDefaultAction(GestureType.PAN);
if (pickedMarker != null) {
GeoCoordinates newCoordinates = map.getCamera().viewToGeoCoordinates(p);
pickedMarker.setCoordinates(newCoordinates);
pickedMarker = null;
return true;
}
return false;
}
while these functions are called on the three states of the onPanListener:
mapView.getGestures().setPanListener((gestureState, point2D, point2DUpdate, v) -> {
if (gestureState.equals(GestureState.BEGIN)) {
mapViewUIEngine.pickMarker(point2D);
}
if (gestureState.equals(GestureState.UPDATE)) {
mapViewUIEngine.dragMarker(point2DUpdate);
}
if (gestureState.equals(GestureState.END)) {
if (mapViewUIEngine.releaseMarker(point2DUpdate)) {
regionController.movePoint(0,
updateNewLocation(point2D, point2DUpdate);
}
}
});
From one of the developer in Github I now know, that the polygon is returned instead of the marker (which is lying on a polygon line, but how can I get the marker instead?
You can use map markers to precisely point to a location on the map.
The following method will add a custom map marker to the map:
MapImage mapImage = MapImageFactory.fromResource(context.getResources(), R.drawable.here_car);
MapMarker mapMarker = new MapMarker(geoCoordinates);
mapMarker.addImage(mapImage, new MapMarkerImageStyle());
mapView.getMapScene().addMapMarker(mapMarker);
For more details, please refer
https://developer.here.com/documentation/android-sdk/dev_guide/topics/map-items.html#add-map-markers
Related
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
mapFragment?.getMapAsync(this)
}
#SuppressLint("MissingPermission", "PotentialBehaviorOverride")
override fun onMapReady(googleMap: GoogleMap?) {
map = googleMap!!
map.isMyLocationEnabled = true
map.setOnMyLocationButtonClickListener(this)
map.setOnMarkerClickListener(this)
map.uiSettings.apply {
isZoomControlsEnabled = false
isZoomGesturesEnabled = false
isRotateGesturesEnabled = false
isTiltGesturesEnabled = false
isCompassEnabled = false
isScrollGesturesEnabled = false
}
observeTrackerService()
}
private fun observeTrackerService() {
TrackerService.locationList.observe(viewLifecycleOwner, {
if (it != null) {
locationList = it
if (locationList.size > 1) {
binding.stopButton.enable()
}
drawPolyline()
followPolyline()
}
})
TrackerService.started.observe(viewLifecycleOwner, {
started.value = it
})
TrackerService.startTime.observe(viewLifecycleOwner, {
startTime = it
})
TrackerService.stopTime.observe(viewLifecycleOwner, {
stopTime = it
if (stopTime != 0L) {
showBiggerPicture()
displayResults()
}
})
}
private fun drawPolyline() {
val polyline = map.addPolyline(
PolylineOptions().apply {
width(10f)
color(Color.BLUE)
jointType(JointType.ROUND)
startCap(ButtCap())
endCap(ButtCap())
addAll(locationList)
}
)
polylineList.add(polyline)
}
private fun followPolyline() {
if (locationList.isNotEmpty()) {
map.animateCamera(
(CameraUpdateFactory.newCameraPosition(
setCameraPosition(
locationList.last()
)
)), 1000, null)
}
}
}
private fun showBiggerPicture() {
val bounds = LatLngBounds.Builder()
for (location in locationList) {
bounds.include(location)
}
map.animateCamera(
CameraUpdateFactory.newLatLngBounds(
bounds.build(), 100
), 2000, null
)
addMarker(locationList.first())
addMarker(locationList.last())
}
private fun addMarker(position: LatLng){
val marker = map.addMarker(MarkerOptions().position(position))
markerList.add(marker)
}
private fun displayResults() {
val result = Result(
calculateTheDistance(locationList),
calculateElapsedTime(startTime, stopTime)
)
lifecycleScope.launch {
delay(2500)
val directions = MapsFragmentDirections.actionMapsFragmentToResultFragment(result)
findNavController().navigate(directions)
binding.startButton.apply {
hide()
enable()
}
binding.stopButton.hide()
binding.resetButton.show()
} `
I would like to send the polylines to Firestore. How to send the polylines in code to Firestore? Can anyone help? My code has a map fragment with buttons. This is a distance tracking app. The app plots the distance using polylines. How to convert polylines to arrays. Here I am doing a location tracking app. I want to convert the polylines to arrays so that I could save it cloud.
According to the official documentation, a Polyline is not a Firestore supported data-type. So there is no way you can add such an object to Firestore.
What's a polyline?
It's basically a list of points. So what you can do instead is to add all these points to Firestore. You can add them as simple as latitude and longitude or as GeoPoint objects. If you have additional details for the locations, you can add them as documents in a collection, otherwise, you can store them in an array within a document.
To read them, simply create a reference to the document, loop through the array, create a new LatLng object of each location, and add all of them to the polyline.
I was taking a look at this :
tornadofx
and tried to expand on it with database connection and little more options, (not all of them make sense, but its just playing in a sandbox).
Even though table can be directly edited and the data will persist in database, i did try to do edit through text fields too. actual table editing would happen through different view and not table itself, as i said its just example.
Database used is Jetbrains Exposed.
object Categories : IntIdTable() {
val name = varchar("name", 64).uniqueIndex()
val description = varchar("description", 128)
}
class Category(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<Category>(Categories)
var name by Categories.name
var description by Categories.description
override fun toString(): String {
return "Category(name=\"$name\", description=\"$description\")"
}
}
now controller looks something like this, functions are just rudimentary and picked as an example.
typealias ModelToDirtyState = Map.Entry<CategoryModel, TableColumnDirtyState<CategoryModel>>
class CategoryModel() : ItemViewModel<Category>() {
val name: SimpleStringProperty = bind(Category::name)
val description: SimpleStringProperty = bind(Category::description)
}
class DBController : Controller() {
val categories: ObservableList<CategoryModel> by lazy {
transaction {
SchemaUtils.create(Categories)
Category.all().map {
CategoryModel().apply {
item = it
}
}.observable()
}
}
init {
Database.connect(
"jdbc:mysql://localhost:3306/test", driver = "com.mysql.cj.jdbc.Driver",
user = "test", password = "test"
)
TransactionManager.manager.defaultIsolationLevel = Connection.TRANSACTION_SERIALIZABLE
}
fun deleteCategory(model: CategoryModel) {
runAsync {
transaction {
model.item.delete()
}
}
categories.remove(model)
}
fun updateCategory(model: CategoryModel) {
transaction {
Categories.update {
model.commit()
}
}
}
fun commitDirty(modelDirtyMappings: Sequence<ModelToDirtyState>) {
transaction {
modelDirtyMappings.filter { it.value.isDirty }.forEach {
it.key.commit()
println(it.key)// commit value to database
it.value.commit() // clear dirty state
}
}
}
Just to quickly comment on controller, delete method works as "intended" however the update one does not, it does not work in sense that after using delete item is remove both from database and tableview(underlying list) itself, and when i do update its not, now i know the reason, i call remove manually on both database and list, now for update perhaps i could do change listener, or maybe tornadofx can do this for me, i just cant set it up to do it. Following code will make things clearer i think.
class CategoryEditor : View("Categories") {
val categoryModel: CategoryModel by inject()
val dbController: DBController by inject()
var categoryTable: TableViewEditModel<CategoryModel> by singleAssign()
var categories: ObservableList<CategoryModel> by singleAssign()
override val root = borderpane {
categories = dbController.categories
center = vbox {
buttonbar {
button("Commit") {
action {
dbController.commitDirty(categoryTable.items.asSequence())
}
}
button("Roll;back") {
action {
categoryTable.rollback()
}
}
// This model only works when i use categorytable.tableview.selected item, if i use categoryModel, list gets updated but not the view itself
// Question #1 how to use just categoryModel variable without need to use categorytable.tableview.selecteditem
button("Delete ") {
action {
val model = categoryTable.tableView.selectedItem
when (model) {
null -> return#action
else -> dbController.deleteCategory(model)
}
}
}
//And here no matter what i did i could not make the view update
button("Update") {
action {
when (categoryModel) {
null -> return#action
else -> dbController.updateCategory(categoryModel)
}
categoryTable.tableView.refresh()
}
}
}
tableview<CategoryModel> {
categoryTable = editModel
items = categories
enableCellEditing()
enableDirtyTracking()
onUserSelect() {
//open a dialog
}
//DOES WORK
categoryModel.rebindOnChange(this) { selectedItem ->
item = selectedItem?.item ?: CategoryModel().item
}
// Question #2. why bindSelected does not work, and i have to do it like above
//DOES NOT WORK
// bindSelected(categoryModel)
//
column("Name", CategoryModel::name).makeEditable()
column("Description", CategoryModel::description).makeEditable()
}
}
right = form {
fieldset {
field("Name") {
textfield(categoryModel.name)
}
}
fieldset {
field("Description") {
textfield(categoryModel.description)
}
}
button("ADD CATEGORY") {
action {
dbController.addCategory(categoryModel.name.value, categoryModel.description.value)
}
}
}
}
}
I apologize for huge amount of code, also in last code snipped i left questions in form of comments where i fail to achive desired results.
I am sure i am not properly binding code, i just dont see why, also i sometimes use one variable to update data, my declared one "categoryModel" and sometimes i use tableview.selecteditem, it just seems hacky and i cant seem to grasp way.
Thank you!
I work on Xamarin.Fomrs shared project. I want to display multiple images at same place with 100 ms interval. So that it will look like a GIF. In Android It is working. I created drawable file and in that I have put all the images with time interval. But in iOS, I am facing problem.
I found CAKeyFrameAnimation is used to implement this type of functionality. But I couldn't find how to implement it as I want.
I have implemented CAKeyFrameAnimation in ImageRenderer like this
class AnimatedImageRenderer : ImageRenderer
{
public AnimatedImageRenderer() { }
Animation objAnimation = new Animation();
protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
{
base.OnElementChanged(e);
if (Control != null)
{
try
{
CAKeyFrameAnimation anim = CAKeyFrameAnimation.FromKeyPath("contents");
anim.Duration = 1;
//anim.KeyTimes = new[] {
// NSNumber.FromDouble (0), // FIRST VALUE MUST BE 0
// NSNumber.FromDouble (0.1),
// NSNumber.FromDouble(0.2),
// NSNumber.FromDouble(0.3),
// NSNumber.FromDouble(0.5),
// NSNumber.FromDouble(0.6),
// NSNumber.FromDouble(0.8),
// NSNumber.FromDouble(1.0), // LAST VALUE MUST BE 1
// };
anim.Values = new NSObject[] {
FromObject(UIImage.FromFile("bomb1.png")),
FromObject(UIImage.FromFile("bomb2.png")),
FromObject(UIImage.FromFile("bomb3.png")),
FromObject(UIImage.FromFile("bomb4.png")),
FromObject(UIImage.FromFile("bomb5.png")),
FromObject(UIImage.FromFile("bomb6.png")),
FromObject(UIImage.FromFile("bomb7.png")),
};
//anim.TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.Linear);
anim.RepeatCount = 1;
anim.RemovedOnCompletion = false;
//anim.CalculationMode = CAAnimation.AnimationLinear;
//c.Init();
Control.Layer.AddAnimation(anim, "bomb");
}
catch (System.Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
// ModCommon.TraceLog("AnimatedImageRenderer tm_Tick" + ex.Message);
}
}
}
}
I don't know what extra property is missing. Please guide me.
Thank you :)
You should use CGImage instead of UIImage. Change your animation's value to:
anim.Values = new NSObject[] {
FromObject(UIImage.FromFile("bomb1.png").CGImage),
FromObject(UIImage.FromFile("bomb2.png").CGImage),
FromObject(UIImage.FromFile("bomb3.png").CGImage),
FromObject(UIImage.FromFile("bomb4.png").CGImage),
FromObject(UIImage.FromFile("bomb5.png").CGImage),
FromObject(UIImage.FromFile("bomb6.png").CGImage),
FromObject(UIImage.FromFile("bomb7.png").CGImage),
};
I am trying to find a way to detect (or receive notification) that a Node has been added to a Scene and is visible.
I am creating Node objects off the main JavaFx thread and add them to the Stage and Scene using Platform.runLater(). However I would like the Node object to receive notification that is has been added to the Scene and is visible, for example I wish to trigger an animation to start.
I can't seem to find any property or method to add a listener to capture such an event. Any suggestions?
The third-party JavaFX library ReactFX has a mechanism for this, and this exact use case is cited in the blog. In short, you can do
Val<Boolean> showing = Val.flatMap(node.sceneProperty(), Scene::windowProperty)
.flatMap(Window::showingProperty);
and then of course
showing.addListener((obs, wasShowing, isNowShowing) -> {
if (isNowShowing) {
// node is showing
} else {
// node is not showing
}
});
The standard library has a version of this, but it is very badly written. (It is not typesafe, has no compile-time checking that the properties exist, and also pipes a lot of unnecessary warnings to standard error if any of the properties in the "chain" are null, even though the API docs indicate this is a supported use case.) If you want to do this with the standard JavaFX library, you can do
BooleanBinding showing = Bindings.selectBoolean(node.sceneProperty(), "window", "showing");
and then use the binding the same way as above.
Finally, you could do all this by hand, but it gets a bit ugly to manage the listeners properly:
BooleanProperty showing = new SimpleBooleanProperty();
ChangeListener<Window> windowListener = (obs, oldWindow, newWindow) -> {
showing.unbind();
if (newWindow != null) {
showing.bind(newWindow.showingProperty());
} else {
showing.set(false);
}
};
ChangeListener sceneListener = (obs, oldScene, newScene) -> {
showing.unbind();
if (oldScene != null) {
oldScene.windowProperty().removeListener(windowListener);
}
if (newScene == null) {
showing.set(false);
} else {
newScene.windowProperty().addListener(windowListener);
if (newScene.getWindow() == null) {
showing.set(false);
} else {
showing.bind(newScene.getWindow().showingProperty());
}
}
};
node.sceneProperty().addListener(sceneListener);
if (node.getScene() == null) {
showing.set(false);
} else {
node.getScene().windowProperty().add(windowListener);
if (node.getScene().getWindow() == null) {
showing.set(false);
} else {
showing.bind(node.getScene().getWindow().showingProperty());
}
}
You can add a listener to the children property of container node into which you are adding the new node.
grid.getChildren().addListener((ListChangeListener<? super Node>) change -> {
System.out.println(change.getList().get(0).getTypeSelector());
});
change.getList().get(0) returns the first node that is added to grid object.
After James's comment, I have looked up and yes, it is possible to do it from node's perspective as well. You can listen to parentProeprty's changes on the node. Following snippet shows the way to do it.
Button b = new Button("Test");
b.parentProperty().addListener((observable, oldValue, newValue) -> {
System.out.println("added to a container " + newValue);
});
answerPane.getChildren().add(b);
I have a lot of POIs in my database including location property. How can I add those POIs based on my location on my Map? I found HERE SDK has api like 'Explore Popular Places by Category', but these categories are predefined by HERE. I don't think I can add my POIs to HERE and search by these APIs.
I knew a solution that by adding cluster Marker on Map. but It's difficult and expensive if I retrieve POIs in my database every time. like finding all the POIs which within a circle region(radius is 10 miles). Do you have any better solution for adding custom POIs on HERE map?
Thanks
You may be looking for the Custom Location Extension.
You can add your custom POIs(markers) with custom images using HERE maps, here is the code:
After initialisation map onButtonClick,
SearchRequest searchRequest = new SearchRequest("Water");
searchRequest.execute(discoveryResultPageListener);
then add this method:
private ResultListener<DiscoveryResultPage> discoveryResultPageListener = new ResultListener<DiscoveryResultPage>() {
#Override
public void onCompleted(DiscoveryResultPage discoveryResultPage, ErrorCode errorCode) {
if (errorCode == ErrorCode.NONE) {
List<DiscoveryResult> s_ResultList = discoveryResultPage.getItems();
for (DiscoveryResult item : s_ResultList) {
/*
* Add a marker for each result of PlaceLink type.For best usability, map can be
* also adjusted to display all markers.This can be done by merging the bounding
* box of each result and then zoom the map to the merged one.
*/
if (item.getResultType() == DiscoveryResult.ResultType.PLACE) {
PlaceLink placeLink = (PlaceLink) item;
addMarkerAtPlace(placeLink);
Log.e("nameeee ",""+placeLink.getTitle());
}
}
} else {
Toast.makeText(m_activity,
"ERROR:Discovery search request returned return error code+ " + errorCode,
Toast.LENGTH_SHORT).show();
}
}
};
after this add a method for custom marker,
private void addMarkerAtPlace(PlaceLink placeLink) {
Image img = new Image();
try {
img.setImageResource(R.drawable.camping);
} catch (Exception e) {
e.printStackTrace();
}
MapMarker mapMarker = new MapMarker();
mapMarker.setIcon(img);
mapMarker.setTitle(placeLink.getTitle());
mapMarker.setCoordinate(new GeoCoordinate(placeLink.getPosition()));
m_map.addMapObject(mapMarker);
m_map.setCenter(new GeoCoordinate(placeLink.getPosition()), Map.Animation.NONE);
m_map.setZoomLevel(13);
List<MapObject> m_mapObjectList = new ArrayList<>();
m_mapObjectList.add(mapMarker);
}