Based from an example given here: http://openlayers.org/en/vector-api/examples/dynamic-data.html?q=dynamic
Instead of using circle:
var imageStyle = new ol.style.Circle({
radius: 5,
fill: new ol.style.Fill({color: 'yellow'}),
stroke: new ol.style.Stroke({color: 'red', width: 1})
});
I want to use Vector Feature (Marker) as the object which is moving instead of using that yellow circle.
An example of using a feature vector is found here:
how to add markers with OpenLayers 3
Sorry, just a beginner in OpenLayers 3. Hope someone can help me. Thanks!
I've made you a basic example.
The idea is: You move an Overlay through a path using an interval to change its position like:
//fire the animation
map.once('postcompose', function(event) {
interval = setInterval(animation, 500);
});
var i = 0, interval;
var animation = function(){
if(i == path.length){
i = 0;
}
marker.setPosition(path[i]);
i++;
};
Related
In Konva, I want to apply a click to the stage, but a doubleclick to a shape within the stage. Wondering what the best way to do this is.
Ultimately, wanted to create a floor plan where I can add tables (rectangles) to a map. If I click on the tables, Konva will allow me to add a rotation transformer. If I click outside the tables, the transformers on the stage disappear. I'm hoping that if I double click the tables, I can delete that shape. BUT - it doesn't appear I can both do a click on the stage, and check for a double click on an element within the stage. The code I have is the simplest example I know of to relate my ignorance about clicking and doubleclicking both on the stage and in an element on the stage.
//If you click on the stage, it creates the circle. And if you click on the circle, once created, I'm hoping it will be destroyed. It doesn't seem to like clicks and doubleclicks together in one area.
stage.on('click', function (e) {
var circle = new Konva.Circle({
x: 100,
y: 100,
fill: 'blue',
radius: 30,
draggable: true,
name: "circle"
});
layer.add(circle);
layer.draw();
});
circle.on('dblclick', function (e) {
this.destroy();
});
Wish I could delete the circle. The circle doesn't delete.
stage.on('click', function (e) {
const clickedOnEmptyArea = e.target === stage;
if (!clickedOnEmptyArea) {
return;
}
var circle = new Konva.Circle({
x: stage.getPointerPosition().x,
y: stage.getPointerPosition().y,
fill: 'blue',
radius: 30,
draggable: true,
name: "circle"
});
layer.add(circle);
layer.draw();
});
stage.on('dblclick', function (e) {
const clickedOnEmptyArea = e.target === stage;
if (clickedOnEmptyArea) {
return;
}
e.target.destroy();
layer.draw();
});
Demo: https://jsbin.com/hogahegame/edit?html,js,output
I am using Leaflet and Leaflet.Draw, and I am letting the user from my code to draw polygon (NOT using the Leaflet Draw Controls).
While the user is drawing the polygon I need to change the color of its first vertex, for example: green, so that user knows that he needs to click on the first point in order to close the polygon and finish drawing.
How can I change color of first vertex while drawing polygon using Leaflet.Draw?
The following image for elaboration, meaning it's fixed with a Paint Software.
P.S. Here is my code
var map = L.map('mapid',
{
minZoom: -1,
maxZoom: 4,
center: [0, 0],
zoom: 1,
crs: L.CRS.Simple
});
var polygonDrawer = new L.Draw.Polygon(map);
map.on('draw:created', function (e) {
var type = e.layerType, layer = e.layer;
layer.editing.enable();
layer.addTo(map);
});
$(document)ready(function(){
polygonDrawer.enable();
});
While I was hacking with the Leaflet.Draw and on the creation of polygon I have come up with the following code:
map.on('draw:drawvertex',
function (e) {
$(".leaflet-marker-icon.leaflet-div-icon.leaflet-editing-icon.leaflet-touch-icon.leaflet-zoom-animated.leaflet-interactive:first").css({ 'background-color': 'green' });
});
So, there is a listener you can insert it in your code, draw:drawvertex which means whenever a vertex created I need to do something.
Then, using jQuery you're selecting the first element from this long selector, and set its background color to green or any other color.
This is a way to do it with CSS only:
#root
> main
> div
> div.col-sm-8.m-auto.p-0.flex-column.float-right
> div.leaflet-container.leaflet-touch.leaflet-fade-anim.leaflet-grab.leaflet-touch-drag.leaflet-touch-zoom
> div.leaflet-pane.leaflet-map-pane
> div.leaflet-pane.leaflet-marker-pane
> div:nth-child(2) {
background: green;
}
For me, worked this way (classes are a little bit different. leaflet 1.3.1 and draw 0.4.3)
map.on('draw:drawvertex', function (e) {
$(".leaflet-marker-icon.leaflet-div-icon.leaflet-editing-icon.leaflet-zoom-animated.leaflet-interactive:first").css({ 'background-color': 'green' });
});
This is worked for me:
map.on("editable:vertex:dragend", function (e) {
// Set GREEN color for Vertex START (First) Point
$(".leaflet-marker-icon.leaflet-div-icon.leaflet-vertex-icon.leaflet-zoom-animated.leaflet-interactive.leaflet-marker-draggable:nth-child(1)").css({ 'background-color': 'green' });
// Set RED color for Vertex END (Last) Point
$(".leaflet-marker-icon.leaflet-div-icon.leaflet-vertex-icon.leaflet-zoom-animated.leaflet-interactive.leaflet-marker-draggable:nth-child(2)").css({ 'background-color': 'red' });
});
I am using Cesium and am looking to visually represent multiple polylines between the same two entities. For example, a green polyline from entity A to entity B, and also a blue polyline from entity A to entity B. I would like them not to overlap or blend, so I am imagining a fanning out as more lines are drawn, so that each line and what it represents can be visualized. I've included a crude drawing of what I'm trying to explain with the fanning out rather than overlapping.
I have a functional data structure keeping track of the lines I want to represent, as well as a Cesium map that they are already being programatically drawn on. I guess at this point I'm looking for the technical explanation of how to programatically bend the polylines on the map, and also any suggestions for polyline management in order to recognize overlapping lines so I can apply the bends.
Thanks for any help!
Here's one method. This sample code will "spread" the lines along longitude only, so works best on North/South lines and not on East/West lines. But I think it should convey the right idea, you just have to figure out a more general-purpose way of "moving" the midpoint to a visually pleasing location.
I'm using time-based paths here, to gain access to Cesium's interpolation logic. But I've selected a reference time far in the past, and I'm only showing the finished paths on the viewer. So, the user is none the wiser that time is playing any role here.
var viewer = new Cesium.Viewer('cesiumContainer', {
navigationInstructionsInitiallyVisible: false,
animation: false,
timeline: false,
// These next 5 lines are just to avoid the Bing Key error message.
imageryProvider : Cesium.createTileMapServiceImageryProvider({
url : Cesium.buildModuleUrl('Assets/Textures/NaturalEarthII')
}),
baseLayerPicker : false,
geocoder : false,
// This next line fixes another Stack Snippet error, you may omit
// this setting from production code as well.
infoBox : false
});
var numberOfArcs = 5;
var startLon = -105;
var startLat = 39.7;
var stopLon = -98.4;
var stopLat = 29.4;
var spread = 5;
var referenceTime = Cesium.JulianDate.fromIso8601('2001-01-01T00:00:00Z');
var midTime = Cesium.JulianDate.addSeconds(referenceTime, 43200, new Cesium.JulianDate());
var stopTime = Cesium.JulianDate.addSeconds(referenceTime, 86400, new Cesium.JulianDate());
for (var i = 0; i < numberOfArcs; ++i) {
var color = Cesium.Color.fromRandom({
alpha : 1.0
});
// Create a straight-line path.
var property = new Cesium.SampledPositionProperty();
var startPosition = Cesium.Cartesian3.fromDegrees(startLon, startLat, 0);
property.addSample(referenceTime, startPosition);
var stopPosition = Cesium.Cartesian3.fromDegrees(stopLon, stopLat, 0);
property.addSample(stopTime, stopPosition);
// Find the midpoint of the straight path, and move it.
var spreadAmount = (spread / (numberOfArcs - 1)) * i - (spread / 2);
var midPoint = Cesium.Cartographic.fromCartesian(property.getValue(midTime));
midPoint.longitude += Cesium.Math.toRadians(spreadAmount);
var midPosition = viewer.scene.globe.ellipsoid.cartographicToCartesian(
midPoint, new Cesium.Cartesian3());
// Redo the path to be the new arc.
property = new Cesium.SampledPositionProperty();
property.addSample(referenceTime, startPosition);
property.addSample(midTime, midPosition);
property.addSample(stopTime, stopPosition);
// Create an Entity to show the arc.
var arcEntity = viewer.entities.add({
position : property,
// This path shows the arc as a polyline.
path : {
resolution : 1200,
material : new Cesium.PolylineGlowMaterialProperty({
glowPower : 0.16,
color : color
}),
width : 10,
leadTime: 1e11,
trailTime: 1e11
}
});
// This is where it becomes a smooth path.
arcEntity.position.setInterpolationOptions({
interpolationDegree : 5,
interpolationAlgorithm : Cesium.LagrangePolynomialApproximation
});
}
// Optionally, add start and stop points, mostly for easy zoomTo().
viewer.entities.add({
position : Cesium.Cartesian3.fromDegrees(startLon, startLat),
point : {
pixelSize : 8,
color : Cesium.Color.WHITE
}
});
viewer.entities.add({
position : Cesium.Cartesian3.fromDegrees(stopLon, stopLat),
point : {
pixelSize : 8,
color : Cesium.Color.WHITE
}
});
viewer.zoomTo(viewer.entities);
html, body, #cesiumContainer {
width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden;
font-family: sans-serif;
}
<link href="http://cesiumjs.org/releases/1.30/Build/Cesium/Widgets/widgets.css"
rel="stylesheet"/>
<script src="http://cesiumjs.org/releases/1.30/Build/Cesium/Cesium.js">
</script>
<div id="cesiumContainer"></div>
I'm using MapBox GL JS to create a map with a custom marker:
var marker = new mapboxgl.Marker(container)
.setLngLat([
datacenters[country][city].coordinates.lng,
datacenters[country][city].coordinates.lat
])
.addTo(map);
However, I seem to have some kind of offset problem with the marker. The thing is: when zoomed out a bit, the bottom of the marker is not really pointing to the exact location:
When I'm zooming in a bit further it reaches its destination and it's pointing to the exact spot.
I really love MapBox GL, but this particular problem is bugging me and I'd love to know how to solve it. When this is fixed my implementation is far more superior to the original mapping software I was using.
From Mapbox GL JS 0.22.0 you're able to set an offset option to the marker. https://www.mapbox.com/mapbox-gl-js/api/#Marker
For example to offset the marker so that it's anchor is the middle bottom (for your pin marker) you would use:
var marker = new mapboxgl.Marker(container, {
offset: [-width / 2, -height]
})
.setLngLat([
datacenters[country][city].coordinates.lng,
datacenters[country][city].coordinates.lat
])
.addTo(map);
New solution for mapbox-gl.js v1.0.0 - Marker objects now have an anchor option to set the position to align to the marker's Lat/Lng: https://docs.mapbox.com/mapbox-gl-js/api/#marker
var marker = new mapboxgl.Marker(container, {anchor: 'bottom');
This should cover most cases and is more reliable than a pixel offset in my experience.
I've found an solution to my problem. It might be somewhat hacky, but it solves the positioning problem of the marker: I'm using a Popup fill it with a font awesome map marker icon and remove it's "tooltip styled" borders:
Javascript:
map.on('load', function() {
var container = document.createElement('div');
var icon = document.createElement('i');
icon.dataset.city = city;
icon.addEventListener('click', function(e) {
var city = e.target.dataset.city;
var country = e.target.dataset.country
flyTo(datacenters[country][city].coordinates);
});
icon.classList.add('fa', 'fa-map-marker', 'fa-2x');
container.appendChild(icon);
var popup = new mapboxgl.Popup({
closeButton: false,
closeOnClick: false
})
.setLngLat([
datacenters[country][city].coordinates.lng,
datacenters[country][city].coordinates.lat
])
.setDOMContent(container)
.addTo(map);
});
CSS:
.map div.mapboxgl-popup-content {
background: none;
padding: 0;
}
.map .mapboxgl-popup-tip {
display: none;
}
I just hope someone comes up with a real solution, because this feels kinda dirty to me. But hey: it does the job just fine!
Mapbox Marker now has an element option see this link Mapbox Marker. So instead of appending the icon HTML to the Div element you can simply add into the options when creating a marker. I found this also gets rid of the offset problem. So using the code above you can do this....
var icon = document.createElement('i');
icon.classList.add('fas', 'fa-map-marker-alt');
icon.style.color = 'blue';
new mapboxgl.Marker(container, {anchor: 'center', offset: [0, 0], element: icon})
Also the CSS for the marker can be updated to allow a pointer
.mapboxgl-marker {
border: none;
cursor: pointer;
}
I use leaflet and geojson-vt too displaing map, and some lines in vector tiles. I made some modifications in geojson-vt because i need to add some my functions when tiles are slicing.
Everything works fine, when i start my leafletMap from zoom 1, and then increasing zoom by mouse wheel, to for example zoom=15. But There is a problem when i start my Map with zoom= for example 7,
var leafletMap = L.map('map').setView([52.00, 19.64], 7);
because the vector tiles are not beeing calcuated from 0 to 7, but only at 7, so "my function" dont working well.
I think that the solution will be to start map on zoom 0, and then in loop increasing zoom to 7. But i dont know how.
I tried this but it isn't working with multiple zooms...
setTimeout(function() {
leafletMap.setZoom(2);
}, 300);
...
setTimeout(function() {
leafletMap.setZoom(7);
}, 300);
Here is an example that shows how to zoom in gradually. Part of the problem with your code is that you called sequential setTimeout methods with the same delay and so they will be executed one right after another. If you change the milliseconds so that they increase (300, 600, 900, ...) then you will actually see the animated zoom.
This was quick example using OSM tiles and not geojson-vt, so it looks a little clunky until your browser caches the tiles. However, with geojson-vt you are creating your own local vector tiles and so it should be a bit smoother.
However, I'm not sure this will solve your problem because you didn't show the code you changed in geojson-vt. It may be that setZoom() isn't triggering your functions, but until you show those custom functions it will be hard to get a proper answer to your question.
var zoomDelayMs = 600; // milliseconds for animation delay
var maxZoom = 18;
var initialZoom = 7;
// Create the map
var map = L.map('map').setView([39.5, -0.5], initialZoom);
// Set up the OSM layer
var baseLayer = L.tileLayer(
'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: maxZoom
}).addTo(map);
// function to zoom in gradually from initialZoom to maxZoom
slowZoom = function() {
// reset zoom to default
var zoom = initialZoom;
map.setZoom(zoom);
// if already in middle of slow zoom, stop it
if (map.zoomtimer) clearInterval(map.zoomtimer);
// zoom in one level every zoomDelayMs
map.zoomtimer = setInterval(function() {
if (zoom < maxZoom)
map.setZoom(++zoom);
else {
clearInterval(map.zoomtimer);
map.zoomtimer = 0;
}
}, zoomDelayMs);
}
#map {
height: 400px;
}
input {
font-size: 1.6em;
}
<link href="https://npmcdn.com/leaflet#0.7.7/dist/leaflet.css" rel="stylesheet" />
<script src="https://npmcdn.com/leaflet#0.7.7/dist/leaflet.js"></script>
<input type='button' onclick='slowZoom()' value='Start slow zoom' />
<div id="map"></div>