diff --git a/client/html/index.html b/client/html/index.html
index 9dbcba9..0815e42 100644
--- a/client/html/index.html
+++ b/client/html/index.html
@@ -55,12 +55,6 @@
-
diff --git a/client/scripts/application.js b/client/scripts/application.js
index 5ea0318..7941817 100644
--- a/client/scripts/application.js
+++ b/client/scripts/application.js
@@ -22,10 +22,11 @@
(function(hscd) {
'use strict';
- var _ctx = { };
+ var _ctx = {};
function onAdjust(name, value) {
_ctx.query.features[name] = value;
+
$.getJSON('/search', _ctx.query, function(results) {
saveSnapshot(results);
outputSnapshot(results, true);
@@ -34,37 +35,19 @@
function onReady(geo) {
_ctx = {
- log: [],
- geo: geo
+ log: [],
+ geo: geo,
+ query: {}
};
- $('#historyIndex').slider({
- formatter: function(value) {
- var delta = _ctx.log.length - (value + 1);
- switch (delta) {
- case 0:
- return 'Most recent query';
- case 1:
- return 'Previous query';
- default:
- return String(delta) + ' queries back';
- }
- }
- });
+ $('#minScore,#hintSteps,#walkingDist,#maxResults').change(onSearch);
- $.getJSON('/get_parameters', function(parameters) {
- _ctx.parameters = parameters;
-
- onSearch();
-
- $('#minScore,#hintSteps,#walkingDist,#maxResults').change(function() { onSearch(getFeaturesGrapher); });
- $('#historyIndex').on('slideStop', onSelectSnapshot);
- });
+ onSearch();
}
- function onSearch(provider) {
+ function onSearch() {
_ctx.query = {
- features: _clone(_ctx.query.features),
+ features: _ctx.query.features || {},
range: { min: -1.0, max: 1.0 },
walkingDist: parseFloat($('#walkingDist').val()),
minScore: parseFloat($('#minScore').val()),
@@ -79,58 +62,47 @@
};
}
- if (!_.has(_ctx, 'grapher')) {
- _ctx.grapher = new grapher.Grapher({
- canvas: new Snap('#svg'),
- steps: _ctx.query.hintSteps,
- range: _ctx.query.range,
- onValueChanged: onAdjust,
- useLocalScale: true,
- useRelativeScale: true
- });
+ $.getJSON('/search', _ctx.query, function(results) {
+ if (!_.has(_ctx, 'grapher')) {
+ _ctx.grapher = new grapher.Grapher({
+ canvas: new Snap('#svg'),
+ steps: _ctx.query.hintSteps,
+ range: _ctx.query.range,
+ onValueChanged: onAdjust,
+ useLocalScale: true,
+ useRelativeScale: true
+ });
- $('#useLocalScale').click(function() {
- var useLocalScale = $('#useLocalScale').is(':checked');
- _ctx.grapher.setUseLocalScale(useLocalScale);
- });
- $('#useRelativeScale').click(function() {
- var useRelativeScale = $('#useRelativeScale').is(':checked');
- _ctx.grapher.setUseRelativeScale(useRelativeScale);
- });
+ $('#useLocalScale').click(function() {
+ var useLocalScale = $('#useLocalScale').is(':checked');
+ _ctx.grapher.setUseLocalScale(useLocalScale);
+ });
- var columns = {};
- for (var feature in _ctx.query.features) {
- columns[feature] = {
- value: 0.0,
- hints: []
- };
+ $('#useRelativeScale').click(function() {
+ var useRelativeScale = $('#useRelativeScale').is(':checked');
+ _ctx.grapher.setUseRelativeScale(useRelativeScale);
+ });
+
+ var columns = {};
+ for (var feature in results.columns) {
+ var column = results.columns[feature];
+ _ctx.query.features[feature] = column.value;
+ columns[feature] = {
+ value: column.value,
+ hints: column.hints
+ };
+ }
+
+ _ctx.grapher.setColumns(columns);
}
- _ctx.grapher.setColumns(columns);
- }
-
- $.getJSON('/search', _ctx.query, function(results) {
saveSnapshot(results);
outputSnapshot(results, false);
});
}
- function onSelectSnapshot() {
- var index = $('#historyIndex').slider('getValue');
- outputSnapshot(_ctx.log[index], false);
- }
-
function saveSnapshot(results) {
_ctx.log.push(results);
-
- var count = _ctx.log.length;
- var history = $('#historyIndex').slider();
- history.slider('setAttribute', 'max', count - 1);
- history.slider('setValue', count - 1);
-
- if (count > 1) {
- $('#history').show();
- }
}
function outputSnapshot(results, omitValues) {
@@ -150,24 +122,29 @@
if (results.length < count) {
searchResultCnt += ' of ' + count;
}
-
$('#resultCount').text(searchResultCnt);
- $('#resultPanel').slideDown();
var template = Handlebars.compile($('#template').html());
$('#results').empty();
- $('#results').append(template({results: results}));
+ $('#results').append(
+ template({ results: results })
+ );
+
+ if (results.length === 0) {
+ $('#resultPanel').slideUp();
+ }
+ else {
+ $('#resultPanel').slideDown();
+ }
}
$(document).on({
ajaxStart: function() {
$('#spinner').show();
},
-
ajaxStop: function() {
$('#spinner').hide();
},
-
ready: function() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
diff --git a/server/search.js b/server/search.js
index 2dcf006..9ada68c 100644
--- a/server/search.js
+++ b/server/search.js
@@ -32,17 +32,18 @@ var pool = null;
function innerProduct(values1, values2) {
var result = 0.0;
- console.assert(_.keys(values1).length == _.keys(values2).length);
for (var feature in values1) {
- result += values1[feature] * values2[feature];
+ if (feature in values2) {
+ result += values1[feature] * values2[feature];
+ }
}
return result;
}
function walkMatches(data, features, minScore, callback) {
- for (var i = 0, count = data.records.length; i < count; ++i) {
- var record = data.records[i];
+ for (var i = 0, count = data.length; i < count; ++i) {
+ var record = data[i];
var score = innerProduct(features, record.features);
if (score >= minScore) {
@@ -62,6 +63,7 @@ function countRecords(data, features, minScore) {
function findRecords(data, features, minScore) {
var results = [];
+
walkMatches(data, features, minScore, function(record, score) {
results.push({
name: record.name,
@@ -189,7 +191,27 @@ function computeRecordGeo(records, context) {
});
}
+function sanitizeQuery(query) {
+ var keys = [
+ 'delicious',
+ 'accomodating',
+ 'affordable',
+ 'atmospheric',
+ 'nearby',
+ 'accessible'
+ ];
+
+ var features = {};
+ _.each(keys, function(key) {
+ features[key] = _.has(query.features, key) ? query.features[key] : 0.0;
+ });
+
+ query.features = features;
+}
+
function execQuery(query, callback) {
+ sanitizeQuery(query);
+
var context = {
geo: query.geo,
walkingDist: query.walkingDist * 1000.0