358 lines
10 KiB
JavaScript
358 lines
10 KiB
JavaScript
|
|
|
|
Backbone.sync = function(method, model, success, error){
|
|
success();
|
|
}
|
|
|
|
//add a function to underscore to get index with a truth function
|
|
_.mixin({
|
|
indexOfElement : function(array,filter){
|
|
return array.reduce(function(a,e,i){
|
|
if ((a<0) && filter(e)) return i;
|
|
return a;
|
|
},-1);
|
|
}
|
|
});
|
|
|
|
|
|
function DataSetPoint(latitude, longitude, time, name, speed, altitude, address, iconName, hasVoice, hasText, isInCall ){
|
|
this.id = name;
|
|
this.latitude = latitude;
|
|
this.longitude = longitude;
|
|
this.time = time;
|
|
this.name = name;
|
|
this.speed = speed;
|
|
this.altitude = altitude;
|
|
this.address = address;
|
|
this.icon = iconName;
|
|
this.hasVoice = hasVoice;
|
|
this.hasText = hasText;
|
|
this.isInCall = isInCall;
|
|
|
|
DataSetPoint.prototype.merge = function(map){
|
|
_.extend(this,map);
|
|
return this;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
var MapProperties = Backbone.Model.extend({
|
|
defaults:{
|
|
dimmensions: [300,300],
|
|
isReset:false,
|
|
mapType : 'terrain',
|
|
openedMarker:'',
|
|
center : [44.423361, 26.093608],
|
|
zoom : 20,
|
|
console: false,
|
|
traffic:false,
|
|
polygonToGet : {name : ''}, //this is an object so you can repeatedly ask for the same polygon name
|
|
//the following are not used yet
|
|
polyPointCallback : function(point){},
|
|
getPolygonCallback : function(points){}
|
|
}
|
|
});
|
|
|
|
var DataSet = Backbone.Model.extend({
|
|
defaults:{
|
|
id:null,
|
|
points:[],
|
|
isVisible:false,
|
|
isAutosize:true,
|
|
lastUpdated:new Date(),
|
|
isShowLabels : true
|
|
},
|
|
initialize: function(){
|
|
console.log('initializing dataset '+this.get('id'));
|
|
},
|
|
|
|
updatePoints : function(newPoints){
|
|
var self = this;
|
|
newPoints.forEach(function(p){
|
|
var index = _(self.get('points')).indexOfElement(function(elem){
|
|
return (elem.id == p.id);
|
|
});
|
|
if (index >= 0) self.get("points").splice(index,1);
|
|
p.dataset = self.get('id');
|
|
self.get("points").push(p);
|
|
// console.dir(p);
|
|
});
|
|
this.set("lastUpdated", new Date());
|
|
// console.log('updated points on dataset:'+this.get("id") + ". There are " + this.get('points').length + " points.");
|
|
},
|
|
|
|
removePoint : function(pointName){
|
|
var point = _(this.get('points')).findWhere({name:pointName});
|
|
var pointIndex = this.get('points')
|
|
.reduce(function(a,e,i){
|
|
if (!a && e.id === pointName) return i;
|
|
return a},null);
|
|
|
|
this.get('points').splice(pointIndex,1);
|
|
// console.log('Removed id = '+pointName+' from index = '+pointIndex);
|
|
// console.dir(this.get('points'));
|
|
this.set("lastUpdated", new Date());
|
|
}
|
|
|
|
});
|
|
|
|
var Polyline = DataSet.extend({
|
|
defaults : {
|
|
color: "blue",
|
|
thickness : 0.4,
|
|
isPolyline : true
|
|
}
|
|
});
|
|
|
|
|
|
|
|
var Polygon = DataSet.extend({
|
|
defaults : {
|
|
isNew: false,
|
|
isEditing : false,
|
|
isPolyline : false
|
|
},
|
|
|
|
initialize : function(){
|
|
this.set('isPolyline',false);
|
|
}
|
|
});
|
|
|
|
|
|
var PolygonCollection = Backbone.Collection.extend({
|
|
model : Polygon
|
|
});
|
|
|
|
var DataSetCollection = Backbone.Collection.extend({
|
|
model:DataSet
|
|
});
|
|
|
|
|
|
|
|
|
|
/**************************************************************/
|
|
/* I n f o W i n d o w V I E W a n d M O D E L */
|
|
/**************************************************************/
|
|
|
|
|
|
var InfoWindowModel = Backbone.Model.extend({
|
|
defaults : {
|
|
id:"info point",
|
|
latitude : 23.4332,
|
|
longitude : -32.234,
|
|
time : new Date(),
|
|
name : 'abcs',
|
|
speed : '23kph',
|
|
altitude : '3 m',
|
|
address : 'bld. Marasesti, Bucuresti, sector 4',
|
|
hasStreetView : false,
|
|
hasVoice : 0,
|
|
hasText : 0,
|
|
isInCall : false
|
|
|
|
},
|
|
mergePoint : function(dataSetPoint){
|
|
console.log("InfoWindowModel: Merge point "+dataSetPoint.id+" with incall="+dataSetPoint.isInCall);
|
|
Object.keys(dataSetPoint).forEach(function(p){
|
|
this.set(p,dataSetPoint[p]);
|
|
}, this);
|
|
}
|
|
});
|
|
|
|
|
|
|
|
var InfoWindowView = Backbone.View.extend({
|
|
// el : '#info',
|
|
|
|
elId : '#info',
|
|
|
|
// template : _.template($('#info').html()), //no params at template
|
|
|
|
events : {
|
|
"mousedown .name img" : "computePttState",
|
|
"mouseup .name img" : "computePttState",
|
|
"dragend .name img" : "computePttState",
|
|
"keypress input" : "onKeyPress"
|
|
},
|
|
|
|
|
|
pttState : 'neutral',
|
|
|
|
//see the diagram in docs/PTT_states.png
|
|
setPttState : function(state){
|
|
if (state == 'ask-ptt') this.ptt(true);
|
|
if (state == 'call-done') this.ptt(false);
|
|
var states = {
|
|
'neutral' : "r_ptt.png", //blue
|
|
'ask-ptt' : "r_ptt_over.png", //green
|
|
'in-call' : "r_ptt_over.png", //green, + dynamic
|
|
'call-failed': "r_ptt_end.png", //red
|
|
'call-done' : "r_ptt_hang.png", //yellow
|
|
'called' : "r_ptt_incoming.png" //gray +dynamic
|
|
}
|
|
var imgState = states[state];
|
|
this.$el.find(".name img[alt='PTT']").attr('src','radio/'+imgState);
|
|
|
|
this.animatePTT((['in-call','called'].indexOf(state)>-1));
|
|
|
|
this.pttState = state;
|
|
// console.log("Set PTT state to:"+state);
|
|
},
|
|
|
|
ptt : function(isOn){
|
|
// if (!isOn) this.model.attributes.isInCall = false;
|
|
var state = isOn?"on":"off";
|
|
this.options.fastCommandCallback && this.options.fastCommandCallback('ptt', this.model.get('id'),state);
|
|
},
|
|
|
|
onKeyPress : function(event) {
|
|
if (event.keyCode === 13) {
|
|
this.options.fastCommandCallback && this.options.fastCommandCallback('text',this.model.get('id'),event.target.value);
|
|
event.target.value = '';
|
|
return false;
|
|
}else
|
|
if (this.$el.find('form input').val().length >= this.model.get('hasText') &&
|
|
!(event.keyCode in [46, 8, 39, 37])) //delete, backspace, left and right arrows
|
|
return false;
|
|
|
|
},
|
|
|
|
isOpened : function(){return this.$el.is(":visible");},
|
|
|
|
initialize : function(options){
|
|
|
|
// this.$el.html(this.template());
|
|
this.$el.html($(this.elId).html());
|
|
this.$el.addClass('info');
|
|
this.options = options;
|
|
this.model.isOpened = this.isOpened.bind(this);
|
|
this.model.on("change", this.update, this);
|
|
// this.update();
|
|
this.$el.hide();
|
|
//reset PTT state if InfoWindow is closing
|
|
//TODO: clear it when state is neutral
|
|
var self = this;
|
|
setInterval(function(){
|
|
if (!self.isOpened()) self.setPttState('neutral');
|
|
},1000);
|
|
|
|
|
|
},
|
|
|
|
animatePTT : function(start){
|
|
var element = this.$el.find(".name .ptt-anim");
|
|
if (start){
|
|
this.animatePTT.interval && clearInterval(this.animatePTT.interval);
|
|
this.animatePTT.interval = setInterval(function(){
|
|
var pos = /_(\d{2})/.exec(element.attr('src'))[1];
|
|
pos = parseInt(pos);
|
|
pos = pos>12?1:pos+1;
|
|
var nextId = (pos>9?"":"0")+pos;
|
|
element.attr('src','radio/white_r_radial_spectrum_'+nextId+'.png');
|
|
},200);
|
|
}else{
|
|
this.animatePTT.interval && clearInterval(this.animatePTT.interval);
|
|
element.attr('src','radio/r_radial_spectrum_00.png');
|
|
}
|
|
|
|
},
|
|
|
|
update : function(){
|
|
var changedAttrs = Object.keys(this.model.changedAttributes());
|
|
var changedProp = changedAttrs.length && changedAttrs[0];
|
|
// console.log("---------------------Prop that changed = " + changedProp)
|
|
this.$el.show();
|
|
var p = this.model;
|
|
var latlng = "["+p.get('latitude')+","+p.get('longitude')+"]";
|
|
|
|
this.$el.find("#name").text(p.get('id').toUpperCase());
|
|
this.$el.find(".position").text(latlng);
|
|
|
|
var mom = moment(p.get('time'));
|
|
var time = mom.fromNow() + " ["+mom.format('hh:mm:ss')+"]";
|
|
var speed = p.get('speed') && p.get('speed').match(/\d+|\w+/g).join(' ');
|
|
this.$el.find("#time span").html(time);
|
|
this.$el.find("#speed span").text(speed);
|
|
|
|
var altitude = p.get('altitude')+"";
|
|
var altElement = this.$el.find('#altitude');
|
|
if (!altitude.length || altitude === '0') altElement.hide();
|
|
else altElement.find('span').text(altitude);
|
|
|
|
var adrEl = this.$el.find('#address');
|
|
if (p.get('address').length == 0) p.attributes.address = latlng;
|
|
adrEl.find('a').remove();
|
|
var imgSource = 'images/i_street.jpg';
|
|
|
|
if (!p.get('hasStreetView')){
|
|
adrEl.find('span').text(p.get('address'));
|
|
imgSource = 'images/i_street_d.jpg'
|
|
}else{
|
|
adrEl.find('span').text('');
|
|
adrEl.find('span').append($('<a/>',{href :"javascript:google.maps.openStreetView()",text:p.get('address')}));
|
|
}
|
|
adrEl.find('img').attr('src',imgSource);
|
|
|
|
|
|
//hide voice and/of text if necessary
|
|
[{".name img[alt='PTT']" : "hasVoice"},{"form" : "hasText"}].forEach(function(o){
|
|
var selector = Object.keys(o)[0];
|
|
var method = this.model.get(o[selector])?"show":"hide";
|
|
this.$el.find(selector)[method]();
|
|
},this);
|
|
|
|
if (changedProp==='isInCall') this.computePttState();
|
|
},
|
|
|
|
computePttState : function(event){
|
|
// console.log("========update with isInCall = "+this.model.get('isInCall') + ' for '+this.model.get('id') + " ptt state = " + this.pttState + " event= "+(event && event.type));
|
|
|
|
var setPttState = this.setPttState.bind(this);
|
|
var type = (event && event.type) || "none";
|
|
|
|
if (this.pttState == 'neutral'){
|
|
if (this.model.get('isInCall')) setPttState('called');
|
|
else setPttState('neutral');
|
|
}
|
|
|
|
|
|
if ((this.pttState == 'called' && !this.model.get('isInCall')) ||
|
|
((this.pttState == 'in-call' || this.pttState == 'ask-ptt') && (type =='mouseup' || type == 'dragend'))){
|
|
setPttState('call-done');
|
|
this.computePttState.askPttTimeout && clearTimeout(this.computePttState.askPttTimeout);
|
|
this.computePttState.callDoneTimeout = setTimeout(function(){setPttState('neutral'); },2000);
|
|
return;
|
|
}
|
|
|
|
var callFailed = function(){setPttState('call-failed'); setTimeout(function(){setPttState('neutral');}, 2000);}
|
|
|
|
if (this.pttState == 'neutral' && type=='mousedown') {
|
|
setPttState('ask-ptt');
|
|
this.computePttState.askPttTimeout = setTimeout(function(){
|
|
callFailed();
|
|
},this.model.get('hasVoice')*1000);
|
|
return;
|
|
}
|
|
|
|
|
|
if (this.pttState == 'ask-ptt' ){
|
|
this.computePttState.askPttTimeout && clearTimeout(this.computePttState.askPttTimeout);
|
|
if (this.model.get('isInCall')) setPttState('in-call');
|
|
else callFailed();
|
|
return;
|
|
}
|
|
|
|
if (this.pttState == 'call-done' && this.model.get('isInCall')){
|
|
this.computePttState.callDoneTimeout && clearTimeout(this.computePttState.callDoneTimeout);
|
|
setPttState('called');
|
|
return;
|
|
}
|
|
|
|
}
|
|
});
|
|
|
|
|
|
|
|
|