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