SafeNet/SDMaps/src/models.js

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() + "&nbsp;&nbsp;&nbsp;["+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;
}
}
});