Skip to content

Instantly share code, notes, and snippets.

@mtaptich
Last active March 16, 2016 00:57
Show Gist options
  • Select an option

  • Save mtaptich/397426e88385a2a5d82a to your computer and use it in GitHub Desktop.

Select an option

Save mtaptich/397426e88385a2a5d82a to your computer and use it in GitHub Desktop.
Solve a Linear Program

A simple, 'hands-on' example of solving a linear mathematical program using d3.js + Angular.js.

/****** dropdown-select *******/
.wrap-dd-select {
/* Size and position */
position: relative;
width: 80px;
margin: 0 auto;
padding: 5px 10px;
padding-right: 35px;
margin-top: -6px;
-webkit-user-select:none;
-moz-user-select:none;
user-select:none;
/* Styles */
background: #fff;
border-radius: 7px;
border: 1px solid rgba(0,0,0,0.15);
box-shadow: 0 1px 1px rgba(50,50,50,0.1);
cursor: pointer;
outline: none;
/* Font settings */
font-weight: bold;
color: #000;
font-size: 20px;
display: inline-block;
}
.wrap-dd-select:after {
content: "";
width: 0;
height: 0;
position: absolute;
right: 15px;
top: 50%;
margin-top: -3px;
border-width: 6px 6px 0 6px;
border-style: solid;
border-color: #8aa8bd transparent;
}
.wrap-dd-select .dropdown {
/* Size & position */
position: absolute;
top: 100%;
left: 0;
right: 0;
z-index: 1000;
/* Styles */
background: white;
padding: 0;
border-radius: inherit;
border: 1px solid rgba(0,0,0,0.17);
box-shadow: 0 0 5px rgba(0,0,0,0.1);
font-weight: normal;
transition: all 0.2s ease-in;
list-style: none;
/* Hiding */
opacity: 0;
pointer-events: none;
}
.wrap-dd-select .dropdown li.divider {
padding: 2px 0;
background: #e6e8ea;
}
.wrap-dd-select .dropdown li a {
display: block;
padding: 5px 10px;
text-decoration: none;
color: #8aa8bd;
border-bottom: 1px solid #e6e8ea;
box-shadow: inset 0 1px 0 rgba(255,255,255,1);
transition: all 0.3s ease-out;
}
.wrap-dd-select .dropdown li i {
float: right;
color: inherit;
}
.wrap-dd-select .dropdown li:first-of-type a {
border-radius: 7px 7px 0 0;
}
.wrap-dd-select .dropdown li:last-of-type a {
border-radius: 0 0 7px 7px;
border: none;
}
/* Hover state */
.wrap-dd-select .dropdown li:hover a {
background: #f3f8f8;
}
.wrap-dd-select .dropdown:after {
content: "";
width: 0;
height: 0;
position: absolute;
bottom: 100%;
right: 15px;
border-width: 0 6px 6px 6px;
border-style: solid;
border-color: #fff transparent;
}
.wrap-dd-select .dropdown:before {
content: "";
width: 0;
height: 0;
position: absolute;
bottom: 100%;
right: 13px;
border-width: 0 8px 8px 8px;
border-style: solid;
border-color: rgba(0,0,0,0.1) transparent;
}
.wrap-dd-select.active .dropdown {
opacity: 1;
pointer-events: auto;
}
/****** dropdown-menu *******/
.wrap-dd-menu {
/* Size and position */
position: relative;
z-index: 1000;
width: 200px;
margin: 0 auto;
padding: 10px;
}
.wrap-dd-menu .dropdown {
/* Size & position */
position: absolute;
z-index: 1000;
top: 70%;
left: 0;
right: 0;
/* Styles */
background: white;
padding: 0;
border-radius: 7px;
border: 1px solid rgba(0,0,0,0.17);
box-shadow: 0 0 5px rgba(0,0,0,0.1);
font-weight: normal;
transition: all 0.2s ease-in;
list-style: none;
/* Hiding */
opacity: 0;
pointer-events: none;
}
.wrap-dd-menu .dropdown li.divider {
padding: 2px 0;
background: #e6e8ea;
}
.wrap-dd-menu .dropdown li a {
display: block;
padding: 10px;
text-decoration: none;
color: #8aa8bd;
border-bottom: 1px solid #e6e8ea;
box-shadow: inset 0 1px 0 rgba(255,255,255,1);
transition: all 0.3s ease-out;
}
.wrap-dd-menu .dropdown li i {
float: right;
color: inherit;
}
.wrap-dd-menu .dropdown li:first-of-type a {
border-radius: 7px 7px 0 0;
}
.wrap-dd-menu .dropdown li:last-of-type a {
border-radius: 0 0 7px 7px;
border: none;
}
/* Hover state */
.wrap-dd-menu .dropdown li:hover a {
background: #f3f8f8;
}
.wrap-dd-menu .dropdown:after {
content: "";
width: 0;
height: 0;
position: absolute;
bottom: 100%;
border-width: 0 6px 6px 6px;
border-style: solid;
border-color: #fff transparent;
}
.wrap-dd-menu .dropdown:before {
content: "";
width: 0;
height: 0;
position: absolute;
bottom: 100%;
right: 95px;
border-width: 0 8px 8px 8px;
border-style: solid;
border-color: rgba(0,0,0,0.1) transparent;
}
.wrap-dd-menu .dropdown.active {
opacity: 1;
pointer-events: auto;
}
/**
* @license MIT http://jseppi.mit-license.org/license.html
*/
(function(window, angular, undefined) {
'use strict';
var dd = angular.module('ngDropdowns', []);
dd.run(['$templateCache', function ($templateCache) {
$templateCache.put('ngDropdowns/templates/dropdownSelect.html', [
'<div class="wrap-dd-select">',
'<span class="selected">{{dropdownModel[labelField]}}</span>',
'<ul class="dropdown">',
'<li ng-repeat="item in dropdownSelect"',
' class="dropdown-item"',
' dropdown-select-item="item"',
' dropdown-item-label="labelField">',
'</li>',
'</ul>',
'</div>'
].join(''));
$templateCache.put('ngDropdowns/templates/dropdownSelectItem.html', [
'<li ng-class="{divider: dropdownSelectItem.divider}">',
'<a href="" class="dropdown-item"',
' ng-if="!dropdownSelectItem.divider"',
' ng-href="{{dropdownSelectItem.href}}"',
' ng-click="selectItem()">',
'{{dropdownSelectItem[dropdownItemLabel]}}',
'</a>',
'</li>'
].join(''));
$templateCache.put('ngDropdowns/templates/dropdownMenu.html', [
'<ul class="dropdown">',
'<li ng-repeat="item in dropdownMenu"',
' class="dropdown-item"',
' dropdown-item-label="labelField"',
' dropdown-menu-item="item">',
'</li>',
'</ul>'
].join(''));
$templateCache.put('ngDropdowns/templates/dropdownMenuItem.html', [
'<li ng-class="{divider: dropdownMenuItem.divider}">',
'<a href="" class="dropdown-item"',
' ng-if="!dropdownMenuItem.divider"',
' ng-href="{{dropdownMenuItem.href}}"',
' ng-click="selectItem()">',
'{{dropdownMenuItem[dropdownItemLabel]}}',
'</a>',
'</li>'
].join(''));
}]);
dd.directive('dropdownSelect', ['DropdownService',
function (DropdownService) {
return {
restrict: 'A',
replace: true,
scope: {
dropdownSelect: '=',
dropdownModel: '=',
dropdownOnchange: '&'
},
controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
$scope.labelField = $attrs.dropdownItemLabel || 'text';
DropdownService.register($element);
this.select = function (selected) {
if (selected !== $scope.dropdownModel) {
angular.copy(selected, $scope.dropdownModel);
}
$scope.dropdownOnchange({
selected: selected
});
};
$element.bind('click', function (event) {
event.stopPropagation();
DropdownService.toggleActive($element);
});
$scope.$on('$destroy', function () {
DropdownService.unregister($element);
});
}],
templateUrl: 'ngDropdowns/templates/dropdownSelect.html'
};
}
]);
dd.directive('dropdownSelectItem', [
function () {
return {
require: '^dropdownSelect',
replace: true,
scope: {
dropdownItemLabel: '=',
dropdownSelectItem: '='
},
link: function (scope, element, attrs, dropdownSelectCtrl) {
scope.selectItem = function () {
if (scope.dropdownSelectItem.href) {
return;
}
dropdownSelectCtrl.select(scope.dropdownSelectItem);
};
},
templateUrl: 'ngDropdowns/templates/dropdownSelectItem.html'
};
}
]);
dd.directive('dropdownMenu', ['$parse', '$compile', 'DropdownService', '$templateCache',
function ($parse, $compile, DropdownService, $templateCache) {
return {
restrict: 'A',
replace: false,
scope: {
dropdownMenu: '=',
dropdownModel: '=',
dropdownOnchange: '&'
},
controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
$scope.labelField = $attrs.dropdownItemLabel || 'text';
var $template = angular.element($templateCache.get('ngDropdowns/templates/dropdownMenu.html'));
// Attach this controller to the element's data
$template.data('$dropdownMenuController', this);
var tpl = $compile($template)($scope);
var $wrap = angular.element('<div class="wrap-dd-menu"></div>');
$element.replaceWith($wrap);
$wrap.append($element);
$wrap.append(tpl);
DropdownService.register(tpl);
this.select = function (selected) {
if (selected !== $scope.dropdownModel) {
angular.copy(selected, $scope.dropdownModel);
}
$scope.dropdownOnchange({
selected: selected
});
};
$element.bind('click', function (event) {
event.stopPropagation();
DropdownService.toggleActive(tpl);
});
$scope.$on('$destroy', function () {
DropdownService.unregister(tpl);
});
}]
};
}
]);
dd.directive('dropdownMenuItem', [
function () {
return {
require: '^dropdownMenu',
replace: true,
scope: {
dropdownMenuItem: '=',
dropdownItemLabel: '='
},
link: function (scope, element, attrs, dropdownMenuCtrl) {
scope.selectItem = function () {
if (scope.dropdownMenuItem.href) {
return;
}
dropdownMenuCtrl.select(scope.dropdownMenuItem);
};
},
templateUrl: 'ngDropdowns/templates/dropdownMenuItem.html'
};
}
]);
dd.factory('DropdownService', ['$document',
function ($document) {
var body = $document.find('body'),
service = {},
_dropdowns = [];
body.bind('click', function () {
angular.forEach(_dropdowns, function (el) {
el.removeClass('active');
});
});
service.register = function (ddEl) {
_dropdowns.push(ddEl);
};
service.unregister = function (ddEl) {
var index;
index = _dropdowns.indexOf(ddEl);
if (index > -1) {
_dropdowns.splice(index, 1);
}
};
service.toggleActive = function (ddEl) {
angular.forEach(_dropdowns, function (el) {
if (el !== ddEl) {
el.removeClass('active');
}
});
ddEl.toggleClass('active');
};
return service;
}
]);
})(window, window.angular);
<html>
<head>
<!-- CSS -->
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
<link href="angular-dropdowns.css" rel="stylesheet">
<link href="style.css" rel="stylesheet">
<!-- JS -->
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.18/angular.min.js"></script>
<script src="angular-dropdowns.js"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body ng-app="LPapp" ng-controller="LPcontroller">
<h2>Objective Value: &nbsp; Z = {{xobj+"x +"+yobj+"y = "}} <span ng-style="UporDown">{{(xobj*Z.x + yobj*Z.y | number : 5)}}</span></h2>
<div class="row">
<div style="float: left;">
<div linear-chart chart-data="lines"></div>
</div>
<div style="float: right; margin-top:25px">
<div>
<form >
<span style="font-weight: bold;">OBJ: &nbsp;</span>
<div dropdown-select="objOptions" dropdown-model="objSelected" class="btn" ></div> &nbsp;
<input type="text" ng-model="xobj" size="3"
placeholder="Cx">&nbsp;x +
<input type="text" ng-model="yobj" size="3"
placeholder="Cy">&nbsp;y &nbsp
</form>
</div>
<span style="font-weight: bold;">Subject to:</span>
<br>
<ul class="unstyled">
<li ng-repeat="constraint in constraints">
<span>{{constraint.text}}</span>
</li>
</ul>
<div>
<form ng-submit="addconstraint()">
<input type="text" ng-model="xconstraint" size="3"
placeholder="Ax">&nbsp;x +
<input type="text" ng-model="yconstraint" size="3"
placeholder="Ay">&nbsp;y &nbsp
<div dropdown-select="ddSelectOptions" dropdown-model="ddSelectSelected" class="btn"></div> &nbsp;
<input type="text" ng-model="bconstraint" size="3"
placeholder="b">
<input class="btn" type="submit" value="add">
</form>
<div class="clear">
[ <a href="" ng-click="poplast()">undo</a> ] &nbsp [ <a href="" ng-click="clear()">clear</a> ]
</div>
</div>
</div>
</div>
<p style="font-size: 0.9em;"> (Hint: If you over-constrain your circle, click the feasile region and it will reappear.)</p>
<p>Drag the blue ball to the coordinate in the x-y space that optimizes each linear program. Feel free to build your own problems, too. Examples: <a data-id='ex22' ng-click='updateexample($event)'>Problem 1</a>, <a data-id='ex23' ng-click='updateexample($event)'>Problem 2</a>. </p>
</body>
<!-- Angular.js APP -->
<script type="text/javascript">
var app = angular.module('LPapp', ['ngDropdowns'])
app.controller('LPcontroller', ['$scope', function($scope) {
$scope.example = "ex21"
$scope.options = {"ex21": [{text: "x >= 0"}, {text: "x <= 10"},{text: "y >= 0"}, {text: "y <= 10"}], "ex22": [{text: "x >= 0"}, {text: "x <= 10"},{text: "y >= 0"}, {text: "y <= 10"}, {text: "1x + 1y <= 12"}, {text: "3x + 1y <= 25"}] }
$scope.constraints = [{text: "x >= 0"}, {text: "x <= 10"},{text: "y >= 0"}, {text: "y <= 10"}];
$scope.lines = [];
$scope.obj = []
$scope.yconstraint = '';
$scope.xconstraint = '';
$scope.bconstraint = '';
$scope.yobj = 1;
$scope.xobj = 1;
$scope.UporDown = {color:'#000'}
$scope.xybound = [{x: -1, y: 0, b:0, sign:"<="}, {x: 1, y: 0, b:10, sign:"<="}, {x: 0, y: -1, b:0, sign:"<="},{x: 0, y: 1, b:10, sign:"<="}];
$scope.Z = {x: 0, y:0};
$scope.updateexample = function(obj){
$scope.example = obj.target.attributes["data-id"].value;
}
$scope.addconstraint = function() {
if($scope.xconstraint !="" && $scope.yconstraint !="" && $scope.bconstraint !=""){
array = [$scope.xconstraint, $scope.yconstraint]
$scope.constraints.push(
{
text:array[0]+"x + "+array[1]+"y "+$scope.ddSelectSelected.text+" "+$scope.bconstraint
}
);
if ($scope.yconstraint == 0) $scope.yconstraint = 0.00005;
$scope.lines.push([
{
xdata: 0, ydata: +$scope.bconstraint / +$scope.yconstraint, bdata: +$scope.bconstraint, sign: $scope.ddSelectSelected.text
},
{
xdata: 10, ydata: (+$scope.bconstraint -10*+$scope.xconstraint) / +$scope.yconstraint, bdata: +$scope.bconstraint, sign:$scope.ddSelectSelected.text
}]
)
$scope.xybound.push({x:$scope.xconstraint, y:$scope.yconstraint, b:$scope.bconstraint, sign:$scope.ddSelectSelected.text})
$scope.yconstraint = '';
$scope.xconstraint = '';
$scope.bconstraint = '';
}
};
$scope.clear = function() {
$scope.constraints = [{text: "x >= 0"}, {text: "x <= 10"},{text: "y >= 0"}, {text: "y <= 10"}];
$scope.lines = [];
$scope.myStyle = {color:'#C33851', background:'#fff', borderColor: 'red'}
$scope.yobj = 1;
$scope.xobj = 1;
$scope.xybound = [{x: -1, y: 0, b:0, sign:"<="}, {x: 1, y: 0, b:10, sign:"<="}, {x: 0, y: -1, b:0, sign:"<="},{x: 0, y: 1, b:10, sign:"<="}];
d3.selectAll(".area").remove()
d3.selectAll(".line").remove()
if(d3.select("#linearChart circle")[0][0] != null){
d3.select("#linearChart circle")[0][0].__data__.y = 330;
d3.select("#linearChart circle")[0][0].__data__.x = 0;
d3.select("#linearChart circle").transition().duration(300).attr("cx", 0).attr("cy", 330)
}
};
$scope.poplast = function(){
if($scope.constraints.length > 4){
var a = $scope.constraints.slice(0,-1)
var b = $scope.lines.slice(0,-1)
var c = $scope.xybound.slice(0,-1)
$scope.constraints = a;
$scope.lines = b;
$scope.xybound = c;
}
}
$scope.ddSelectOptions = [
{
text: '<=',
},
{
text: '>=',
}
];
$scope.ddSelectSelected = { text: '<='};
$scope.objOptions = [
{
text: 'min',
},
{
text: 'max',
}
];
$scope.objSelected = { text: 'max'}; // Must be an object
}])
app.directive("linearChart", function($parse, $window) {
return{
restrict: "EA",
template: "<svg id='linearChart' width='600' height='400'></svg>",
link: function(scope, elem, attrs){
var margin = {top: 20, right: 20, bottom: 50, left: 50},
width = 600 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom,
xAxis, yAxis, line, x, ylc, line, areaup, clip, drag
var d3 = $window.d3;
var svg = d3.select("#linearChart").append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var clip = svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("id", "clip-rect")
.attr("x", "0")
.attr("y", "0")
.attr("width", width)
.attr("height", height);
svg.append('svg:rect')
.attr('width', width)
.attr('height', height)
.attr('fill', '#eee')
.on("click", function(){
if (d3.select("circle")[0][0] == null){
var a = d3.mouse(this);
svg.append("g")
.attr("class", "dot")
.selectAll("circle")
.data([{x: a[0], y: a[1]}])
.enter().append("circle")
.attr("r", 5)
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.call(drag);
}
})
var exp = $parse(attrs.chartData);
var DataToPlot=exp(scope);
// Update the constraints
scope.$watchCollection(exp, function(newVal, oldVal) {
var e = scope.xybound[scope.xybound.length - 1];
var cx = d3.select("#linearChart circle")[0][0].__data__.x
var cy = d3.select("#linearChart circle")[0][0].__data__.y
if (e.sign == "<="){
if (e.x * x.invert(cx) + e.y * ylc.invert(cy) > e.b){
d3.select("#linearChart circle").transition().duration(500).attr("r", 10).transition().duration(300).attr("r", 1).remove()
}
DataToPlot = newVal;
drawline();
} else{
if (e.x * x.invert(cx) + e.y * ylc.invert(cy) < e.b){
d3.select("#linearChart circle").transition().duration(300).attr("r", 8).transition().duration(300).attr("r", 1).remove()
}
DataToPlot = newVal;
drawline();
}
});
//Load Examples
scope.$watch("example", function(oldVal, newVal){
scope.clear()
if(scope.example =="ex22"){
d3.select("#linearChart circle")[0][0].__data__.y = ylc(4);
d3.select("#linearChart circle")[0][0].__data__.x = x(4);
d3.select("#linearChart circle").transition().duration(300).attr("cx", x(4)).attr("cy", ylc(4));
scope.yobj = -2;
scope.objSelected = { text: 'min'};
scope.constraints.push({text: "1x + 1y <= 12"}, {text: "3x + 1y <= 25"}, {text: "-2x + 1y <= 5"}, {text: "3x + 1y >= 6"});
scope.lines = [[{xdata: 12, ydata: 0, bdata: 12, sign:"<="}, {xdata: 0, ydata: 12, bdata: 12, sign:"<="}], [{xdata: 0, ydata: 25, bdata: 25, sign:"<="}, {xdata: 10, ydata: -5, bdata: 25, sign:"<="}],[{xdata: 0, ydata: 5, bdata: 5, sign:"<="}, {xdata: 10, ydata: 25, bdata: 5, sign:"<="}], [{xdata: 0, ydata: 6, bdata: 6, sign:">="}, {xdata: 10, ydata: -24, bdata: 6, sign:">="}]]
scope.xybound.push({x: 1, y: 1, b:12, sign:"<="},{x: 3, y: 1, b:25, sign:"<="},{x: -2, y: 1, b:5, sign:"<="}, {x: 3, y: 1, b:6, sign:">="})
} else if (scope.example =="ex23"){
d3.select("#linearChart circle")[0][0].__data__.y = ylc(5);
d3.select("#linearChart circle")[0][0].__data__.x = x(5);
d3.select("#linearChart circle").transition().duration(300).attr("cx", x(5)).attr("cy", ylc(5));
scope.xobj = -1;
scope.yobj = 1;
scope.objSelected = { text: 'min'};
scope.constraints.push({text: "0x + 1y <= 8"}, {text: "10x + 1y >= 10"}, {text: "-30x + 9y <= 30"}, {text: "0x + 1y >= 2"});
scope.lines = [[{xdata: 0, ydata: 8, bdata: 8, sign:"<="}, {xdata: 10, ydata: 8, bdata: 8, sign:"<="}], [{xdata: 0, ydata: 10, bdata: 10, sign:">="}, {xdata: 10, ydata: -90, bdata: 10, sign:">="}], [{xdata: 10, ydata: 36.666666666666666666, bdata: 30, sign:"<="}, {xdata: 0, ydata: 3.333333333333333333, bdata: 30, sign:"<="}], [{xdata: 10, ydata: 2, bdata: 2, sign:">="}, {xdata: 0, ydata: 2, bdata: 2, sign:">="}]]
scope.xybound.push({x: 0, y: 1, b:8, sign:"<="}, {x: 10, y: 1, b:10, sign:">="}, {x: -30, y: 9, b:30, sign:"<="}, {x: 0, y: 1, b:2, sign:">="})
}
drawline()
})
// Update the style of the objective result
scope.$watchGroup(["Z.x","Z.y"], function(newVal, oldVal) {
if(scope.objSelected.text =="max"){
if((scope.xobj*newVal[0] + scope.yobj*newVal[1]) > (scope.xobj*oldVal[0] + scope.yobj*oldVal[1])){
scope.UporDown = {color:'green'}
}else{
scope.UporDown = {color:'red'}
}
} else{
if((scope.xobj*newVal[0] + scope.yobj*newVal[1]) < (scope.xobj*oldVal[0] + scope.yobj*oldVal[1])){
scope.UporDown = {color:'green'}
}else{
scope.UporDown = {color:'red'}
}
}
});
function drawLineChart() {
x = d3.scale.linear()
.range([0, width])
.domain([0,10])
ylc = d3.scale.linear()
.range([height, 0])
.domain([0,10])
line = d3.svg.line()
.x(function(d) { return x(+d.xdata); })
.y(function(d) { return ylc(+d.ydata); });
areaup = d3.svg.area()
.x(function(d) { return x(+d.xdata); })
.y0(function(d) { return ylc(+d.ydata)})
.y1(function(d){
if (d.sign =="<="){
return ylc(10);
} else if(d.sign ==">="){
return ylc(0);
}
});
xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5);
yAxis = d3.svg.axis()
.scale(ylc)
.orient("left")
.ticks(5);
drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged)
.on("dragend", dragended);
svg.append("svg:g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", +40)
.style("text-anchor", "end")
.text("x");
svg.append("svg:g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", -50)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("y");
svg.append("g")
.attr("class", "dot")
.selectAll("circle")
.data([{x: 0, y: height}])
.enter().append("circle")
.attr("r", 5)
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.call(drag);
function checkbounds(e, index, array){
if (e.sign =="<="){
return e.x * x.invert(d3.event.x) + e.y * ylc.invert(d3.event.y) <= e.b
} else{
return e.x * x.invert(d3.event.x) + e.y * ylc.invert(d3.event.y) >= e.b
}
}
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
d3.select(this).classed("dragging", true);
}
function dragged(d) {
if(scope.xybound.every(checkbounds)){
d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
scope.Z.x = x.invert(d3.event.x);
scope.Z.y = ylc.invert(d3.event.y);
scope.$apply()
}
}
function dragended(d) {
d3.select(this).classed("dragging", false);
}
}
function drawline(){
d3.selectAll(".area").remove()
d3.selectAll(".line").remove()
svg.selectAll("areas")
.data(DataToPlot).enter()
.append("path")
.attr("class", "area")
.attr("d", areaup)
.attr("clip-path", "url(#clip)");
svg.selectAll(".lines")
.data(DataToPlot).enter()
.append("path")
.attr("class", "line")
.attr("d", line)
.attr("clip-path", "url(#clip)");
}
drawLineChart()
}
};
})
d3.select(self.frameElement).style("height", " 700px");
</script>
</html>
body {
width: 960px;
margin-top: 0;
margin: auto;
font-family: "Lato", "PT Serif", serif;
color: #222222;
padding: 0;
font-weight: 300;
line-height: 33px;
-webkit-font-smoothing: antialiased;
}
p {
font-size: 20px;
display: block;
-webkit-margin-before: 1em;
-webkit-margin-after: 1em;
-webkit-margin-start: 0px;
-webkit-margin-end: 0px;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
}
.x.axis text, .y.axis text{
font-size: 20px;
font-weight: normal;
}
.line, .xpline{
fill: none;
stroke: #000;
stroke-dasharray: 10px 1px;
stroke-width: 2px;
}
.pairs{
fill: none;
stroke: #000;
stroke-dasharray: 3px 3px;
stroke-width: 3px;
}
.clear{
text-align: right
}
.area, .xp{
fill-opacity: 0.9;
fill:#fff;
}
.dot{
fill: #2966C0;
}
.boundsunder path, .boundsunder line {
fill: none;
stroke: #eee;
stroke-width: 3px;
}
.bounds {
stroke: #000;
stroke-width: 5px;
}
.dial{
fill: #B22222;
}
.paired{
width:100%;
}
.paired .simplechart{
float: left;
width:50%;
}
.clear {
clear: both;
}
.space{
margin-top: 30px;
}
.boundedarea{
fill: #B22222;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment