Skip to content

Instantly share code, notes, and snippets.

@MrHen
Last active November 26, 2015 19:25
Show Gist options
  • Save MrHen/435aad414c87921b3bb3 to your computer and use it in GitHub Desktop.
Save MrHen/435aad414c87921b3bb3 to your computer and use it in GitHub Desktop.
Incremental game graph
body {
background: darkgrey;
}
.app-container {
margin: 2em;
}
.incremental-container {
max-width: 600px;
}
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdge;
}
.axis text {
font-family: sans-serif;
font-size: 10px;
}
.tick {
stroke-dasharray: 1, 2;
}
var app = angular.module('incrementalApp', []);
app.controller('GameController', ['$scope', '$interval', function($scope, $interval) {
$scope.numWidgets = 0;
$scope.costScaling = 1.1;
$scope.widgeteers = [{
"name": "novice-widgeteer",
"label": "Hire Novice Widgeteer",
"cost": 10,
"value": 1,
"owned": 0,
}, {
"name": "master-widgeteer",
"label": "Hire Master Widgeteer",
"cost": 25,
"value": 5,
"owned": 0,
}, {
"name": "wisened-widgeteer",
"label": "Hire Wisened Widgeteer",
"cost": 100,
"value": 10,
"owned": 0,
}];
// Increase numWidgets every time produce-widget is clicked
$scope.produceWidget = function() {
$scope.numWidgets++;
}
// Same for novice-widgeteer
$scope.hireWidgeteer = function(widgeteer) {
widgeteer.owned++;
$scope.numWidgets -= widgeteer.cost;
widgeteer.cost = Math.ceil(widgeteer.cost * 1.1);
}
// Run UI update code every 10ms
$interval(function() {
for (var i = 0; i < $scope.widgeteers.length; i++) {
$scope.numWidgets += ($scope.widgeteers[i].owned * $scope.widgeteers[i].value / 100);
}
}, 10);
}]);
app.controller('ChartController', ['$scope', '$interval', function($scope, $interval) {
$scope.startTime = null;
$scope.values = [];
$scope.lastValue = $scope.numWidgets;
// Run UI update code every 10ms
$interval(function() {
if ($scope.lastValue != $scope.numWidgets) {
if (!$scope.startTime) {
$scope.startTime = Date.now();
}
addValue($scope.numWidgets);
}
}, 10);
function addValue(value, time) {
time = time || (Date.now() - $scope.startTime);
$scope.values.push({
time: time,
value: angular.copy(value)
});
$scope.lastValue = value;
}
}]);
app.directive('linearChart', function($parse, $window) {
return {
restrict: 'EA',
template: "<svg width='500' height='300'></svg>",
link: function(scope, elem, attrs) {
var exp = $parse(attrs.chartData);
var chartData = exp(scope);
var padding = 30;
var pathClass = "path";
var xScale, yScale, xAxisGen, yAxisGen, lineFun;
var d3 = $window.d3;
var rawSvg = elem.find('svg');
var svg = d3.select(rawSvg[0]);
var height = rawSvg.attr("height");
var width = rawSvg.attr("width");
scope.$watchCollection(exp, function(newVal, oldVal) {
chartData = newVal;
redrawLineChart();
});
drawLineChart();
function setChartParameters() {
var xMin = chartData.length ? chartData[0].time / 1000: 0;
var xMax = chartData.length ? chartData[chartData.length - 1].time / 1000 : 0;
xScale = d3.scale.linear()
.domain([xMin, xMax])
.range([padding + 5, width - padding]);
yScale = d3.scale.linear()
.domain([0, d3.max(chartData, function(d) {
return d.value;
})])
.range([height - padding * 2, 0]);
xAxisGen = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(10);
yAxisGen = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(5);
lineFun = d3.svg.line()
.x(function(d) {
return xScale(d.time / 1000);
})
.y(function(d) {
return yScale(d.value);
})
.interpolate("basis");
}
function drawLineChart() {
setChartParameters();
svg.append("svg:g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height - 30) + ")")
.call(xAxisGen);
svg.append("svg:g")
.attr("class", "y axis")
.attr("transform", "translate(" + padding + "," + padding + ")")
.call(yAxisGen);
svg.append("svg:path")
.attr("transform", "translate(0," + padding + ")")
.attr({
d: lineFun(chartData),
"stroke": "blue",
"stroke-width": 2,
"fill": "none",
"class": pathClass
});
}
function redrawLineChart() {
setChartParameters();
svg.selectAll("g.y.axis").call(yAxisGen);
svg.selectAll("g.x.axis").call(xAxisGen);
svg.selectAll("." + pathClass)
.attr({
d: lineFun(chartData)
});
}
}
}
});
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" integrity="sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="game.css">
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.1/angular.js"></script>
<script type="text/javascript" src="//code.jquery.com/jquery-2.1.0.js"></script>
<script src="//d3js.org/d3.v3.js"></script>
<script type="text/javascript" src="game.js"></script>
</head>
<body>
<div class="app-container" ng-app="incrementalApp">
<div class="incremental-container center-block" ng-controller="GameController">
<div class="panel panel-default">
<h2 id="widget-count" class="panel-heading panel-title text-center">
Widgets: {{numWidgets | number: 0}}
</h2>
<div class="panel-body">
<button class="btn btn-primary btn-block" id="produce-widget" ng-click="produceWidget()">Produce Widget</button>
</div>
</div>
<div class="panel panel-default">
<h2 class="panel-heading panel-title text-center">
Store
</h2>
<div class="list-group">
<button class="list-group-item btn" ng-repeat="widgeteer in widgeteers" ng-click="hireWidgeteer(widgeteer)" ng-disabled="widgeteer.cost > numWidgets">{{widgeteer.label}} - {{widgeteer.cost}}</button>
</div>
</div>
<div class="panel panel-default">
<h2 class="panel-heading panel-title text-center">
Graph
</h2>
<div class="panel-body">
<div class="graph-container" ng-controller="ChartController">
<div linear-chart chart-data="values"></div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
d3.select(self.frameElement).style("height", "1000px");
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment