Changing OpenLayers marker icon - javascript

I have a problem with OpenLayers. If I want to change the icon of some marker on the fly (for instance, to paint the marker with another color to indicate a status change), the marker starts behaving buggy, not showing in the proper place and even leaving semi-randomly located copies of itself, noticeable when zooming the map in or out.
I already realized that the problem happens when I reassign the marker.icon attribute, from some pre-loaded icon images which work fine otherwise. I have tried both with and without using icon.clone() to redraw.
Here's a full but simplified example which moves the marker randomly and should modify its icon too. If you comment out the "troublesome code" snippet, it works well, except for the icon change:
<!DOCTYPE HTML>
<HTML>
<HEAD>
<TITLE>Mapa</TITLE>
<SCRIPT language="javascript" type="text/javascript" src="OpenLayers.js"></SCRIPT>
<SCRIPT language="javascript" type="text/javascript">
var vMapa;
var prj0 = new OpenLayers.Projection("EPSG:4326"); // Transform from WGS 1984
var prj1 = new OpenLayers.Projection("EPSG:900913"); // to Spherical Mercator Projection
var vLon = 12.568142;
var vLat = 55.676320;
var vTimer = null;
var vCont = 0;
</SCRIPT>
</HEAD>
<BODY onClose="vTimer = null; vLon = null; vLat = null;">
<DIV id="demoMap" style="height: 700px; width: 1000px;"></DIV><DIV id="Contador">0</DIV>
<SCRIPT>
var options = {
controls: [
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PanZoomBar(),
]
};
vMapa = new OpenLayers.Map("demoMap", options);
vMapa.addLayer(new OpenLayers.Layer.OSM());
vMapa.setCenter(new OpenLayers.LonLat(vLon, vLat).transform(prj0, prj1), 15, false, false);
var Navigation = new OpenLayers.Control.Navigation( { defaultDblClick: function(event) { return; } } );
vMapa.addControl(Navigation);
var markers = new OpenLayers.Layer.Markers("Markers");
vMapa.addLayer(markers);
var size = new OpenLayers.Size(12, 12);
var offset = new OpenLayers.Pixel(-6, -6);
var iconOff = new OpenLayers.Icon('img/CircOff.png', size, offset);
var iconOn = new OpenLayers.Icon('img/CircOn.png', size, offset);
var marker = new OpenLayers.Marker(new OpenLayers.LonLat(vLon, vLat).transform(prj0, prj1), iconOff.clone());
marker.setOpacity(1.0);
marker.events.register('mousedown', marker, function(evt) { vMapa.panTo(marker.lonlat); OpenLayers.Event.stop(evt); });
marker.pfInfo = 'Vel: 0.0 km/h';
markers.addMarker(marker);
vTimer = setTimeout('TimerEvent()', 1000);
function TimerEvent() {
vLon += ((Math.random() - 0.5) / 500);
vLat += ((Math.random() - 0.5) / 500);
// ------- Troublesome code -------
var ixIcon = Math.round(Math.random());
if (ixIcon == 0) {
marker.icon = iconOff.clone();
} else {
marker.icon = iconOn.clone();
}
// --------------------------------
var newLonLat = new OpenLayers.LonLat(vLon, vLat).transform(prj0, prj1);
var newPx = marker.map.getLayerPxFromViewPortPx(marker.map.getPixelFromLonLat(newLonLat));
marker.moveTo(newPx);
marker.draw();
vCont ++;
document.getElementById('Contador').innerHTML = vCont;
vTimer = setTimeout('TimerEvent()', 1000);
}
</SCRIPT>
</BODY>
</HTML>
Thanks a lot in advance for your suggestions.

I never use Marker to create markers.
I create a Vector layer, and add Point objects. Then style these Points.
This works much better and has more functionality.

You can create a restful web service which can return an SVG as a string. The parameters passed would tell the service what has to change on the icon. The service would read in a template SVG change it appropriately and return it.

Related

Leaflet/JS: Adding polylines after pan/zoom

I am using a Leaflet map as an image viewer, and I'm trying to add a 'toggle crosshairs' function that will place a crosshair at the center of the image. I've got it working to a point where the crosshair appears correctly, and is 'coupled' to the image when doing pans/zooms, which is what I would expect to see.
The issue I'm having is that if I do the pan/zoom FIRST, and then toggle the crosshairs, the crosshairs appear in the center of the 'window', not in the center of the image.
The code I'm using for this is here:
toggleCrosshair(toggleVal) {
let map = this.map;
if (toggleVal == true) {
var north = map.getBounds().getNorth(); // these are in lat, lng
var south = map.getBounds().getSouth();
var east = map.getBounds().getEast();
var west = map.getBounds().getWest();
var center = map.getCenter();
var latlngHorizontalLeft = new L.latLng(center.lat, west);
var latlngHorizontalRight = new L.latLng(center.lat, east);
var horizLineList = [latlngHorizontalLeft, latlngHorizontalRight];
let horizLine = new L.Polyline(horizLineList, {
color: 'red',
weight: 2,
opacity: 0.5,
smoothFactor: 1
});
var latlngVerticalTop = new L.latLng(north, center.lng);
var latlngVerticalBottom = new L.latLng(south, center.lng);
var vertLineList = [latlngVerticalTop, latlngVerticalBottom];
let vertLine = new L.Polyline(vertLineList, {
color: '#A5CE3A',
weight: 2,
opacity: 0.5,
smoothFactor: 1
});
horizLine.addTo(map);
vertLine.addTo(map);
} else {
var i;
for (i in map._layers) {
if (map._layers[i].options.color == '#A5CE3A') {
try {
map.removeLayer(map._layers[i]);
} catch (e) {
console.log("problem with " + e + map._layers[i]);
}
} else if (map._layers[i].options.color == 'red') {
try {
map.removeLayer(map._layers[i]);
} catch (e) {
console.log("problem with " + e + map._layers[i]);
}
}
}
}
}
Does anyone have any hints on how to get the behavior I'm hoping for? Thanks!
map.getBounds() only gives you the geographical bounds visible in the current map view.
So in short, whatever you see on the screen.
Set it to the actual center lat lng coordinates.
https://leafletjs.com/reference-1.6.0.html#map-getbounds
Thanks for the responses. I ended up saving the original location/zoom value, moving the image to a known location/zoom value (using the SetView method), then adding the cross hairs, and then moving the image back to the original location/zoom values. I did have to set the animation to false in the SetView calls...the timing of the animation threw things off.
Probably not the most elegant solution, but its something I remember having to do something similar when using Canvas elements.

Disable drag on Google Map Javascript custom controls

I want to create a Google map custom control using the Javascript API.
The control is an 'add waypoint' button. The user is supposed to be able to drag from the control, causing a marker to appear at the mouse pointer, and drop this marker on to the map.
The intended behavior is nearly identical to the existing pegman feature.
The problem is that the Google map controls seem to interact with drag, even when the drag has been explicitly disabled, as seen below.
In the example code, The first time I click and drag, it works as intended. The second time I click and drag, I get a 'no drag' icon and the control spawns a ghost of itself. The third time I drag, it's working again. On the next drag, there's a 'no drag'. The sequence continues, with odd drags working, and even drags failing.
Here's what I believe to be the relevant section:
<div id="map"></div>
<script>
var spawning = false;
var inProgress = false;
var waypointSpawner;
var targetLat;
var targetLng;
function initMap()
{
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 0.0000, lng: 0.0000},
zoom: 2
});
// Create the DIV to hold the control and call the CenterControl()
// constructor passing in this DIV.
var centerControlDiv = document.createElement('div');
var centerControl = new CenterControl(centerControlDiv, map);
centerControlDiv.index = 1;
map.controls[google.maps.ControlPosition.LEFT_TOP].push(centerControlDiv);
}
function CenterControl(controlDiv, map) {
// Set CSS for the control border.
var controlUI = document.createElement('div');
controlUI.style.backgroundColor = '#fff';
controlUI.style.border = '2px solid #fff';
controlUI.style.borderRadius = '3px';
controlUI.style.boxShadow = '0 2px 6px rgba(0,0,0,.3)';
controlUI.style.cursor = 'pointer';
controlUI.style.marginBottom = '22px';
controlUI.style.width = '40px';
controlUI.style.height = '50px';
controlUI.style.opacity = "0.7";
controlUI.style.backgroundImage = "url('create_waypoint_icon.png')";
controlUI.title = 'Add Waypoint';
controlUI.draggable = "false";
//controlDiv.draggable = "false";
controlDiv.appendChild(controlUI);
}
I was unable to get the above code to work in jsfiddle, but there are a couple of other examples that illustrate the problem.
http://jsfiddle.net/maunovaha/jptLfhc8/
Attempting to drag and drop the blue and green squares in the top left of the map results in some unintended behavior. Depending on your zoom level, and somewhat randomly, you will get a variety of different outcomes -
1 - Nothing happens. The pointer remains as a finger and moves normally.
2 - The finger pointer changes to a 'no drag' but otherwise moves normally.
3 - The finger pointer changes to a 'no drag' and a blue-and green semi-transparent 'to-paste' widget.
4 - The finger pointer changes to a 'no drag', and either the blue or green half of the widget (depending on your selection) goes with it.
This behavior is also somewhat evident in the Google control example code:
https://developers.google.com/maps/documentation/javascript/examples/control-custom
In this instance, when the text is highlighted, you get the 'no drag' icon. The parent control doesn't appear to be selectable, which is the desired goal.
I believe that the custom control is acquiring some kind of 'focus' status, and that clicking it again clears the focus. This behavior is evident in the green/blue example. Perhaps the control is being 'highlighted' somehow?
I attempted to implement the solutions given in How can I make a div unselectable? to no effect. I also tried a variety of ways to make the div undraggable in the code, but this did not appear to have any impact.
I also tried simulating mouse clicks on other parts of the program, and double clicking on the control, to change the focus/highlight status, but it appears the API doesn't actually carry out the clicks, only generates events from them. I couldn't find a way to cause a 'real' click. Manually clicking, then clicking and dragging worked.
I also tried making the control draggable but it still has the 'no drag' mouse pointer even when dragging it about.
If I understand correctly what you are saying, you want to be able to drag a marker onto the map, from outside, and place a point on that position.
I have the following solution which does that.
First we need to build the map:
function buildMap() {
var g = google.maps;
var mapOptions = {
center: new g.LatLng(52.052491, 9.84375),
zoom: 4,
mapTypeId: g.MapTypeId.ROADMAP,
streetViewControl: false,
panControl: false
};
map = new g.Map(document.getElementById("map"), mapOptions);
iw = new g.InfoWindow();
g.event.addListener(map, "click", function() {
if (iw) iw.close()
});
drag_area = document.getElementById("markers");
var b = drag_area.getElementsByTagName("div");
b[0].onmousedown = initDrag
dummy = new DummyOView()
}
We create a standard map and add features such as infoWindows to display the lat lng when the marker is added.
In addition we get where the marker is held and onMouseDown call a function (soon to come).
We use b[0] as we are getting the first set of <div> tags in the mark-up below, this is where the draggable icon is held:
<div id="markers">
<div id="m1" class="drag" style="left:0; background-image: url('https://maps.gstatic.com/mapfiles/ms/icons/ltblue-dot.png')">
</div>
</div>
The DummyOView is a map OverlayView which allows us to drag onto the map and grab the coords and position. More information on SO + credit to : More info
function DummyOView() {
this.setMap(map);
this.draw = function() {}
}
DummyOView.prototype = new google.maps.OverlayView();
The initDrag function is where most of the work is done, this is quite a lengthy function so I did comment the code, any questions on clarification just add a comment.
//function that allows us to drag the marker from the div to the map
function initDrag(e) {
//allows us to drag the marker and keep record of the clientX client Y coordinates
var j = function(e) {
var a = {};
if (!e) var e = window.event;
a.x = e.clientX;
a.y = e.clientY
return a
};
//function called whenever the mouse moves. this will keep track of the marker as we move around
var k = function(e) {
//check to ensure that the object is of class drag - otherwise we could drag everything
if (obj && obj.className == "drag") {
var i = j(e),
deltaX = i.x - l.x,
deltaY = i.y - l.y;
obj.style.left = (obj.x + deltaX) + "px";
obj.style.top = (obj.y + deltaY) + "px";
obj.onmouseup = function() {
//get the information to check to see if the dragObj is on the map on mouse up
var a = map.getDiv(),
mLeft = a.offsetLeft,
mTop = a.offsetTop,
mWidth = a.offsetWidth,
mHeight = a.offsetHeight;
var b = drag_area.offsetLeft,
areaTop = drag_area.offsetTop,
oWidth = obj.offsetWidth,
oHeight = obj.offsetHeight;
//check to see if obj is in bounds of map div X and Y
var x = obj.offsetLeft + b + oWidth / 2;
var y = obj.offsetTop + areaTop + oHeight / 2;
if (x > mLeft && x < (mLeft + mWidth) && y > mTop && y < (mTop + mHeight)) {
var c = 1;
var mapTemp = google.maps;
var point = new mapTemp.Point(x - mLeft - c, y - mTop + (oHeight / 2));
var proj = dummy.getProjection();
var latlng = proj.fromContainerPixelToLatLng(point);
var backImage = obj.style.backgroundImage.slice(4, -1).replace(/"/g, "");
createDraggedMarker(latlng, backImage);
fillMarker(backImage)
}
}
}
return false
};
//assign the event to a windows event
obj = e.target ? e.target : e.srcElement;
//if the object where the event took place is not called drag cancel the event
if (obj.className != "drag") {
if (e.cancelable) e.preventDefault();
obj = null;
return
} else {
z_index += 1;
obj.style.zIndex = z_index.toString();
obj.x = obj.offsetLeft;
obj.y = obj.offsetTop;
var l = j(e); //get the initial position of the marker relative to the client
document.onmousemove = k;
//if we lift the mouse up outside the map div set to null and leave where it is
document.onmouseup = function() {
document.onmousemove = null;
document.onmouseup = null;
if (obj) obj = null
}
}
return false
}
Summarised this function is called whenever the mouse has been clicked and dragged. It registed the starting position and the positions of the map div and checks when the onmouseup to see if the current mouse position is over the map div. If so we create a marker on the map and re-add the marker icon to the div to allow redragging.
//when the marker is dragged onto the map
//we call this function to create a marker on the map
function createDraggedMarker(position, iconImage) {
var mapLocal = google.maps;
var icon = {
url: iconImage,
size: new mapLocal.Size(32, 32),
anchor: new mapLocal.Point(15, 32)
};
var marker = new mapLocal.Marker({
position: position,
map: map,
clickable: true,
draggable: true,
crossOnDrag: false,
optimized: false,
icon: icon,
zIndex: highestOrder()
});
mapLocal.event.addListener(marker, "click", function() {
actual = marker;
var lat = actual.getPosition().lat();
var lng = actual.getPosition().lng();
var innerHtml = "<div class='infowindow'>" + lat.toFixed(6) + ", " + lng.toFixed(6) + "<\/div>";
iw.setContent(innerHtml);
iw.open(map, this)
});
mapLocal.event.addListener(marker, "dragstart", function() {
if (actual == marker) iw.close();
z_index += 1;
marker.setZIndex(highestOrder())
})
}
Re-adding the marker to the div
//Used to replace the marker
//once we have moved it from its div
function fillMarker(a) {
var div = document.createElement("div");
div.style.backgroundImage = "url(" + a + ")";
var padding;
if (obj.id == "m1") {
padding = "0px"
}
div.style.left = padding;
div.id = obj.id;
div.className = "drag";
div.onmousedown = initDrag;
drag_area.replaceChild(div, obj);
obj = null
}
JSfiddle you can use : https://jsfiddle.net/q3wjrpdw/7/
Any questions feel free to ask.

How to get FlashPro CC HTML5 Canvas exports to work with sound on the iPad/iPhone

I can't get FlashPro CC HTML5 Canvas exports to work with sound on the iPad/iPhone.
I reached out on Twitter and got this response:
"Timeline plays on click, but sound plays asynchronously on frame2. Fix this using "playEmptySound."
Here is the link I was given.
http://www.createjs.com/Docs/SoundJS/classes/WebAudioPlugin.html#method_playEmptySound
OK, now the problem, I am an animator at best, and know very little if any code… where do I insert this "playEmptySound" code?
I've posted the 2 files Flash kicks out, the HTML & the JS
Any help on this will be greatly appreciated.
This is the JS animation generated from Flash CC
(function (lib, img, cjs) {
var p; // shortcut to reference prototypes
// library properties:
lib.properties = {
width: 550,
height: 400,
fps: 15,
color: "#FFFFFF",
manifest: [
{src:"audio/moo.mp3", id:"moo"}
]
};
// symbols:
(lib.triangle = function() {
this.initialize();
// Layer 1
this.shape = new cjs.Shape();
this.shape.graphics.f("#6600FF").s().p("AolIlIIJxKIJBRKg");
this.shape.setTransform(55,55);
this.addChild(this.shape);
}).prototype = p = new cjs.Container();
p.nominalBounds = new cjs.Rectangle(0,0,110,110);
(lib.square_btn = function() {
this.initialize();
// Layer 1
this.shape = new cjs.Shape();
this.shape.graphics.f("#FF0000").s().p("AnkHlIAAvJIPJAAIAAPJg");
this.shape.setTransform(48.5,48.5);
this.addChild(this.shape);
}).prototype = p = new cjs.Container();
p.nominalBounds = new cjs.Rectangle(0,0,97,97);
(lib.blue_btn = function(mode,startPosition,loop) {
this.initialize(mode,startPosition,loop,{});
// timeline functions:
this.frame_2 = function() {
playSound("moo");
}
// actions tween:
this.timeline.addTween(cjs.Tween.get(this).wait(2).call(this.frame_2).wait(1));
// Layer 1
this.shape = new cjs.Shape();
this.shape.graphics.f().s("#009900").ss(1,1,1).p("AGQAAQAAClh2B1Qh1B2ilAAQikAAh2h2Qh1h1AAilQAAikB1h2QB2h1CkAAQClAAB1B1QB2B2AACkg");
this.shape.setTransform(40,40);
this.shape_1 = new cjs.Shape();
this.shape_1.graphics.f("#0066FD").s().p("AkaEaQh1h1AAilQAAikB1h2QB2h1CkAAQClAAB1B1QB2B2AACkQAAClh2B1Qh1B2ilAAQikAAh2h2g");
this.shape_1.setTransform(40,40);
this.timeline.addTween(cjs.Tween.get({}).to({state:[{t:this.shape_1},{t:this.shape}]}).to({state:[{t:this.shape_1},{t:this.shape}]},2).wait(1));
}).prototype = p = new cjs.MovieClip();
p.nominalBounds = new cjs.Rectangle(-1,-1,82,82);
(lib.background = function() {
this.initialize();
// Layer 1
this.shape = new cjs.Shape();
this.shape.graphics.f("#666666").s().p("EgsXAgMMAAAhAXMBYvAAAMAAABAXg");
this.shape.setTransform(284.1,206.1);
this.addChild(this.shape);
}).prototype = p = new cjs.Container();
p.nominalBounds = new cjs.Rectangle(0,0,568.2,412.1);
(lib.sound_mc = function(mode,startPosition,loop) {
this.initialize(mode,startPosition,loop,{});
// timeline functions:
this.frame_0 = function() {
/* Stop at This Frame
The timeline will stop/pause at the frame where you insert this code.
Can also be used to stop/pause the timeline of movieclips.
*/
this.stop();
/* Click to Go to Frame and Play
Clicking on the specified symbol instance moves the playhead to the specified frame in the timeline and continues playback from that frame.
Can be used on the main timeline or on movie clip timelines.
Instructions:
1. Replace the number 5 in the code below with the frame number you would like the playhead to move to when the symbol instance is clicked.
2.Frame numbers in EaselJS start at 0 instead of 1
*/
this.square_btn.addEventListener("click", fl_ClickToGoToAndPlayFromFrame_2.bind(this));
function fl_ClickToGoToAndPlayFromFrame_2()
{
this.gotoAndPlay(1);
}
}
this.frame_2 = function() {
playSound("moo");
}
// actions tween:
this.timeline.addTween(cjs.Tween.get(this).call(this.frame_0).wait(2).call(this.frame_2).wait(58));
// square
this.square_btn = new lib.square_btn();
this.square_btn.setTransform(48.5,48.5,1,1,0,0,0,48.5,48.5);
new cjs.ButtonHelper(this.square_btn, 0, 1, 1);
this.timeline.addTween(cjs.Tween.get(this.square_btn).to({y:210.5},33).wait(27));
}).prototype = p = new cjs.MovieClip();
p.nominalBounds = new cjs.Rectangle(0,0,97,97);
// stage content:
(lib.moo_button = function(mode,startPosition,loop) {
this.initialize(mode,startPosition,loop,{});
// timeline functions:
this.frame_0 = function() {
/* Stop at This Frame
The timeline will stop/pause at the frame where you insert this code.
Can also be used to stop/pause the timeline of movieclips.
*/
this.stop();
/* Click to Go to Frame and Play
Clicking on the specified symbol instance moves the playhead to the specified frame in the timeline and continues playback from that frame.
Can be used on the main timeline or on movie clip timelines.
Instructions:
1. Replace the number 5 in the code below with the frame number you would like the playhead to move to when the symbol instance is clicked.
2.Frame numbers in EaselJS start at 0 instead of 1
*/
this.blue_btn.addEventListener("click", fl_ClickToGoToAndPlayFromFrame.bind(this));
function fl_ClickToGoToAndPlayFromFrame()
{
this.gotoAndPlay(1);
}
}
// actions tween:
this.timeline.addTween(cjs.Tween.get(this).call(this.frame_0).wait(50));
// Layer 2
this.triangle = new lib.triangle();
this.triangle.setTransform(377,178,1,1,0,0,0,55,55);
this.timeline.addTween(cjs.Tween.get(this.triangle).wait(50));
// Layer 1
this.blue_btn = new lib.blue_btn();
this.blue_btn.setTransform(85,203,1,1,0,0,0,40,40);
new cjs.ButtonHelper(this.blue_btn, 0, 1, 2);
this.timeline.addTween(cjs.Tween.get(this.blue_btn).to({x:455},49).wait(1));
// Layer 4
this.sound_mc = new lib.sound_mc();
this.sound_mc.setTransform(220.6,84.5,1,1,0,0,0,48.5,48.5);
this.timeline.addTween(cjs.Tween.get(this.sound_mc).wait(50));
// Layer 3
this.instance = new lib.background("synched",0);
this.instance.setTransform(278.1,202.1,1,1,0,0,0,284.1,206.1);
this.timeline.addTween(cjs.Tween.get(this.instance).wait(50));
}).prototype = p = new cjs.MovieClip();
p.nominalBounds = new cjs.Rectangle(269,196,568.2,412.1);
})(lib = lib||{}, images = images||{}, createjs = createjs||{});
var lib, images, createjs;
This is the HTML generated from Flash CC
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>moo_button-tringle2</title>
<script src="script/easeljs-0.7.1.min.js"></script>
<script src="script/tweenjs-0.5.1.min.js"></script>
<script src="script/movieclip-0.7.1.min.js"></script>
<script src="script/preloadjs-0.4.1.min.js"></script>
<script src="script/soundjs-0.5.2.min.js"></script>
<script src="moo_button-tringle2.js"></script>
<script>
var canvas, stage, exportRoot;
function init() {
canvas = document.getElementById("canvas");
var loader = new createjs.LoadQueue(false);
loader.installPlugin(createjs.Sound);
loader.addEventListener("complete", handleComplete);
loader.loadManifest(lib.properties.manifest);
}
function handleComplete() {
exportRoot = new lib.moo_button();
stage = new createjs.Stage(canvas);
stage.addChild(exportRoot);
stage.update();
stage.enableMouseOver();
createjs.Ticker.setFPS(lib.properties.fps);
createjs.Ticker.addEventListener("tick", stage);
}
function playSound(id, loop) {
createjs.Sound.play(id, createjs.Sound.INTERRUPT_EARLY, 0, 0, loop);
}
</script>
</head>
<body onload="init();" style="background-color:#D4D4D4">
<canvas id="canvas" width="550" height="400" style="background-color:#FFFFFF"></canvas>
</body>
</html>
OJay's answer is what I would have initially tried. The only other thing I would try instead is, inside of your function handleComplete() something like:
function handleComplete() {
exportRoot = new lib.moo_button();
stage = new createjs.Stage(canvas);
stage.addChild(exportRoot);
stage.update();
stage.enableMouseOver();
createjs.Ticker.setFPS(lib.properties.fps);
createjs.Ticker.addEventListener("tick", stage);
var listener = function() {
createjs.WebAudioPlugin.playEmptySound();
window.removeEventListener('touchstart', listener);
};
window.addEventListener('touchstart', listener);
}
¯\_(ツ)_/¯
you'll want to insert it in lib.moo_button function fl_ClickToGoToAndPlayFromFrame. It should look like this:
function fl_ClickToGoToAndPlayFromFrame()
{
if(createjs.WebAudioPlugin.context != null) {
createjs.WebAudioPlugin.playEmptySound();
}
this.gotoAndPlay(1);
}
You may need to apply it to all your buttons if you are not sure which one will be pressed first, but the downside is that the code will run on every button press. Coding in Flash is not the best solution for this kind of problem, but can get the job done.
Hope that helps.

Creating an javascript graph with marker that is synchronize with a movie

I'm trying to create an online web tool for eeg signal analysis. The tool suppose to display a graph of an eeg signal synchronize with a movie that was display to a subject.
I've already implemented it successfully on csharp but I can't find a way to do it easily with any of the know javascript chart that I saw.
A link of a good tool that do something similar can be found here:
http://www.mesta-automation.com/real-time-line-charts-with-wpf-and-dynamic-data-display/
I've tried using dygraph, and google chart. I know that it should be relatively easy to create an background thread on the server that examine the movie state every ~50ms. What I was not able to do is to create a marker of the movie position on the chart itself dynamically. I was able to draw on the dygraph but was not able to change the marker location.
just for clarification, I need to draw a vertical line as a marker.
I'm in great suffering. Please help :)
Thanks to Danvk I figure out how to do it.
Below is a jsfiddler links that demonstrate such a solution.
http://jsfiddle.net/ng9vy8mb/10/embedded/result/
below is the javascript code that do the task. It changes the location of the marker in synchronizing with the video.
There are still several improvement that can be done.
Currently, if the user had zoomed in the graph and then click on it, the zoom will be reset.
there is no support for you tube movies
I hope that soon I can post a more complete solution that will also enable user to upload the graph data and video from their computer
;
var dc;
var g;
var v;
var my_graph;
var my_area;
var current_time = 0;
//when the document is done loading, intialie the video events listeners
$(document).ready(function () {
v = document.getElementsByTagName('video')[0];
v.onseeking = function () {
current_time = v.currentTime * 1000;
draw_marker();
};
v.oncanplay = function () {
CreateGraph();
};
v.addEventListener('timeupdate', function (event) {
var t = document.getElementById('time');
t.innerHTML = v.currentTime;
g.updateOptions({
isZoomedIgnoreProgrammaticZoom: true
});
current_time = v.currentTime * 1000;
}, false);
});
function change_movie_position(e, x, points) {
v.currentTime = x / 1000;
}
function draw_marker() {
dc.fillStyle = "rgba(255, 0, 0, 0.5)";
var left = my_graph.toDomCoords(current_time, 0)[0] - 2;
var right = my_graph.toDomCoords(current_time + 2, 0)[0] + 2;
dc.fillRect(left, my_area.y, right - left, my_area.h);
};
//data creation
function CreateGraph() {
number_of_samples = v.duration * 1000;
// A basic sinusoidal data series.
var data = [];
for (var i = 0; i < number_of_samples; i++) {
var base = 10 * Math.sin(i / 90.0);
data.push([i, base, base + Math.sin(i / 2.0)]);
}
// Shift one portion out of line.
var highlight_start = 450;
var highlight_end = 500;
for (var i = highlight_start; i <= highlight_end; i++) {
data[i][2] += 5.0;
}
g = new Dygraph(
document.getElementById("div_g"),
data, {
labels: ['X', 'Est.', 'Actual'],
animatedZooms: true,
underlayCallback: function (canvas, area, g) {
dc = canvas;
my_area = area;
my_graph = g;
bottom_left = g.toDomCoords(0, 0);
top_right = g.toDomCoords(highlight_end, +20);
draw_marker();
}
});
g.updateOptions({
clickCallback: change_movie_position
}, true);
}

Show a moving marker on the map

I am trying to make a marker move(not disappear and appear again) on the map as a vehicle moves on the road.
I have two values of latLng and I want to move the marker between the two till the next point is sent by the vehicle. And then repeat the process again.
What I tried:[This is not a very efficient way, I know]
My thought was to implement the above using the technique in points below:
1) Draw a line between the two.
2) Get the latLng of each point on 1/10th fraction of the polyline.
3) Mark the 10 points on the map along with the polyline.
Here is my Code:
var isOpen = false;
var deviceID;
var accountID;
var displayNameOfVehicle;
var maps = {};
var lt_markers = {};
var lt_polyLine = {};
function drawMap(jsonData, mapObj, device, deleteMarker) {
var oldposition = null;
var oldimage = null;
var arrayOflatLng = [];
var lat = jsonData[0].latitude;
var lng = jsonData[0].longitude;
//alert(jsonData[0].imagePath);
var myLatLng = new google.maps.LatLng(lat, lng);
if (deleteMarker == true) {
if (lt_markers["marker" + device] != null) {
oldimage = lt_markers["marker" + device].getIcon().url;
oldposition = lt_markers["marker" + device].getPosition();
lt_markers["marker" + device].setMap(null);
lt_markers["marker" + device] = null;
}
else {
console.log('marker is null');
oldimage = new google.maps.MarkerImage(jsonData[0].imagePath,
null,
null,
new google.maps.Point(5, 17), //(15,27),
new google.maps.Size(30, 30));
oldposition = myLatLng;
}
}
var image = new google.maps.MarkerImage(jsonData[0].imagePath,
null,
null,
new google.maps.Point(5, 17), //(15,27),
new google.maps.Size(30, 30));
lt_markers["marker" + device] = new google.maps.Marker({
position: myLatLng,
icon: image,
title: jsonData[0].address
});
if (oldposition == myLatLng) {
alert('it is same');
lt_markers["marker" + device].setMap(mapObj);
mapObj.panTo(myLatLng);
}
else {
alert('it is not same');
var markMarker = null;
var i = 10;
for (i = 10; i <= 100; i + 10) {
//-------
// setTimeout(function() {
if (markMarker != null) {
markMarker.setMap(null);
markMarker = null;
}
alert('inside the loop');
var intermediatelatlng = mercatorInterpolate(mapObj, oldposition, myLatLng, i / 100);
alert('Intermediate Latlng is :' + intermediatelatlng);
arrayOflatLng.push(intermediatelatlng);
var flightPath = new google.maps.Polyline({
path: arrayOflatLng,
strokeColor: "#FFFFFF",
strokeOpacity: 1.0,
strokeWeight: 1
});
flightPath.setMap(mapObj);
if (i != 100) {
markMarker = new google.maps.Marker({
position: intermediatelatlng,
icon: image,
title: jsonData[0].address,
map: mapObj
});
}
else {
markMarker = new google.maps.Marker({
position: intermediatelatlng,
icon: oldimage,
title: jsonData[0].address,
map: mapObj
});
}
mapObj.panTo(intermediatelatlng);
//--------
// }, 1000);
}
}
}
function mercatorInterpolate(map, latLngFrom, latLngTo, fraction) {
// Get projected points
var projection = map.getProjection();
var pointFrom = projection.fromLatLngToPoint(latLngFrom);
var pointTo = projection.fromLatLngToPoint(latLngTo);
// Adjust for lines that cross the 180 meridian
if (Math.abs(pointTo.x - pointFrom.x) > 128) {
if (pointTo.x > pointFrom.x)
pointTo.x -= 256;
else
pointTo.x += 256;
}
// Calculate point between
var x = pointFrom.x + (pointTo.x - pointFrom.x) * fraction;
var y = pointFrom.y + (pointTo.y - pointFrom.y) * fraction;
var pointBetween = new google.maps.Point(x, y);
// Project back to lat/lng
var latLngBetween = projection.fromPointToLatLng(pointBetween);
return latLngBetween;
}
Problems Faced:
1) The marker is not showing up on the map because the process of plotting and removal of marker is so fast that the marker is not visisble on screen. I've tried setTimeOut, and It does not help at all.
2) if I alow the browser to run this code for more than 5 minutes, the browser crashes.
Note: The Above function is called every 10 seconds using setInterval.
What Can be a better solution? Please Help..
For the marker to move relatively smoothly, you need to
Update more than every 1/10 fraction of the polyline (at least every few pixels)
Call the update method more frequently
Don't delete and re-add the marker
For example, something like:
var counter = 0;
interval = window.setInterval(function() {
counter++;
// just pretend you were doing a real calculation of
// new position along the complex path
var pos = new google.maps.LatLng(35, -110 + counter / 100);
marker.setPosition(pos);
if (counter >= 1000) {
window.clearInterval(interval);
}
}, 10);
I made a simple example at http://jsfiddle.net/bmSbU/2/ which shows a marker moving along a straight path. If this is what you want, most of your code above regarding where along the line you are can be reused (or check out http://broady.github.io/maps-examples/points-along-line/along-directions.html )
You can use marker-animate-unobtrusive library to make markers
smoothly transition from one location to another (instead of reappearing).
You could initialize your marker like that:
var marker = new SlidingMarker({
//your original marker options
});
Just call marker.setPosition() each time new vehicle's coordinate arrive.
P.S. I'm the author of the library.
Why not keep the existing Marker/ MarkerImage and call setPosition() to move it, either on a timer or as the position changes?
Deleting it & recreating it is what causes it to flash/ flicker and eventually crash. If you keep the same instance but just move it, you should do much better.
See: Marker.setPosition()
https://developers.google.com/maps/documentation/javascript/reference#Marker

Categories

Resources