Skip to content

Commit

Permalink
feat(visualise) Binding the visulize page to API
Browse files Browse the repository at this point in the history
Additionally, the correct lane of tiles is now shown in the distributionVisualisation control.

Additionally, a bug was fixed in the  `d3.selection.prototype.clipPath` function on https://github.com/QutBioacoustics/baw-client/blob/visualize-use-real-data/src/components/services/vendorServices/externals.js#L71
  • Loading branch information
atruskie committed Feb 25, 2015
1 parent 96c6267 commit 2272310
Show file tree
Hide file tree
Showing 9 changed files with 261 additions and 28 deletions.
10 changes: 10 additions & 0 deletions src/app/d3Bindings/eventDistribution/distributionDetail.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ angular
this.minimum = null;
this.maximum = null;
this.visibleExtent = null;
this.selectedCategory = null;

// init
create();
Expand Down Expand Up @@ -186,6 +187,7 @@ angular
that.lanes = data.lanes || [];
that.maximum = data.maximum;
that.minimum = data.minimum;
that.selectedCategory = that.lanes[0];
}

function updateScales() {
Expand Down Expand Up @@ -338,6 +340,14 @@ angular
// updates the public visibleExtent field - has no effect on the graph
that.visibleExtent = domain;

// update public field - this will allow us to switch which
// lane is shown based on where an interaction happens on the drawing surface
var mouseY = d3.mouse(main[0][0])[1],
inverted = yScale.invert(mouseY),
rounded = Math.floor(inverted);
that.selectedCategory = that.lanes[rounded];


// updates the controller - bind back
dataFunctions.extentUpdate(that.visibleExtent, "DistributionDetail");

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

<div class="metaTrack">
meta data tracks
<!--meta data tracks-->
</div>
<div class="imageTrack">
<div class="tiles">
Expand All @@ -17,7 +17,7 @@
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<svg height="256px" width="60px" >
<image xlink:href="assets/temp/tiles/tile_0.png" x="0" y="0" height="256px" width="60px" />
</svg>
<!--<svg height="256px" width="60px" >-->
<!--<image xlink:href="assets/temp/tiles/tile_0.png" x="0" y="0" height="256px" width="60px" />-->
<!--</svg>-->
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ angular
$scope.options.functions.extentUpdate = function (newExtent, source) {
var difference = newExtent[1] - newExtent[0];
var humanDuration = difference === 0 ? "" : moment.duration(difference).humanize();
var selectedLane = that.detail.selectedCategory || that.data.lanes[0] || "";

if (source != "DistributionOverview") {
that.overview.updateExtent(newExtent);
Expand All @@ -56,8 +57,7 @@ angular
that.detail.updateExtent(newExtent);
}
if (source != "DistributionVisualisation") {
// TODO: fix 2nd arg
that.visualisation.updateMiddle(middlePointBetweenDates(newExtent), "NE Site");
that.visualisation.updateMiddle(middlePointBetweenDates(newExtent), selectedLane);
var visualizationMiddle = that.visualisation.visibleDuration;
var humanized = visualizationMiddle && moment.duration(visualizationMiddle, "seconds").humanize() || "";
}
Expand All @@ -67,6 +67,7 @@ angular
$scope.options.overviewExtent = newExtent;
$scope.options.detailDuration = humanDuration;
$scope.options.visualizationDuration = humanized;
$scope.options.selectedLane = selectedLane;
}

if (!$scope.$root.$$phase) {
Expand Down
8 changes: 7 additions & 1 deletion src/app/visualize/_visualize.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@
}

small {

.projectSiteList {
border-left: $gray-lighter solid 1px;
border-bottom: $gray-lighter solid 1px;
border-right: $gray-lighter solid 1px;
padding: 1px;
margin-right: 1em;
}
}
}
}
Expand Down
187 changes: 177 additions & 10 deletions src/app/visualize/visualize.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,89 @@ angular
"VisualizeController",
[
"$scope",
"$routeParams",
"$http",
function ($scope, $http) {
"$q",
"lodash",
"conf.paths",
"Project",
"Site",
"AudioRecording",
function ($scope, $routeParams, $http, $q, _, paths, Project, Site, AudioRecording) {

var sitesMap = {};

// testing data
$scope.recordingData = [];
$http.get("assets/temp/dummyData.json").then(function (response) {
$scope.recordingData = response.data;
}, function () {
console.error("loading dummy data failed", arguments);
});
$scope.errorState = undefined;
$scope.filterType = null;
$scope.sites = [];
$scope.projects = [];


var parameters = validateParameters();

// only start downloading if parameters are valid
if (!parameters.error) {
var chain;
if (parameters.projectFirst) {
chain = Site.getSitesByProjectIds(parameters.ids);
}
else {
chain = Site.getSitesByIds(parameters.ids);
}

chain.then(sitesRetrieved)
.then(getOtherData)
.then(processOtherData, function error() {
if (!$scope.errorState) {
$scope.errorState = "an unknown error occurred";
}
console.error("Visualise data promise chain failure", arguments);
}
);
}

/*
$http.get("assets/temp/dummyData.json").then(function (response) {
$scope.recordingData = response.data;
}, function () {
console.error("loading dummy data failed", arguments);
});
*/

// options that bind the generic event distribution
// controls to our particular data structures
$scope.distributionOptions = {
functions: {
getId: function (d) {
return d.audioId;
return d.id;
},
getCategory: function (d) {
return d.siteName;
return sitesMap[d.siteId].name;
},
getLow: function (d) {
if ((typeof d.recordedDate) === "string") {
d.recordedDate = new Date(d.recordedDate);
}

if (d.minimumMilliseconds === undefined) {
d.minimumMilliseconds = d.recordedDate.getTime();
}

return d.minimumMilliseconds;
},
getHigh: function (d) {
if ((typeof d.durationSeconds) === "string") {
d.durationSeconds = Number(d.durationSeconds);
}

if (d.durationMilliseconds === undefined) {
d.durationMilliseconds = d.durationSeconds * 1000;
}
return this.getLow(d) + d.durationMilliseconds;
},
getText: function (d) {
return d.audioId;
return d.id;
}
}
};
Expand Down Expand Up @@ -77,6 +125,125 @@ angular
title: "Time (hours)"
}
};

$scope.getProjectLink = function(project) {
if (project) {
return paths.api.routes.project.showAbsolute.format({projectId: project.id});
}
};

$scope.getSiteLink = function(project, site) {
if (project && site) {
return paths.api.routes.site.nestedAbsolute.format({siteId: site.id, projectId: project.id});
}
};

$scope.getSitesForProject = function(project) {
return $scope.sites.filter(function(site) {
return site.projectIds.indexOf(project.id) >= 0;
});
};


function validateParameters() {

// parse QSPs
var hasProjectId = $routeParams.hasOwnProperty("projectId");
var hasSiteId = $routeParams.hasOwnProperty("siteId");
var hasSiteIds = $routeParams.hasOwnProperty("siteIds");

// only one QSP is valid
var qspsSet = _.countBy([hasProjectId, hasSiteId, hasSiteIds])["true"];
if (qspsSet !== 1) {
$scope.errorState = (qspsSet === undefined ? "No" : "Too many") + " query string options were specified";
}

// parse ids
var ids = [];
if (hasProjectId) {
ids.push(parseInt($routeParams.projectId, 10));
$scope.filterType = "projectId";
}
if (hasSiteId) {
ids.push(parseInt($routeParams.siteId, 10));
$scope.filterType = "siteId";
}
if (hasSiteIds) {
var siteIdString = $routeParams.siteIds;
$scope.filterType = "siteIds";

if (siteIdString) {
Array.prototype.push.apply(
ids,
siteIdString.split(",").map(function (x) {
return parseInt(x, 10);
})
);
}
}

// validate ids
var validIds = ids.every(function (x) {
return typeof x === "number" &&
x >= 0 && !isNaN(x);
});

if (!validIds) {
$scope.errorState = "The site or project ids specified were invalid";
}

$scope.ids = ids;

return {
projectFirst: hasProjectId,
ids: ids,
error: $scope.errorState
}
}

function sitesRetrieved(result) {
var sites = result.data.data;

if (!sites || sites.length === 0) {
$scope.errorState = "No sites could be found";
return $q.reject(new Error("Empty sites returned"));
}

sitesMap = sites.reduce(function (previous, current) {
previous[current.id] = current;
return previous;
}, {});

$scope.sites = sites;

return sites;
}

function getOtherData(sites) {
var siteIds = [], projectIds = [];
sites.forEach(function (s) {
siteIds.push(s.id);
Array.prototype.push.apply(projectIds, s.projectIds);
});

return $q.all([
AudioRecording.getRecordingsForVisulisation(siteIds),
Project.getByIds(projectIds)
])
}

function processOtherData(results) {
console.debug("Visualise data promise chain success", arguments);

var projects = results[1].data.data;
$scope.projects = projects;

var audioRecordings = results[0].data.data;
$scope.recordingData = audioRecordings;


}

}
]
);
31 changes: 27 additions & 4 deletions src/app/visualize/visualize.tpl.html
Original file line number Diff line number Diff line change
@@ -1,14 +1,37 @@
<div id="content" class="visualize-content">
<section class="row visualizeContentHeader">
<h2>Audio distribution visualisation</h2>

<div class="text-center">
<small class="">Current filter: e.g. Project 341</small>
<p ng-if="::errorState" class="alert alert-danger" role="alert">
The page is unable to be loaded.
The error is: {{::errorState}}.
</p>
<small>
<span>Current filter: </span>
<span ng-switch="filterType">
<span ng-switch-when="projectId">one project ({{ids[0]}})</span>
<span ng-switch-when="siteId">one site ({{ids[0]}})</span>
<span ng-switch-when="siteIds">many sites (ids)</span>
</span> that is showing information from&nbsp;
<span ng-repeat="p in projects" class="projectSiteList">
<!--{{ $first && "" || ", "}}-->

<a ng-href="{{::getProjectLink(p)}}" target="_self">{{p.name}}</a>
&nbsp;&#47;&nbsp;
<span ng-repeat="s in getSitesForProject(p)">
<a ng-href="{{::getSiteLink(p, s)}}" target="_self">{{s.name}}</a>
{{ $last && " " || ", "}}
</span>
{{ $last && " " || ";"}}
</span>
</small>
</div>
</section>
<div event-distribution data="recordingData" options="distributionOptions" >
<div ng-if="!errorState" event-distribution data="recordingData" options="distributionOptions">

<section class="row">
<event-distribution-overview> </event-distribution-overview>
<event-distribution-overview></event-distribution-overview>
<!--{{distributionOptions.overviewExtent}}-->
</section>

Expand All @@ -18,7 +41,7 @@ <h3>Detailed view for {{distributionOptions.detailDuration}}</h3>
</section>

<section class="row">
<h3>False colour visualisation for {{distributionOptions.visualizationDuration}}</h3>
<h3>False colour visualisation for {{distributionOptions.visualizationDuration}} in {{distributionOptions.selectedLane}}</h3>
<event-distribution-visualisation></event-distribution-visualisation>
</section>
</div>
Expand Down
Loading

0 comments on commit 2272310

Please sign in to comment.