Mapbox sidepanel and polygon interaction - javascript

I am attempting to make an interaction between images in a sidepanel and polygons on a map, so when the sidepanel is moved via mousescroll, the corresponding polygon with same name is brought into focus.
My current attempt is not responsive to mousescrolls as needed. Is there another approach than the one I have taken?
$('.sidebar').bind('mousewheel', function(e){
$("#help").html(' ');
var winTop = $(this).scrollTop();
var $imgs = $('.sidebar').find('img');
var $midElement;
var distance = null;
var currDistance = 0;
var minHeight = $(window).scrollTop();
var maxHeight = $(window).height();
var img_h=$('.sidebar').find('img');
var img_h1=img_h.height() / 2;
var middleHeightA = (maxHeight + minHeight) / 2;
var middleHeight = middleHeightA - img_h1;
$.each($imgs, function() {
currDistance = Math.abs(middleHeight - $(this).position().top);
if ( distance == null || currDistance < distance ) {
/*$midElement = $(element);*/
distance = currDistance;
for (j=0;j<polygons1.length;j++) {
polygons1[j].setStyle({color: '#fff',fillColor:'#000', weight:'1px'});
}
var scrid=$(this).attr('id');
for (j=0;j<help.length;j++) {
id=help[j];
if(id==scrid)
{
polygons1[j].openPopup(polygons1[j].getBounds().getCenter());
map.setView(polygons1[j].getBounds().getCenter(),10);
polygons1[j].setStyle({color: '#e72f2a',fillColor:'#e72f2a',weight:'7px'});
$('.thumbnail').removeClass('active');
$('.'+scrid).addClass('active');
}
}
}
var scrid=$(this).attr('id');
for (j=0;j<help.length;j++) {
id=help[j];
if(id==scrid)
{
polygons1[j].openPopup(polygons1[j].getBounds().getCenter());
map.setView(polygons1[j].getBounds().getCenter(),10);
polygons1[j].setStyle({color: '#e72f2a',fillColor:'#e72f2a',weight:'7px'});
}
}
}*/

I would recommend you to use a debounce function. Debounce function limits the rate at which a function can fire. The idea is to make polygons focus not every time a mouse-wheel event is triggered, but focus them with a kind of cooldown.
Debounce functions are already implemented in many libraries, for example in lodash. All you have to do is to wrap your mousewheel callback in it. Something like:
$('.sidebar').bind('mousewheel', _.debounce(function(e){
$("#help").html(' ');
...
), 100});
Pay attention to options param, in lodash implementation, most probably you would like to use one of them, for example maxWait.

Related

How to dynamically shift a DIV down based on predecessor

I've got a series of DIVs, all with the same class (.ms-acal-item). What I'm trying to do is get the position of each one, compare it to the one above it, and shift it down if needed. This is to correct an issue on a SharePoint 2013 calendar where event tiles are overlapping. Here's my code so far:
$(function() {
$('.ms-acal-item').each(function(i, obj) {
var tile = jQuery(this);
var prev = tile.prev();
var prevPos = prev.position();
var tilePOs = tile.position();
var curTop = parseInt(tilePos.top);
var newTop = parseInt(prevPos.top) + 30;
if(curtop !== newTop){
tile.css('top', newTop);
}
});
});
And here's an example of what the SharePoint-generated content looks like:
Each tile is 20px high and positioned absolutely in-line. What I need to do is compare the position of each tile to its predecessor and then move it down 30px if it isn't already there (20px for the tile and 10px between them). So far it's not working - my code seems to have no effect on the tile positions.
What am I doing wrong?
There is a problem in the logic, while processing the first element we do not have any previous element, so we need to ignore it and few typo(variable case issues) mistakes in your code. Below is the revamp code.(To see the changes effect i changed style from top to margin-left, correct it afterwards)
$(function() {
$('.ms-acal-item').each(function(i, obj) {
var tile = $(this);
var prev = tile.prev();
if (typeof prev.position() !== "undefined") {
var prevPos = JSON.parse(JSON.stringify(prev.position()));
var tilePos = JSON.parse(JSON.stringify(tile.position()));
var curTop = parseInt(tilePos.top);
var newTop = parseInt(prevPos.top) + 30;
if(curTop !== newTop){
tile.css('margin-left', newTop);
}
}
});
});

Applying function to a div by class

I thought I was doing this right but its not working. I think I'm being stupid...
function expand(){
var wide = $(this).css('width');
var high = $(this).css('height');
var newwide = wide * 10;
var newhigh = high * 10;
$(this).animate({'width':newwide,'height':newhigh}, 2000);
}
$('.object1').expand();
I just want to run this 'expand' function on the div with the class 'object1', what am I doing wrong?
Thanks
In jQuery, to add a custom function, you do it like this:
(function($){
$.fn.myFunction = function() {
//Custom Function
}
})(jQuery);
So, your code should look like this:
(function($){
$.fn.expand = function() {
var wide = $(this).css('width');
var high = $(this).css('height');
var newwide = wide * 10;
var newhigh = high * 10;
$(this).animate({'width':newwide,'height':newhigh}, 2000);
}
})(jQuery);
Learn More
Try to rewrite your code like this,
function expand($this){
var wide = $this.css('width');
var high = $this.css('height');
var newwide = wide * 10;
var newhigh = high * 10;
$this.animate({'width':newwide,'height':newhigh}, 2000);
}
expand($('.object1'));
How should the $ object know it has a expand() method now?
If you really want a jQuery plugin here (that's what they call it when you attach something to the jQuery object), you have to attach it to $.fn:
$.fn.expand = expand // as you defined it earlier
You almost surely don't want this. What creates what you were trying to achieve is giving the $('.object1') as a parameter to expand():
function expand($element){
var wide = $element.css('width');
var high = $element.css('height');
var newwide = wide * 10;
var newhigh = high * 10;
$element.animate({'width':newwide,'height':newhigh}, 2000);
}
expand($('.object1'));

SVG Camera Pan - Translate keeps resetting to 0 evertime?

Well i have this SVG canvas element, i've got to the point so far that once a user clicks and drags the canvas is moved about and off-screen elements become on screen etc....
However i have this is issue in which when ever the user then goes and click and drags again then the translate co-ords reset to 0, which makes the canvas jump back to 0,0.
Here is the code that i've Got for those of you whio don't wanna use JS fiddle
Here is the JSfiddle demo - https://jsfiddle.net/2cu2jvbp/2/
edit: Got the solution - here is a JSfiddle DEMO https://jsfiddle.net/hsqnzh5w/
Any and all sugesstion will really help.
var states = '', stateOrigin;
var root = document.getElementById("svgCanvas");
var viewport = root.getElementById("viewport");
var storeCo =[];
function setAttributes(element, attribute)
{
for(var n in attribute) //rool through all attributes that have been created.
{
element.setAttributeNS(null, n, attribute[n]);
}
}
function setupEventHandlers() //self explanatory;
{
setAttributes(root, {
"onmousedown": "mouseDown(evt)", //do function
"onmouseup": "mouseUp(evt)",
"onmousemove": "mouseMove(evt)",
});
}
setupEventHandlers();
function setTranslate(element, x,y,scale) {
var m = "translate(" + x + "," + y+")"+ "scale"+"("+scale+")";
element.setAttribute("transform", m);
}
function getMousePoint(evt) { //this creates an SVG point object with the co-ords of where the mouse has been clicked.
var points = root.createSVGPoint();
points.x = evt.clientX;
points.Y = evt.clientY;
return points;
}
function mouseDown(evt)
{
var value;
if(evt.target == root || viewport)
{
states = "pan";
stateOrigin = getMousePoint(evt);
console.log(value);
}
}
function mouseMove(evt)
{
var pointsLive = getMousePoint(evt);
if(states == "pan")
{
setTranslate(viewport,pointsLive.x - stateOrigin.x, pointsLive.Y - stateOrigin.Y, 1.0); //is this re-intializing every turn?
storeCo[0] = pointsLive.x - stateOrigin.x
storeCo[1] = pointsLive.Y - stateOrigin.Y;
}
else if(states == "store")
{
setTranslate(viewport,storeCo[0],storeCo[1],1); // store the co-ords!!!
stateOrigin = pointsLive; //replaces the old stateOrigin with the new state
states = "stop";
}
}
function mouseUp(evt)
{
if(states == "pan")
{
states = "store";
if(states == "stop")
{
states ='';
}
}
}
In your mousedown function, you are not accounting for the fact that the element might already have a transform and you are just overwriting it.
You are going to need to either look for, and parse, any existing transform. Or an easier approach would be to keep a record of the old x and y offsets and when a new mousedown happens add them to the new offset.

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);
}

webGL story sphere popups

I am trying to adapt the really cool looking WebGL Story Sphere, source code and css here. There's one big problem: once you click on a news article, the text of the article in the popup is always the same. I want to modify the code so that when you click on an article, the right text appears in the popup.
I'm working from a set of article texts that I specify in the code, e.g. var captions = ["good","better","best"]. Though the article titles and images populate correctly in the popup, I can't get the text to do so. Can you help me?? Here's what I've got:
// function code
var passvar = null; // failed attempt to store texts for later
function initialize() {
math = tdl.math;
fast = tdl.fast;
canvas = document.getElementById("canvas");
g_fpsTimer = new tdl.fps.FPSTimer();
hack();
canvas.addEventListener("mousedown", handleMouseDown, false);
canvas.addEventListener("mousemove", handleMouseMove, false);
canvas.addEventListener("mouseup", handleMouseUp, false);
// Create a canvas 2d for making textures with text.
g_canvas2d = document.createElement('canvas');
window.two2w = window.two2h = g_tilesize;
g_canvas2d.width = two2w;
g_canvas2d.height = two2h;
g_ctx2d = g_canvas2d.getContext("2d");
window.gl = wu.create3DContext(canvas);
if (g_debug) {
gl = wd.makeDebugContext(gl, undefined, LogGLCall);
}
//gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, gl.TRUE);
// Here is where I specify article titles, images, captions
// Titles and images populate the popup correctly, captions don't...
var titles = ["a","b","c"];
var captions = ["good","better","best"];
var images = ['imagesphere/assets/1.jpg',
'imagesphere/assets/bp/2.png',
'imagesphere/assets/bp/3.png'
];
var headlines = titles.concat( titles);
var blurbs = captions.concat( captions);
var tmpImages = [];
var tmpHeadlines = [];
var tmpCaptions = [];
// make a bunch of textures.
for (var ii = 0; ii < g_imagesDownGrid; ++ii) {
var textures = [];
for (var jj = 0; jj < g_imagesAcrossGrid; ++jj) {
var imgTexture = new ImgTexture();
textures.push(imgTexture);
if (tmpImages.length == 0) {
tmpImages = images.slice();
}
if (tmpHeadlines.length == 0) {
tmpHeadlines = headlines.slice();
}
if (tmpCaptions.length == 0) {
tmpCaptions = blurbs.slice();
}
var rando = math.randomInt(tmpImages.length);
var img = tmpImages.splice(rando, 1)[0];
var headline = tmpHeadlines.splice(rando, 1)[0];
var caption = tmpCaptions.splice(rando, 1)[0];
passvar = caption;
if (img.indexOf('videoplay.jpg') > -1){
window.vidtexture = imgTexture;
images = images.slice(1); // dont use that thumb again.
headlines = 'WebGL Brings Video To the Party as Well'
}
imgTexture.load(img, /* "[" + jj + "/" + ii + "]" + */ headline);
}
g_textures.push(textures);
}
// And here's where I try to put this in a popup, finally
// But passvar, the stored article text, never refreshes!!!
<div id="story" class="prettybox" style="display:none">
<img class="close" src="imagesphere/assets/close.png">
<div id="storyinner">
<input id = "mytext">
<script>document.getElementById("mytext").value = passvar;</script>
</div>
</div>
And here is my click handler code:
function sphereClick(e){
window.console && console.log('click!', e, e.timeStamp);
var selected = g_textures[sel.y][sel.x];
window.selected = selected;
animateGL('eyeRadius', glProp('eyeRadius'), 4, 500);
var wwidth = $(window).width(),
wheight = $(window).height(),
story = $('#story').width( ~~(wwidth / 7 * 4) ).height( ~~(wheight / 6 * 5) ),
width = story.width(),
height = story.height(),
miniwidth = 30;
story.detach()
.find('#storyinner').find('h3,img,caption').remove().end().end()
.show();
story.css({
left : e.pageX,
top : e.pageY,
marginLeft : - width / 2,
marginTop : - height / 2
}).appendTo($body); // we remove and put back on the DOM to reset it to the correct position.
$('style.anim.story').remove();
$('<style class="anim story">')
.text( '.storyopen #story { left : ' + (wwidth / 3 * 2) + 'px !important; top : ' + wheight / 2 + 'px !important; }' )
.appendTo($body);
$(selected.img).prependTo('#storyinner').parent();
$('<h3>').text(selected.msg.replace(/\(.*/,'')).prependTo('#storyinner');
$body.addClass('storyopen');
} // eo sphereClick()
There's a lot wrong here, but here's a start. It won't solve your problem, but it will help you avoid issues like this.
var passvar = null; is a global variable.
Your loop for (var ii = 0; ... sets that global variable to a new value on every iteration.
Later, you click something and the global variable passvar is never changed.
If you want to use this pattern, you need to set passvar from your click handler so it has the value that was clicked. Since you didn't actually post your click handlers, it's hard to advise more.
But this is also a bad pattern, functions take arguments for a good reason. Since you have to find your clicked item in the click handler anyway, why not pass it directly which does involve a shared global variable at all?
var handleMouseUp = function(event) {
var story = findClickedThing(event);
if (obj) {
showPopup(story.texture, story.caption);
}
}
Which brings me to this:
var titles = ["a","b","c"];
var captions = ["good","better","best"];
var images = ['imagesphere/assets/1.jpg',
'imagesphere/assets/bp/2.png',
'imagesphere/assets/bp/3.png'
];
When you have 3 arrays, all of the same length, each array describing a different property of an object, you are doing it wrong. What you want, is one array of objects instead.
var stories = [
{
title: "a",
caption: "good",
image: "imagesphere/assets/1.jpg"
}, {
title: "b",
caption: "better",
image: "imagesphere/assets/bp/2.jpg"
}, {
title: "c",
caption: "best",
image: "imagesphere/assets/bp/3.jpg"
},
];
console.log(stories[1].caption); // "better"
Now once you find the clicked object, you can just ask it what it's caption is. And you can pass the whole object to the popup maker. And no field is handled differently or passed around in a different manner, because you are not passing around the fields. You are passsing the entire object.

Categories

Resources