740d5ccfab
slider skip will continue to final chapter map pans when character is enabled close buttons in all headers towns added to search results search results are clickable edited about text
286 lines
10 KiB
JavaScript
286 lines
10 KiB
JavaScript
angular.module('quartermaester')
|
|
|
|
.controller("mapCtrl", function($scope, $filter, $timeout, uiGmapGoogleMapApi, smgMapType, qmCsv) {
|
|
|
|
var qmData = {};
|
|
$scope.state = "slider";
|
|
$scope.search = "";
|
|
$scope.slider = {
|
|
show: "episodes",
|
|
currentEpisode: 0,
|
|
currentChapter: 0
|
|
};
|
|
$scope.options = {
|
|
characterPaths: true,
|
|
houseHeraldry: false,
|
|
geographicRegions: false,
|
|
politicalAllegiances: false,
|
|
characters: {}
|
|
};
|
|
$scope.map = {
|
|
center: {
|
|
latitude: 1.3182,
|
|
longitude: -105.9960
|
|
},
|
|
zoom: 4,
|
|
options: {
|
|
maxZoom: 5,
|
|
minZoom: 1,
|
|
disableDefaultUI: true,
|
|
zoomControl: true
|
|
},
|
|
events: {
|
|
click: mapClick
|
|
},
|
|
control: {},
|
|
smgMapType: smgMapType,
|
|
locationClick: locationClick,
|
|
heraldryClick: heraldryClick,
|
|
characterClick: characterClick
|
|
};
|
|
$scope.mapModels = {
|
|
towns: [],
|
|
heraldry: [],
|
|
characters: [],
|
|
paths: [],
|
|
regions: [],
|
|
loyalties: []
|
|
};
|
|
$scope.episodes = [];
|
|
$scope.chapters = [];
|
|
$scope.searchResults = [];
|
|
$scope.toState = toState;
|
|
$scope.slideTo = slideTo;
|
|
$scope.panTo = panTo;
|
|
$scope.resultClick = resultClick;
|
|
$scope.refreshMap = refreshMap;
|
|
$scope.locationDetail = null;
|
|
|
|
// Set up promises
|
|
uiGmapGoogleMapApi.then(onMapLoad);
|
|
qmCsv.loadData().then(addToScope);
|
|
|
|
|
|
//////////////////
|
|
|
|
function addToScope(d) {
|
|
qmData = d;
|
|
|
|
// Add data from CSV files into $scope
|
|
$scope.episodes = qmData.episodes;
|
|
$scope.chapters = qmData.chapters;
|
|
$scope.characters = qmData.characters;
|
|
$scope.searchResults = qmData.searchResults;
|
|
$scope.mapModels.regions = qmData.regions;
|
|
|
|
$scope.$watch('slider', refreshMap, true);
|
|
$scope.$watch('options', refreshMap, true);
|
|
$scope.$watch('options.characters', panToCharacter, true);
|
|
|
|
for (var i=0;i<qmData.characters.length; i++) {
|
|
$scope.options.characters[qmData.characters[i].key] = false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function refreshMap() {
|
|
// Redraw map with new slider values
|
|
$scope.mapModels.towns = $filter('qmSlider')(qmData.towns, $scope.slider);
|
|
$scope.mapModels.heraldry = $scope.options.houseHeraldry ? $filter('qmSlider')(qmData.heraldry, $scope.slider) : [];
|
|
$scope.mapModels.characters = $filter('qmSlider')(qmData.characterMarkers, $scope.slider, $scope.options);
|
|
$scope.mapModels.paths = $filter('qmSlider')(qmData.characterPaths, $scope.slider, $scope.options);
|
|
//console.log("mapModels.paths", $scope.mapModels.paths);
|
|
}
|
|
|
|
function panToCharacter(newValue, oldValue) {
|
|
for (var character in newValue) {
|
|
if (newValue[character] && !oldValue[character]) {
|
|
var characterMarkers = $filter('filter')($scope.mapModels.characters, {character: {key: character}});
|
|
if (characterMarkers.length==0) return false;
|
|
|
|
var coords = characterMarkers[characterMarkers.length-1].coords
|
|
$scope.map.control.getGMap().panTo({lat: coords.latitude, lng: coords.longitude});
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
function toState(stateName) {
|
|
$scope.state = stateName;
|
|
if (stateName=="search") $timeout(function() {
|
|
document.getElementById("searchInput").focus();
|
|
});
|
|
// if (stateName=="slider-full") $timeout(function() {
|
|
// console.log(document.getElementById("slide-"+$scope.slider.show).getElementsByClassName("rz-pointer"));
|
|
// document.getElementById("slide-"+$scope.slider.show).getElementsByClassName("rz-pointer")[0].focus();
|
|
// });
|
|
}
|
|
|
|
function slideTo(input) {
|
|
var books = qmData.books.map(function(book) {return book.abbreviation;});
|
|
var measure = ($scope.slider.show=="episodes") ? "currentEpisode" : "currentChapter";
|
|
var sliderMax = ($scope.slider.show=="episodes") ? $scope.episodes.length-1 : $scope.chapters.length-1;
|
|
switch (input) {
|
|
case -10:
|
|
if ($scope.slider[measure]==0) break;
|
|
if ($scope.slider.show=="episodes") $scope.slider[measure] = Math.floor(($scope.slider[measure]-1)/10)*10;
|
|
else {
|
|
for (var bookId=4; bookId>=0; bookId--) {
|
|
var prologue = parseInt(qmData.books[bookId].precedingChapters, 10);
|
|
if (prologue > $scope.slider[measure]-1) continue;
|
|
$scope.slider[measure] = prologue;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case -1:
|
|
if ($scope.slider[measure]>0) $scope.slider[measure]--;
|
|
break;
|
|
case 1:
|
|
if ($scope.slider[measure]<sliderMax) $scope.slider[measure]++;
|
|
break;
|
|
case 10:
|
|
if ($scope.slider[measure]==sliderMax) break;
|
|
if ($scope.slider.show=="episodes") $scope.slider[measure] = Math.min(sliderMax, Math.ceil(($scope.slider[measure]+2)/10)*10-1);
|
|
else {
|
|
if ($scope.slider[measure] >= 270) {
|
|
$scope.slider[measure] = 344;
|
|
break;
|
|
}
|
|
for (var bookId=0; bookId<=4; bookId++) {
|
|
var epilogue = parseInt(qmData.books[bookId].precedingChapters, 10)-1;
|
|
if (epilogue < $scope.slider[measure]+1) continue;
|
|
$scope.slider[measure] = epilogue;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
$scope.state = "slider";
|
|
if (input.indexOf("-")<0) {
|
|
// HBO show
|
|
$scope.slider.show = "episodes";
|
|
$scope.slider.currentEpisode = qmCsv.getEpisodeId(input);
|
|
// var reMatch = /S(\d)E0?(\d+)/.exec(input);
|
|
// $scope.slider.currentEpisode = 10*(parseInt(reMatch[1])-1) + parseInt(reMatch[2])-1;
|
|
} else {
|
|
$scope.slider.show = "chapters";
|
|
// $scope.slider.currentChapter = qmCsv.getChapterId(input);
|
|
var reMatch = /(\w{4})\-(\d+)/.exec(input);
|
|
var bookId = books.indexOf(reMatch[1]);
|
|
$scope.slider.currentChapter = parseInt(qmData.books[bookId].precedingChapters, 10) + parseInt(reMatch[2], 10);
|
|
}
|
|
break;
|
|
}
|
|
$scope.$broadcast('rzSliderForceRender');
|
|
}
|
|
|
|
function panTo(input) {
|
|
|
|
console.log("panTo", input);
|
|
var location = $filter('filter')($scope.map.locations, {key: input})[0];
|
|
$scope.map.control.getGMap().panTo({lat: location.coords.latitude, lng: location.coords.longitude});
|
|
$scope.locationDetail = location;
|
|
$scope.state = "location";
|
|
}
|
|
|
|
function resultClick(model) {
|
|
switch (model.icon) {
|
|
case "glyphicon-map-marker":
|
|
var town = $filter('filter')($scope.mapModels.towns, {key: model.key})[0];
|
|
$scope.map.control.getGMap().panTo({lat: town.coords.latitude, lng: town.coords.longitude});
|
|
$scope.locationDetail = town;
|
|
$scope.state = "location";
|
|
break;
|
|
|
|
case "glyphicon-user":
|
|
$scope.options.characters[model.key] = true;
|
|
var character = $filter('filter')($scope.characters, {key: model.key})[0];
|
|
var allCharacterMarkers = $filter('qmSlider')(qmData.characterMarkers, $scope.slider, $scope.options);
|
|
var matchedCharacterMarkers = $filter('filter')(allCharacterMarkers, {character: {key: model.key}});
|
|
$scope.locationDetail = {
|
|
name: "",
|
|
url: "",
|
|
house: character.name,
|
|
houseImg: character.house.img,
|
|
houseUrl: character.url,
|
|
direct: "#"
|
|
};
|
|
$scope.state = "location";
|
|
if (matchedCharacterMarkers.length==0) break;
|
|
var thisCharacterMarker = matchedCharacterMarkers[0];
|
|
$scope.map.control.getGMap().panTo({lat: thisCharacterMarker.coords.latitude, lng: thisCharacterMarker.coords.longitude});
|
|
$scope.locationDetail.name = thisCharacterMarker.town.name;
|
|
$scope.locationDetail.url = thisCharacterMarker.town.url;
|
|
$scope.locationDetail.direct = ($scope.slider.show=="episodes") ? thisCharacterMarker.episode.url : thisCharacterMarker.chapter.url;
|
|
break;
|
|
|
|
case "glyphicon-home":
|
|
var house = $filter('filter')(qmData.heraldry, {seat: model.subtitle})[0];
|
|
$scope.map.control.getGMap().panTo({lat: house.coords.latitude, lng: house.coords.longitude});
|
|
$scope.locationDetail = {
|
|
name: house.seat,
|
|
url: house.seatUrl,
|
|
house: house.name,
|
|
houseImg: house.houseImg,
|
|
houseUrl: house.url,
|
|
direct: house.direct
|
|
};
|
|
$scope.state = "location";
|
|
break;
|
|
|
|
case "glyphicon-facetime-video":
|
|
case "glyphicon-book":
|
|
slideTo(model.abbr);
|
|
break;
|
|
|
|
default:
|
|
console.log("resultClick", model);
|
|
}
|
|
}
|
|
|
|
function locationClick(marker, eventName, model) {
|
|
$scope.locationDetail = model;
|
|
$scope.state = "location";
|
|
}
|
|
|
|
function heraldryClick(marker, eventName, model) {
|
|
$scope.locationDetail = {
|
|
name: model.seat,
|
|
url: model.seatUrl,
|
|
house: model.name,
|
|
houseImg: model.houseImg,
|
|
houseUrl: model.url,
|
|
direct: model.direct
|
|
};
|
|
$scope.state = "location";
|
|
}
|
|
|
|
function characterClick(marker, eventName, model) {
|
|
$scope.locationDetail = {
|
|
name: model.town.name,
|
|
url: model.town.url,
|
|
house: model.character.name,
|
|
houseImg: model.character.houseImg,
|
|
houseUrl: model.character.url,
|
|
direct: ($scope.slider.show=="episodes") ? model.episode.url : model.chapter.url
|
|
};
|
|
$scope.state = "location";
|
|
}
|
|
|
|
function mapClick() {
|
|
$scope.state = "slider";
|
|
}
|
|
|
|
function onMapLoad(maps) {
|
|
|
|
// Add background to .rz-bar
|
|
var rzbars = document.getElementsByClassName("rz-bar");
|
|
rzbars[0].innerHTML = "<span class='odd'>1</span><span>2</span><span class='odd'>3</span><span>4</span><span class='odd'>5</span><span>6</span>";
|
|
rzbars[2].innerHTML = "<span class='odd'>AGOT</span><span>ACOK</span><span class='odd'>ASOS</span><span>AFFC</span><span class='odd'>ADWD</span>";
|
|
|
|
}
|
|
|
|
});
|