got character switches working

added character paths
fixed heraldry & character click events
fast-forward button moves to next book/season
This commit is contained in:
Ryan Carpenter
2016-08-01 22:08:19 +08:00
parent b909081afd
commit 1b97ca6412
4 changed files with 126 additions and 30 deletions
+2 -2
View File
@@ -7,7 +7,7 @@ season,episode,title,awoiaf,wikipedia
1,6,A Golden Crown,A_Golden_Crown, 1,6,A Golden Crown,A_Golden_Crown,
1,7,You Win or You Die,You_Win_or_You_Die, 1,7,You Win or You Die,You_Win_or_You_Die,
1,8,The Pointy End,The_Pointy_End, 1,8,The Pointy End,The_Pointy_End,
1,9,Baelor,Baelor, 1,9,Baelor,Baelor_(TV),
1,10,Fire and Blood,Fire_and_Blood_(Game_of_Thrones), 1,10,Fire and Blood,Fire_and_Blood_(Game_of_Thrones),
2,1,The North Remembers,The_North_Remembers_(TV), 2,1,The North Remembers,The_North_Remembers_(TV),
2,2,The Night Lands,The_Night_Lands_(TV), 2,2,The Night Lands,The_Night_Lands_(TV),
@@ -58,4 +58,4 @@ season,episode,title,awoiaf,wikipedia
6,7,The Broken Man,,The_Broken_Man 6,7,The Broken Man,,The_Broken_Man
6,8,No One,,No_One_(Game_of_Thrones) 6,8,No One,,No_One_(Game_of_Thrones)
6,9,Battle of the Bastards,,Battle_of_the_Bastards 6,9,Battle of the Bastards,,Battle_of_the_Bastards
6,10,The Winds of Winter,,The_Winds_of_Winter_(Game_of_Thrones) 6,10,The Winds of Winter,,The_Winds_of_Winter_(Game_of_Thrones)
1 season episode title awoiaf wikipedia
7 1 6 A Golden Crown A_Golden_Crown
8 1 7 You Win or You Die You_Win_or_You_Die
9 1 8 The Pointy End The_Pointy_End
10 1 9 Baelor Baelor Baelor_(TV)
11 1 10 Fire and Blood Fire_and_Blood_(Game_of_Thrones)
12 2 1 The North Remembers The_North_Remembers_(TV)
13 2 2 The Night Lands The_Night_Lands_(TV)
58 6 7 The Broken Man The_Broken_Man
59 6 8 No One No_One_(Game_of_Thrones)
60 6 9 Battle of the Bastards Battle_of_the_Bastards
61 6 10 The Winds of Winter The_Winds_of_Winter_(Game_of_Thrones)
+9 -5
View File
@@ -67,10 +67,14 @@
</ui-gmap-markers> </ui-gmap-markers>
<!-- Character Paths --> <!-- Character Paths -->
<!-- <ui-gmap-polylines <ui-gmap-polylines
models='mapModels.paths' models='mapModels.paths'
idkey="'key'"> path="'path'"
</ui-gmap-polylines> --> stroke="'stroke'"
static="'static'"
icons="'icons'"
idkey="'key'">
</ui-gmap-polylines>
</ui-gmap-google-map> </ui-gmap-google-map>
@@ -195,7 +199,7 @@
</a> </a>
<a ng-href="{{character.url}}" ng-class="{noimg:(character.house=='')}">{{character.name}}</a> <a ng-href="{{character.url}}" ng-class="{noimg:(character.house=='')}">{{character.name}}</a>
<toggle-switch <toggle-switch
ng-model="options.characters[$index]" ng-model="options.characters[character.key]"
on-label="Show" on-label="Show"
off-label="Hide" off-label="Hide"
class="pull-right"> class="pull-right">
+58 -15
View File
@@ -15,7 +15,7 @@ angular.module('quartermaester')
houseHeraldry: false, houseHeraldry: false,
geographicRegions: false, geographicRegions: false,
politicalAllegiances: false, politicalAllegiances: false,
characters: [] characters: {}
}; };
$scope.map = { $scope.map = {
center: { center: {
@@ -36,7 +36,7 @@ angular.module('quartermaester')
smgMapType: smgMapType, smgMapType: smgMapType,
locationClick: locationClick, locationClick: locationClick,
heraldryClick: heraldryClick, heraldryClick: heraldryClick,
characterClick: heraldryClick characterClick: characterClick
}; };
$scope.mapModels = { $scope.mapModels = {
towns: [], towns: [],
@@ -75,6 +75,10 @@ angular.module('quartermaester')
$scope.$watch('slider', refreshMap, true); $scope.$watch('slider', refreshMap, true);
$scope.$watch('options', refreshMap, true); $scope.$watch('options', refreshMap, true);
for (var i=0;i<qmData.characters.length; i++) {
$scope.options.characters[qmData.characters[i].key] = false;
}
return true; return true;
} }
@@ -82,9 +86,9 @@ angular.module('quartermaester')
// Redraw map with new slider values // Redraw map with new slider values
$scope.mapModels.towns = $filter('qmSlider')(qmData.towns, $scope.slider); $scope.mapModels.towns = $filter('qmSlider')(qmData.towns, $scope.slider);
$scope.mapModels.heraldry = $scope.options.houseHeraldry ? $filter('qmSlider')(qmData.heraldry, $scope.slider) : []; $scope.mapModels.heraldry = $scope.options.houseHeraldry ? $filter('qmSlider')(qmData.heraldry, $scope.slider) : [];
$scope.mapModels.characters = $filter('qmSlider')(qmData.characterMarkers, $scope.slider); //$filter('qmCharacters')(qmData.characterMarkers, $scope.options.characters, $scope.slider); $scope.mapModels.characters = $filter('qmSlider')(qmData.characterMarkers, $scope.slider, $scope.options);
$scope.mapModels.paths = qmData.characterPaths; $scope.mapModels.paths = $filter('qmSlider')(qmData.characterPaths, $scope.slider, $scope.options);
console.log("qmData.characterPaths", qmData.characterPaths); // console.log("qmData.characterPaths", qmData.characterPaths);
} }
@@ -103,7 +107,16 @@ angular.module('quartermaester')
var sliderMax = ($scope.slider.show=="episodes") ? $scope.episodes.length-1 : $scope.chapters.length-1; var sliderMax = ($scope.slider.show=="episodes") ? $scope.episodes.length-1 : $scope.chapters.length-1;
switch (input) { switch (input) {
case -10: case -10:
$scope.slider[measure] = 0; 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; break;
case -1: case -1:
if ($scope.slider[measure]>0) $scope.slider[measure]--; if ($scope.slider[measure]>0) $scope.slider[measure]--;
@@ -112,21 +125,32 @@ angular.module('quartermaester')
if ($scope.slider[measure]<sliderMax) $scope.slider[measure]++; if ($scope.slider[measure]<sliderMax) $scope.slider[measure]++;
break; break;
case 10: case 10:
$scope.slider[measure] = sliderMax; 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 {
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; break;
default: default:
$scope.state = "slider"; $scope.state = "slider";
if (input.indexOf("-")<0) { if (input.indexOf("-")<0) {
// HBO show // HBO show
$scope.slider.show = "episodes"; $scope.slider.show = "episodes";
var reMatch = /S(\d)E0?(\d+)/.exec(input); $scope.slider.currentEpisode = qmCsv.getEpisodeId(input);
$scope.slider.currentEpisode = 10*(parseInt(reMatch[1])-1) + parseInt(reMatch[2])-1; // var reMatch = /S(\d)E0?(\d+)/.exec(input);
break; // $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);
} }
$scope.slider.show = "chapters";
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; break;
} }
@@ -147,7 +171,26 @@ angular.module('quartermaester')
} }
function heraldryClick(marker, eventName, model) { function heraldryClick(marker, eventName, model) {
$scope.locationDetail = 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"; $scope.state = "location";
} }
+57 -8
View File
@@ -51,9 +51,11 @@ angular.module('quartermaester')
.factory('qmCsv', function($q, $http, $filter, fCsv) { .factory('qmCsv', function($q, $http, $filter, fCsv) {
var csvLocation = "http://www.rslc.us/quartermaester/data/"; var csvLocation = (window.location.protocol=="file:") ? "https://raw.githubusercontent.com/carpiediem/quartermaester/master/data/" : "data/";
return { return {
loadData: loadData loadData: loadData,
getEpisodeId: getEpisodeId,
//getChapterId: getChapterId
}; };
/////////////////////////////// ///////////////////////////////
@@ -78,6 +80,7 @@ angular.module('quartermaester')
function parseData(books, chapters, seasons, episodes, houses, characters, regions, towns, borders, stops, waypoints, paths) { function parseData(books, chapters, seasons, episodes, houses, characters, regions, towns, borders, stops, waypoints, paths) {
var qmData = { var qmData = {
borderArrays: {}, borderArrays: {},
waypointArrays: {},
bookLookup: {} bookLookup: {}
}; };
@@ -88,6 +91,12 @@ angular.module('quartermaester')
qmData.borderArrays[borders[i].name].push(borders[i]); qmData.borderArrays[borders[i].name].push(borders[i]);
} }
for (var i=0; i<waypoints.length; i++) {
if (!(waypoints[i].key in qmData.waypointArrays))
qmData.waypointArrays[waypoints[i].key] = [];
qmData.waypointArrays[waypoints[i].key].push(waypoints[i]);
}
for (var i=0; i<books.length; i++) { for (var i=0; i<books.length; i++) {
qmData.bookLookup[books[i].abbreviation] = books[i]; qmData.bookLookup[books[i].abbreviation] = books[i];
} }
@@ -100,6 +109,7 @@ angular.module('quartermaester')
qmData.towns = getTownMarkers(towns, houses); qmData.towns = getTownMarkers(towns, houses);
qmData.heraldry = houses.map(heraldryMarkerModel); qmData.heraldry = houses.map(heraldryMarkerModel);
qmData.characterMarkers = stops.map(characterMarkerModel); qmData.characterMarkers = stops.map(characterMarkerModel);
qmData.characterPaths = paths.map(characterPathModel);
qmData.searchResults = [].concat( qmData.searchResults = [].concat(
@@ -110,8 +120,6 @@ angular.module('quartermaester')
chapters.map(chapterSearchModel) chapters.map(chapterSearchModel)
); );
qmData.characterPaths = [];
return qmData; return qmData;
@@ -232,6 +240,7 @@ angular.module('quartermaester')
key: character.key, key: character.key,
name: character.name, name: character.name,
url: "http://awoiaf.westeros.org/index.php/" + character.key, url: "http://awoiaf.westeros.org/index.php/" + character.key,
color: character.markerColor,
pin: "https://chart.googleapis.com/chart?chst=d_map_pin_letter&chld=" + character.letter + "|" + character.markerColor.substring(1,7) + "|" + character.letterColor.substring(1,7), pin: "https://chart.googleapis.com/chart?chst=d_map_pin_letter&chld=" + character.letter + "|" + character.markerColor.substring(1,7) + "|" + character.letterColor.substring(1,7),
house: (character.house=="") ? "" : { house: (character.house=="") ? "" : {
name: decodeURI(matchingHouse.wikiKey).replace(/_/g," "), name: decodeURI(matchingHouse.wikiKey).replace(/_/g," "),
@@ -335,13 +344,15 @@ angular.module('quartermaester')
return { return {
key: "stop-" + index, key: "stop-" + index,
character: { character: {
key: matchingCharacter.key,
name: matchingCharacter.name, name: matchingCharacter.name,
url: "http://awoiaf.westeros.org/index.php/" + matchingCharacter.key url: "http://awoiaf.westeros.org/index.php/" + matchingCharacter.key,
houseImg: matchingCharacter.house.img
}, },
episode: qmData.episodes[firstEpisode], episode: qmData.episodes[firstEpisode],
chapter: qmData.chapters[firstChapter], chapter: qmData.chapters[firstChapter],
location: { town: {
name: (stop.town=="") ? stop.clue : stop.town, name: (stop.town=="") ? stop.clue : decodeURI(stop.town).replace(/_/g," "),
url: (stop.town=="") ? "#" : "http://awoiaf.westeros.org/index.php/" + stop.town url: (stop.town=="") ? "#" : "http://awoiaf.westeros.org/index.php/" + stop.town
}, },
timing: { timing: {
@@ -355,7 +366,39 @@ angular.module('quartermaester')
}; };
} }
function characterPathModel(path, index) {
var reMatch = /([\w\_]+)\-\d+/.exec(path.key);
var matchingCharacter = $filter('filter')(qmData.characters, {key: reMatch[1]})[0];
var firstChapter = getChapterId(path.firstChapter);
var firstEpisode = getEpisodeId(path.firstEpisode);
var waypoints = qmData.waypointArrays[path.key].map(waypointModel);
return {
key: "path-" + index,
character: { key: matchingCharacter.key },
path: waypoints,
stroke: {
color: matchingCharacter.color,
weight: 3
},
static: true,
icons: [{
icon: { path: 2 }, //google.maps.SymbolPath.BACKWARD_OPEN_ARROW
offset: '25px',
repeat: '100px'
}],
timing: {
episodes: [firstEpisode, 999],
chapters: [firstChapter, 999]
}
};
}
function waypointModel(waypoint) {
if (waypoint.location=="") return {latitude: parseFloat(waypoint.latitude), longitude: parseFloat(waypoint.longitude)};
var matchingTown = $filter('filter')(qmData.towns, {key: waypoint.location})[0];
return matchingTown.coords;
}
@@ -381,6 +424,9 @@ angular.module('quartermaester')
.get(csvLocation + filename) .get(csvLocation + filename)
.then(getDataAttr) .then(getDataAttr)
.then(fCsv.toJson) .then(fCsv.toJson)
// .then(function(json){
// // Remove \" characters from strings
// })
.then(angular.fromJson) .then(angular.fromJson)
} }
@@ -402,7 +448,7 @@ angular.module('quartermaester')
// In the return function, we must pass in a single parameter which will be the data we will work on. // In the return function, we must pass in a single parameter which will be the data we will work on.
// We have the ability to support multiple other parameters that can be passed into the filter optionally // We have the ability to support multiple other parameters that can be passed into the filter optionally
return function(inputArray, slider) { return function(inputArray, slider, options) {
var outputArray = []; var outputArray = [];
var currentValue = (slider.show=="episodes") ? slider.currentEpisode : slider.currentChapter; var currentValue = (slider.show=="episodes") ? slider.currentEpisode : slider.currentChapter;
@@ -410,6 +456,9 @@ angular.module('quartermaester')
for (var i=0; i<inputArray.length; i++) { for (var i=0; i<inputArray.length; i++) {
if (currentValue < inputArray[i].timing[slider.show][0]) continue; if (currentValue < inputArray[i].timing[slider.show][0]) continue;
if (currentValue > inputArray[i].timing[slider.show][1]) continue; if (currentValue > inputArray[i].timing[slider.show][1]) continue;
if (typeof options !== "undefined" && typeof inputArray[i].character.key !== "undefined") {
if (!options.characters[ inputArray[i].character.key ]) continue;
}
outputArray.push(inputArray[i]); outputArray.push(inputArray[i]);
} }