Initial Commit

This commit is contained in:
Ryan Carpenter
2016-07-24 19:33:57 +08:00
commit 26ed9882ce
1385 changed files with 2099 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
angular.module("fCsv",[]).factory("fCsv",function(){var n=function(n,r,t){if(n){r=r||",",t=t||!0;var e=[],f=[],l=0,i=n.split("\n"),s=i[0].split(r).length;t&&(f=i[0].split(r),l=1);for(var a=l;a<i.length;a++){var o={},g=i[a].split(new RegExp(r+'(?![^"]*"(?:(?:[^"]*"){2})*[^"]*$)'));if(g.length===s){if(t)for(var v=0;v<f.length;v++)o[f[v]]=g[v];else for(var u=0;u<g.length;u++)o[u]=g[u];e.push(o)}}return JSON.stringify(e)}};return{toJson:n}});
+13
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
angular.module("toggle-switch",["ng"]).directive("toggleSwitch",["$compile",function($compile){return{restrict:"EA",replace:!0,require:"ngModel",scope:{isDisabled:"=",onLabel:"@",offLabel:"@",knobLabel:"@",html:"=",onChange:"&"},template:'<div class="ats-switch" ng-click="toggle()" ng-keypress="onKeyPress($event)" ng-class="{ \'disabled\': isDisabled }" role="switch" aria-checked="{{!!model}}"><div class="switch-animate" ng-class="{\'switch-off\': !model, \'switch-on\': model}"><span class="switch-left"></span><span class="knob"></span><span class="switch-right"></span></div></div>',compile:function(element,attrs){return angular.isUndefined(attrs.onLabel)&&(attrs.onLabel="On"),angular.isUndefined(attrs.offLabel)&&(attrs.offLabel="Off"),angular.isUndefined(attrs.knobLabel)&&(attrs.knobLabel=" "),angular.isUndefined(attrs.isDisabled)&&(attrs.isDisabled=!1),angular.isUndefined(attrs.html)&&(attrs.html=!1),angular.isUndefined(attrs.tabindex)&&(attrs.tabindex=0),function(scope,iElement,iAttrs,ngModel){iElement.attr("tabindex",attrs.tabindex),scope.toggle=function(){scope.isDisabled||(scope.model=!scope.model,ngModel.$setViewValue(scope.model)),scope.onChange()};var spaceCharCode=32;scope.onKeyPress=function($event){$event.charCode!=spaceCharCode||$event.altKey||$event.ctrlKey||$event.metaKey||scope.toggle();$event.preventDefault()},ngModel.$formatters.push(function(modelValue){return modelValue}),ngModel.$parsers.push(function(viewValue){return viewValue}),ngModel.$viewChangeListeners.push(function(){scope.$eval(attrs.ngChange)}),ngModel.$render=function(){scope.model=ngModel.$viewValue};var bindSpan=function(span,html){span=angular.element(span);var bindAttributeName=html===!0?"ng-bind-html":"ng-bind";span.removeAttr("ng-bind-html"),span.removeAttr("ng-bind"),angular.element(span).hasClass("switch-left")&&span.attr(bindAttributeName,"onLabel"),span.hasClass("knob")&&span.attr(bindAttributeName,"knobLabel"),span.hasClass("switch-right")&&span.attr(bindAttributeName,"offLabel"),$compile(span)(scope,function(cloned,scope){span.replaceWith(cloned)})},bindSwitch=function(iElement,html){angular.forEach(iElement[0].children[0].children,function(span,index){bindSpan(span,html)})};scope.$watch("html",function(newValue){bindSwitch(iElement,newValue)})}}}}]);
+9
View File
@@ -0,0 +1,9 @@
angular.module('quartermaester', ['ui.bootstrap', 'uiGmapgoogle-maps', 'fCsv', 'toggle-switch', 'rzModule'])
.config(function(uiGmapGoogleMapApiProvider) {
uiGmapGoogleMapApiProvider.configure({
key: 'AIzaSyA805RWgioHgUbrtVo9sWAnk_UWT9_xDXE',
//v: '3.20', //defaults to latest 3.X anyhow
libraries: 'weather,geometry,visualization'
});
});
+250
View File
@@ -0,0 +1,250 @@
angular.module('quartermaester')
.controller("mapCtrl", function($scope, $q, $filter, $timeout, uiGmapGoogleMapApi, smgMapType, qmCsv) {
$scope.state = "slider";
$scope.slider = {
show: "episodes",
currentEpisode: 0,
currentChapter: 0
};
$scope.map = {
center: {
latitude: 1.3182,
longitude: -105.9960
},
zoom: 4,
options: {
maxZoom: 5,
minZoom: 1
},
events: {
click: mapClick
},
control: {},
locationClick: locationClick,
locations: []
};
$scope.options = {
characterPaths: true,
houseHeraldry: false,
geographicRegions: false,
politicalAllegiances: false
};
$scope.search = "";
$scope.smgMapType = smgMapType;
$scope.toState = toState;
$scope.slideTo = slideTo;
$scope.panTo = panTo;
$scope.episodes = [];
$scope.chapters = [];
$scope.searchResults = [
{
icon: "glyphicon-user",
title: "Eddard Stark",
subtitle: "House Stark",
search: "Eddard Stark",
click: function(){showCharacter("eddard")}
}
];
$scope.locationDetail = null;
// Set up promises
uiGmapGoogleMapApi.then(onMapLoad);
$q.all([
qmCsv.get('locations.csv'),
qmCsv.get('houses.csv')
]).then(createLocationMarkers);
$q.all([
qmCsv.get('books.csv'),
qmCsv.get('chapters.csv')
]).then(addChaptersToScope);
qmCsv.get('episodes.csv').then(addEpisodesToScope);
$q.all([
qmCsv.get('characters.csv'),
qmCsv.get('houses.csv')
]).then(addCharactersToScope);
$q.all([
qmCsv.get('regions.csv'),
qmCsv.get('borders.csv')
]).then(addRegionsToScope);
function toState(stateName) {
$scope.state = stateName;
if (stateName=="search")
$timeout(function() {
document.getElementById("searchInput").focus();
});
}
function slideTo(input) {
var books = $scope.books.map(function(book) {return book.abbreviation;});
var sliderIndex = ($scope.slider.show=="episodes") ? "currentEpisode" : "currentChapter";
var sliderMax = ($scope.slider.show=="episodes") ? $scope.episodes.length-1 : $scope.chapters.length-1;
switch (input) {
case -10:
$scope.slider[sliderIndex] = 0;
break;
case -1:
if ($scope.slider[sliderIndex]>0) $scope.slider[sliderIndex]--;
break;
case 1:
if ($scope.slider[sliderIndex]<sliderMax) $scope.slider[sliderIndex]++;
break;
case 10:
$scope.slider[sliderIndex] = sliderMax;
break;
default:
$scope.state = "slider";
if (input.indexOf("-")<0) {
// HBO show
$scope.slider.show = "episodes";
var reMatch = /S(\d)E0?(\d+)/.exec(input);
$scope.slider.currentEpisode = 10*(parseInt(reMatch[1])-1) + parseInt(reMatch[2])-1;
break;
}
$scope.slider.show = "chapters";
var reMatch = /(\w{4})\-(\d+)/.exec(input);
var bookId = books.indexOf(reMatch[1]);
$scope.slider.currentChapter = parseInt($scope.books[bookId].precedingChapters, 10) + parseInt(reMatch[2], 10);
break;
}
}
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 addEpisodesToScope(response) {
$scope.episodes = response.map(function(episode) {
var epNumber = (episode.episode.length==2) ? episode.episode : "0"+episode.episode;
return {
name: "S" + episode.season + "E" + epNumber + ": " + episode.title,
url: (episode.awoiaf=="") ? "https://en.wikipedia.org/wiki/"+episode.wikipedia : "http://awoiaf.westeros.org/index.php/"+episode.awoiaf
};
});
//console.log("e", $scope.episodes);
$scope.searchResults = $scope.searchResults.concat(response.map(function(episode) {
var epNumber = (episode.episode.length==2) ? episode.episode : "0"+episode.episode;
return {
icon: "glyphicon-facetime-video",
title: episode.title,
subtitle: "HBO episode",
search: episode.title,
abbr: "S" + episode.season + "E" + epNumber + ": " + episode.title,
click: function(){slideTo(this.abbr)}
};
}));
}
function addChaptersToScope(response) {
$scope.books = response[0];
$scope.chapters = response[1].map(function(chapter) {
return {
name: response[0][chapter.book].abbreviation + "-" + chapter.chapter + ": " + chapter.title,
url: "http://awoiaf.westeros.org/index.php/"+chapter.awoiaf
};
});
//console.log("c", $scope.chapters);
$scope.searchResults = $scope.searchResults.concat(response[1].map(function(chapter) {
return {
icon: "glyphicon-book",
title: chapter.title,
subtitle: response[0][chapter.book].title,
search: chapter.title,
abbr: response[0][chapter.book].abbreviation + "-" + chapter.chapter,
click: function(){slideTo(this.abbr)}
};
}));
}
function addCharactersToScope(responses) {
$scope.characters = responses[0].map(function(character) {
var output = {
name: character.name,
url: "http://awoiaf.westeros.org/index.php/" + character.awoiaf,
house: ""
}
if (character.house!="") {
matchingHouse = $filter('filter')(responses[1], {wikiKey: character.house})[0];
output.house = {
name: decodeURI(matchingHouse.wikiKey).replace(/_/g," "),
url: "http://awoiaf.westeros.org/index.php/" + matchingHouse.wikiKey,
img: matchingHouse.img
}
}
return output;
});
}
function addRegionsToScope(responses) {
// console.log("regions", responses[0]);
// console.log("borders", responses[1]);
var borderArrays = {};
for (var i=0; i<responses[1].length; i++) {
if (!(responses[1][i].name in borderArrays)) borderArrays[responses[1][i].name] = [];
borderArrays[responses[1][i].name].push(responses[1][i]);
}
$scope.map.regions = responses[0].map(function(region) {
return {
key: region.name,
fill: {
color: region.color,
opacity: 0.5
},
stroke: {
weight: 0
},
path: borderArrays[region.name]
};
});
}
function createLocationMarkers(responses) {
$scope.houses = responses[1];
$scope.map.locations = qmCsv.setHomes(responses[0], responses[1]);
//console.log("locations", $scope.map.locations);
$scope.searchResults = $scope.searchResults.concat($scope.map.locations.map(function(location) {
return {
icon: "glyphicon-map-marker",
key: location.key,
title: location.name,
subtitle: (location.occupants.length) ? location.occupants[0].name : "",
search: (location.occupants.length) ? location.name + " " + location.occupants[0].name : location.name,
click: function(){panTo(this.key)}
};
}));
}
function locationClick(marker, eventName, model) {
model.currentOccupant = qmCsv.getCurrentOccupant(model);
$scope.locationDetail = model;
$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>";
}
});
+146
View File
@@ -0,0 +1,146 @@
angular.module('quartermaester')
.factory('smgMapType', function() {
return {
getTile: getTile,
tileSize: {height:256, H:"px", width:256, W:"px"},
name: 'Planetos',
radius: 1738000
};
function getTile(coord, zoom, ownerDocument) {
if (isOutsideTileRange(coord,zoom)) return false;
var div = ownerDocument.createElement('div');
div.style.width = '256px';
div.style.height = '256px';
div.style.backgroundImage = "url('tiles/" + getTileCode(coord,zoom) + ".jpg')";
return div;
}
function isOutsideTileRange(coord,zoom) {
var tileRange = 1 << zoom;
if (coord.x < 0 || coord.x >= tileRange) return true;
if (coord.y < 0 || coord.y >= tileRange) return true;
return false;
}
function getTileCode(a,b) {
//converts tile x,y into keyhole string
var c=Math.pow(2,b);
var d=a.x;
var e=a.y;
var f="t";
for(var g=0;g<b;g++){
c=c/2;
if(e<c){
if(d<c){f+="q"}
else{f+="r";d-=c}
}
else{
if(d<c){f+="t";e-=c}
else{f+="s";d-=c;e-=c}
}
}
return f;
}
})
.factory('qmCsv', function($http, $filter, fCsv) {
var csvLocation = "http://www.rslc.us/quartermaester/data/";
return {
get: getFile,
setHomes: setHomes,
getCurrentOccupant: getCurrentOccupant
};
///////////////////////////////
function getFile(filename) {
return $http
.get(csvLocation + filename)
.then(getDataAttr)
.then(fCsv.toJson)
.then(angular.fromJson)
}
function getDataAttr(resp) {
return resp.data;
}
function setHomes(locations, houses) {
//console.log(locations, houses);
var markers = locations.map(locationModel);
for (var i=0; i<markers.length; i++) {
var matchingHouses = $filter('filter')(houses, {seatKey: locations[i].key});
markers[i].occupants = matchingHouses.map(function(house) {
return {
name: decodeURI(house.wikiKey).replace(/_/g," "),
url: "http://awoiaf.westeros.org/index.php/" + house.wikiKey,
img: house.img,
firstChapter: parseInt(house.firstChapter, 10) || null,
lastChapter: parseInt(house.lastChapter, 10) || null,
firstEpisode: parseInt(house.firstEpisode, 10) || null,
lastEpisode: parseInt(house.lastEpisode, 10) || null
}
});
}
return markers;
}
function locationModel(json) {
return {
key: json.key,
name: decodeURI(json.key).replace(/_/g," "),
url: "http://awoiaf.westeros.org/index.php/" + json.key,
direct: "#@" + json.key,
coords: {
latitude: parseFloat(json.latitude),
longitude: parseFloat(json.longitude)
},
options: {
icon: {path: 0, strokeOpacity: 0, scale: 3}
},
occupants: []
};
}
function getCurrentOccupant(marker) {
if (marker.occupants.length==0) return null;
if (marker.occupants.length==1) return marker.occupants[0];
return $filter('qmSlider')(marker.occupants, "episodes", 0)[0];
}
})
.filter('qmSlider', function() {
// 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
return function(inputArray, slider, value) {
outputArray = [];
for (var i=0; i<inputArray.length; i++) {
switch (slider) {
case "episodes":
if (inputArray[i].firstEpisode==null || (value>=inputArray[i].firstEpisode && value<=inputArray[i].lastEpisode)) outputArray.push(inputArray[i]);
break;
case "chapters":
if (inputArray[i].firstChapter==null || (value>=inputArray[i].firstChapter && value<=inputArray[i].lastChapter)) outputArray.push(inputArray[i]);
break;
}
}
return outputArray;
}
});
+10
View File
File diff suppressed because one or more lines are too long