-
About Quatrermaester.info
+
+ About Quatrermaester.info
+
+
This is a map of the world depicted in the novel series A Song of Ice & Fire and the TV adaptation, A Game of Thrones. The website is designed to display useful information on top of the map layer and link to additional details on the Westeros.org wiki site.
If you haven't finished reading the novels or watching the shows, you can hide any details that might spoil the plot. Simply drag the slider in the top-right corner to the last chapter or episode that you've completed. You can move the slider with arrow buttons in order to animate the characters' paths. Keep in mind that the slider only controls this map; any page you may open on the wiki site may contain spoilers.
-
The map layer used in this website was drawn by theMountainGoat, based on previous work by Tear of the Cartographer's Guild. The map interface is based on the Google Maps API, with custom tiles generated by GMap Image Cutter Version 1.42 and arrows using code from Bill Chadwick. Intellectual property of A Song of Ice and Fire, this map and all locations belong to George R.R. Martin. If you find any errors in the map data, please alert me on the Westeros.org message board.
+
The map layer used in this website was drawn by theMountainGoat, based on previous work by Tear of the Cartographer's Guild. The map interface is built on the Google Maps API, through the angular-google-maps directive. It displays custom tiles generated by GMap Image Cutter Version 1.42. Intellectual property of A Song of Ice and Fire, this map and all locations belong to George R.R. Martin. If you find any errors in the map data, please let me know.
You may notice that this map is contradicted, in places, by the maps shown in The Lands of Ice and Fire. Since the maps in that collection are clearly copyrighted material, I have no intention of copying them directly and I'm going to remain cautious in pulling details from them to correct this website. You can find low-resolution versions of the official maps on the artist's website or in Random House's iOS & Android apps.
Other Resources
diff --git a/js/controller.js b/js/controller.js
index da61747..877820d 100644
--- a/js/controller.js
+++ b/js/controller.js
@@ -52,6 +52,7 @@ angular.module('quartermaester')
$scope.toState = toState;
$scope.slideTo = slideTo;
$scope.panTo = panTo;
+ $scope.resultClick = resultClick;
$scope.refreshMap = refreshMap;
$scope.locationDetail = null;
@@ -74,6 +75,7 @@ angular.module('quartermaester')
$scope.$watch('slider', refreshMap, true);
$scope.$watch('options', refreshMap, true);
+ $scope.$watch('options.characters', panToCharacter, true);
for (var i=0;i
= 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;
@@ -153,7 +173,7 @@ angular.module('quartermaester')
}
break;
}
-
+ $scope.$broadcast('rzSliderForceRender');
}
function panTo(input) {
@@ -165,6 +185,61 @@ angular.module('quartermaester')
$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";
diff --git a/js/services.js b/js/services.js
index 6684a35..b51798b 100644
--- a/js/services.js
+++ b/js/services.js
@@ -138,7 +138,7 @@ angular.module('quartermaester')
icon: "glyphicon-facetime-video",
title: episode.title,
subtitle: "HBO episode",
- abbr: "S" + episode.season + "E" + epNumber + ": " + episode.title,
+ abbr: "S" + episode.season + "E" + epNumber,
click: function(){slideTo(this.abbr)}
};
}
@@ -213,6 +213,7 @@ angular.module('quartermaester')
longitude: parseFloat(town.longitude)
},
options: {
+ // zindex: 2, // bug prevents this form working
icon: {path: 0, strokeOpacity: 0, scale: 3}
}
});
@@ -228,9 +229,8 @@ angular.module('quartermaester')
return {
icon: "glyphicon-map-marker",
key: town.key,
- title: town.name,
- subtitle: town.region.replace(/_/g," "),
- click: function(){panTo(this.key)}
+ title: decodeURI(town.key).replace(/_/g," "),
+ subtitle: town.region.replace(/_/g," ")
};
}
@@ -255,8 +255,7 @@ angular.module('quartermaester')
icon: "glyphicon-user",
key: character.key,
title: character.name,
- subtitle: "", //decodeURI(character.house).replace(/_/g," "),
- click: function(){showCharacter(this.key)}
+ subtitle: "", //decodeURI(character.house).replace(/_/g," ")
};
}
@@ -292,6 +291,7 @@ angular.module('quartermaester')
direct: "#@" + house.seatKey,
coords: coords,
options: {
+ // zindex: 1, // bug prevents this form working
icon: {
url: house.img,
scaledSize: house.isGreat ? {height:60, width:50} : {height:30, width:25},
@@ -305,8 +305,7 @@ angular.module('quartermaester')
return {
icon: "glyphicon-home",
title: decodeURI(house.wikiKey).replace(/_/g," "),
- subtitle: (house.seatKey=="") ? house.clue : decodeURI(house.seatKey).replace(/_/g," "),
- click: function(){showCharacter(character.key)}
+ subtitle: (house.seatKey=="") ? house.clue : decodeURI(house.seatKey).replace(/_/g," ")
};
}
@@ -486,7 +485,7 @@ angular.module('quartermaester')
// var listHeight = attrs.qmList ? 41*parseInt(attrs.qmList, 10) : 0;
// console.log(winHeight, attrs.qmList, listHeight);
// if (listHeight>winHeight) elem.css('height', winHeight - 48 + 'px');
- elem.css('height', winHeight - 50 + 'px');
+ elem.css('height', winHeight - 55 + 'px');
}
};
});