diff --git a/server.go b/server.go
index f77ccce..35ca18b 100644
--- a/server.go
+++ b/server.go
@@ -59,8 +59,8 @@ func executeQuery(rw http.ResponseWriter, req *http.Request) {
sorter.sort()
response := jsonQueryResponse{
- Count: len(foundEntries),
Columns: make(map[string]jsonColumn),
+ Count: len(foundEntries),
MinScore: request.MinScore,
Records: make([]jsonRecord, 0)}
@@ -68,10 +68,10 @@ func executeQuery(rw http.ResponseWriter, req *http.Request) {
mode, _ := modes[name]
column := jsonColumn{
- Bracket: jsonBracket{Max: -1, Min: 1},
+ Bracket: jsonBracket{Max: -1.0, Min: 1.0},
Mode: mode.String(),
- Value: value,
- Steps: request.Resolution}
+ Steps: request.Resolution,
+ Value: value}
hints := project(
entries,
@@ -216,7 +216,6 @@ func removeCategory(rw http.ResponseWriter, req *http.Request) {
}
_, err := db.Exec("DELETE FROM categories WHERE id = (?)", request.Id)
-
js, err := json.Marshal(jsonRemoveCategoryResponse{err == nil})
if err != nil {
log.Fatal(err)
@@ -295,8 +294,7 @@ func main() {
flag.Parse()
var err error
- db, err = sql.Open("mysql", *dataSrc)
- if err != nil {
+ if db, err = sql.Open("mysql", *dataSrc); err != nil {
log.Fatal(err)
}
defer db.Close()
diff --git a/static/index.html b/static/index.html
index e96c7a6..8c97349 100644
--- a/static/index.html
+++ b/static/index.html
@@ -11,7 +11,7 @@
-
+
diff --git a/static/scripts/grapher.js b/static/scripts/grapher.js
index 2e0f13c..a5bb696 100644
--- a/static/scripts/grapher.js
+++ b/static/scripts/grapher.js
@@ -92,18 +92,18 @@
var _tickSize = 5;
var _width = 125;
- var _indicatorAnim = null;
- var _bracketAnim = null;
- var _canvas = params.canvas;
- var _data = params.data;
- var _index = params.index;
- var _name = params.name;
- var _valueTrans = params.data.value;
- var _bracketTrans = params.data.bracket;
- var _onStateChanged = params.onStateChanged;
- var _range = params.range;
- var _scale = params.scale;
- var _elements = {};
+ var _indicatorAnim = null;
+ var _bracketAnim = null;
+ var _canvas = params.canvas;
+ var _data = params.data;
+ var _index = params.index;
+ var _name = params.name;
+ var _valueTrans = params.data.value;
+ var _bracketTrans = params.data.bracket;
+ var _stateChanged = params.stateChanged;
+ var _range = params.range;
+ var _scale = params.scale;
+ var _elements = {};
function createShapes() {
// indicatorBg
@@ -298,23 +298,25 @@
}
function updateMode() {
- var modeText = '( ' + _data.mode + ' )';
+ var modes = {'product': 'importance', 'distance': 'similarity'};
+ var mode = modes[_data.mode];
if (_.has(_elements, 'mode')) {
_elements.mode.attr({
- text: modeText
+ text: mode
});
}
else {
_elements.mode = _canvas.text(
(_width - _bracketSize) / 2,
_height - _panelSize / 4,
- modeText
+ mode
).attr({
'dominant-baseline': 'middle',
'text-anchor': 'middle',
- cursor: 'hand',
- 'fill': _modeColor
+ 'text-decoration': 'underline',
+ 'fill': _modeColor,
+ cursor: 'hand'
}).click(modeClick);
}
}
@@ -354,8 +356,8 @@
_data.value = _range.clamp(value);
_data.mode = mode;
- if (_onStateChanged) {
- _onStateChanged(_name, _data.value, _data.mode);
+ if (_stateChanged) {
+ _stateChanged(_name, _data.value, _data.mode);
}
animateIndicator(_valueTrans, _data.value);
@@ -493,13 +495,13 @@
//
grapher.Grapher = function(params) {
- var _canvas = params.canvas;
- var _columns = {};
- var _data = {};
- var _range = new Range(-1.0, 1.0);
- var _useLocalScale = params.useLocalScale || false;
- var _displayType = params.displayType || 'density';
- var _onStateChanged = params.onStateChanged;
+ var _canvas = params.canvas;
+ var _columns = {};
+ var _data = {};
+ var _range = new Range(-1.0, 1.0);
+ var _useLocalScale = params.useLocalScale || false;
+ var _displayType = params.displayType || 'density';
+ var _stateChanged = params.stateChanged;
function processHintParameters(columns) {
var displayTypes = {compatibility: 'compatibility', density: 'count'};
@@ -557,13 +559,13 @@
}
else {
_columns[name] = new Column({
- onStateChanged: _onStateChanged,
- range: _range,
- canvas: _canvas,
- data: columnData,
- name: name,
- scale: scale,
- index: index++,
+ stateChanged: _stateChanged,
+ range: _range,
+ canvas: _canvas,
+ data: columnData,
+ name: name,
+ scale: scale,
+ index: index++,
});
}
}
diff --git a/static/scripts/search.js b/static/scripts/search.js
index acd3609..a1001d5 100644
--- a/static/scripts/search.js
+++ b/static/scripts/search.js
@@ -25,7 +25,7 @@
var _ctx = {};
- function onStateChanged(name, value, mode) {
+ function stateChanged(name, value, mode) {
_ctx.query.features[name] = value;
_ctx.query.modes[name] = mode;
@@ -35,7 +35,7 @@
}, 'json');
}
- function onReady(geo) {
+ function ready(geo) {
_ctx = {
sortKey: 'score',
sortAsc: false,
@@ -98,10 +98,10 @@
$.post('/query', JSON.stringify(_ctx.query), function(results) {
if (!_.has(_ctx, 'grapher')) {
_ctx.grapher = new grapher.Grapher({
- canvas: new Snap('#svg'),
- onStateChanged: onStateChanged,
- displayType: $('#displayType').val(),
- useLocalScale: $('#useLocalScale').is(':checked')
+ canvas: new Snap('#svg'),
+ stateChanged: stateChanged,
+ displayType: $('#displayType').val(),
+ useLocalScale: $('#useLocalScale').is(':checked')
});
$('#useLocalScale').click(function() {
@@ -200,13 +200,13 @@
ready: function() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
- function(geo) { onReady(geo); },
- function(err) { onReady(null); },
+ function(geo) { ready(geo); },
+ function(err) { ready(null); },
{ enableHighAccuracy: true }
);
}
else {
- onReady(null);
+ ready(null);
}
}
});
diff --git a/types.go b/types.go
index 0f231f0..387f3ea 100644
--- a/types.go
+++ b/types.go
@@ -22,18 +22,20 @@
package main
-import "sort"
-
-type modeType int
-
-const (
- ModeTypeNone modeType = iota
- ModeTypeProduct
- ModeTypeDistance
+import (
+ "errors"
+ "sort"
)
type featureMap map[string]float64
type modeMap map[string]modeType
+type records []record
+type modeType int
+
+const (
+ modeTypeProd = iota + 1
+ modeTypeDist
+)
type jsonAccessRequest struct {
Id int `json:"id"`
@@ -150,8 +152,6 @@ type record struct {
url string
}
-type records []record
-
type recordSorter struct {
ascending bool
entries records
@@ -198,22 +198,22 @@ func (s recordSorter) Swap(i, j int) {
func (m modeType) String() string {
switch m {
- case ModeTypeProduct:
+ case modeTypeProd:
return "product"
- case ModeTypeDistance:
+ case modeTypeDist:
return "distance"
default:
- return "invalid"
+ return ""
}
}
-func strToModeType(mode string) modeType {
+func parseModeType(mode string) (modeType, error) {
switch mode {
case "product":
- return ModeTypeProduct
+ return modeTypeProd, nil
case "distance":
- return ModeTypeDistance
+ return modeTypeDist, nil
default:
- return ModeTypeNone
+ return 0, errors.New("invalid mode type")
}
}
diff --git a/util.go b/util.go
index 974af99..4096bc3 100644
--- a/util.go
+++ b/util.go
@@ -40,8 +40,9 @@ func fixFeatures(features featureMap) featureMap {
"atmospheric": 0.0}
for name := range fixedFeatures {
- value, _ := features[name]
- fixedFeatures[name] = value
+ if value, ok := features[name]; ok {
+ fixedFeatures[name] = value
+ }
}
return fixedFeatures
@@ -49,42 +50,48 @@ func fixFeatures(features featureMap) featureMap {
func fixModes(modes map[string]string) modeMap {
fixedModes := modeMap{
- "nearby": ModeTypeProduct,
- "accessible": ModeTypeProduct,
- "delicious": ModeTypeProduct,
- "accommodating": ModeTypeProduct,
- "affordable": ModeTypeProduct,
- "atmospheric": ModeTypeProduct}
+ "nearby": modeTypeProd,
+ "accessible": modeTypeProd,
+ "delicious": modeTypeProd,
+ "accommodating": modeTypeProd,
+ "affordable": modeTypeProd,
+ "atmospheric": modeTypeProd}
for name := range fixedModes {
if value, ok := modes[name]; ok {
- fixedModes[name] = strToModeType(value)
+ if mode, err := parseModeType(value); err == nil {
+ fixedModes[name] = mode
+ }
}
}
return fixedModes
}
-func innerProduct(features1 featureMap, features2 featureMap) float64 {
- var result float64
+func distance(features1 featureMap, features2 featureMap) float64 {
+ var sum float64
+
for key, value1 := range features1 {
value2, _ := features2[key]
- result += value1 * value2
+ sum += math.Pow(value1-value2, 2)
}
- return result
+ return math.Sqrt(sum)
}
func compare(features1 featureMap, features2 featureMap, modes modeMap) float64 {
var result float64
+
for key, value1 := range features1 {
value2, _ := features2[key]
switch mode, _ := modes[key]; mode {
- case ModeTypeDistance:
+ case modeTypeDist:
result += 1 - math.Abs(value1-value2)
- default:
+ case modeTypeProd:
result += value1 * value2
+ default:
+ log.Fatal("unsupported compare mode")
}
}
@@ -228,7 +235,7 @@ func computeRecordPopularity(entries records, context queryContext) {
log.Fatal(err)
}
- groupSum += innerProduct(recordProfile, context.profile)
+ groupSum += distance(recordProfile, context.profile)
groupCount++
}
if err := historyRows.Err(); err != nil {