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 {