Browse Source

added tag clouds

asiekierka 6 years ago
parent
commit
847e297a6f
5 changed files with 138 additions and 10 deletions
  1. 15
    3
      app.js
  2. 35
    0
      cloudgen.js
  3. 73
    7
      imagedb.js
  4. 14
    0
      templates/tagcloud.html
  5. 1
    0
      util.js

+ 15
- 3
app.js View File

@@ -16,7 +16,8 @@ var express = require('express')
16 16
   , queryParser = require('./queryparser.js').QueryParser
17 17
   , imageHandler = require('./image.js')
18 18
   , tempurl = require('./tempurl.js')
19
-  , util = require('./util.js');
19
+  , util = require('./util.js')
20
+  , tagCloud = require('./cloudgen.js');
20 21
 
21 22
 _.str = require('underscore.string');
22 23
 _.mixin(_.str.exports());
@@ -322,6 +323,15 @@ function listImages(req,res,images1,options,defConfig,maxVal) {
322 323
   });
323 324
 }
324 325
 
326
+app.get("/cloud/*", parse, function(req,res) {
327
+  if(req.params.length < 1 || !imageDB.isCloudTag(req.params[0])) { error(req,res,"No tag found!",404); return; }
328
+  imageDB.getCloud(req.params[0], function(cloudData) {  
329
+    console.log(cloudData);
330
+    var cloudTag = tagCloud.generate(cloudData, {});
331
+    var opts = {title: "All "+req.params[0]+"s", tagCloud: cloudTag, req: req};
332
+    res.send(makeTemplate("tagcloud",opts,req.query["mode"] || "",false));
333
+  });
334
+});
325 335
 app.get("/*", function(req,res) {
326 336
   var p = qs.unescape(req.path).split("/");
327 337
   console.log("Request: " + JSON.stringify(p)); 
@@ -362,8 +372,10 @@ userDB.exists("admin", function(err, exists) {
362 372
 });
363 373
 
364 374
 function start() {
365
-  app.listen(config.port);
366
-  console.log("Working on port " + config.port);
375
+  imageDB.updateDatabase(function() {
376
+    app.listen(config.port);
377
+    console.log("Working on port " + config.port);
378
+  });
367 379
 }
368 380
 
369 381
 if(argv.r || argv.regen) {

+ 35
- 0
cloudgen.js View File

@@ -0,0 +1,35 @@
1
+var _ = require("underscore");
2
+
3
+var defOptions = {
4
+  "minFontSize": 10,
5
+  "maxFontSize": 30,
6
+  "template": "<a href='$TARGET' style='font-size: $SIZEpx' title='$COUNT times'>$TEXT</a>, ",
7
+  "targetTemplate": "/tag/$TEXT",
8
+  "alphaSort": true,
9
+  "useLog": true
10
+}
11
+
12
+exports.generate = function(array, userOptions) {
13
+  var nums = _.values(array)
14
+    , tags = _.keys(array)
15
+    , maxn = _.max(nums)
16
+    , minn = _.min(nums)
17
+    , options = _.defaults(userOptions, defOptions)
18
+    , cloud = "";
19
+  var multiplier = 0;
20
+  if(options.useLog)
21
+    multiplier = (options.maxFontSize - options.minFontSize) / (Math.log(maxn) - Math.log(minn));
22
+  else 
23
+    multiplier = (options.maxFontSize - options.minFontSize) / (maxn - minn);
24
+  if(options.alphaSort) tags = tags.sort();
25
+  _.each(tags, function(tag) {
26
+    var val = (options.useLog ? Math.log(array[tag]) : array[tag]);
27
+    var target = options.targetTemplate.replace("$TEXT",tag);
28
+    var tag = options.template.replace("$TEXT",tag)
29
+              .replace("$COUNT",array[tag])
30
+              .replace("$SIZE",(options.minFontSize + (val*multiplier)))
31
+              .replace("$TARGET",target);
32
+    cloud += tag;
33
+  });
34
+  return cloud;
35
+}

+ 73
- 7
imagedb.js View File

@@ -1,11 +1,76 @@
1 1
 var ImageDB = {}
2 2
   , redis = require("redis")
3 3
   , _ = require("underscore")
4
-  , async = require("async");
4
+  , async = require("async")
5
+  , util = require("./util.js");
5 6
 
6
-var client = null;
7
+var client = null
8
+  , CURRENT_VERSION = 2
9
+  , cloudTags = ["tag", "author", "uploader"];
7 10
 
8
-ImageDB.connect = function(cli) { client = cli; }
11
+ImageDB.connect = function(cli) {
12
+  client = cli;
13
+}
14
+ImageDB.log = function(t) { console.log("[ImageDB] "+t); }
15
+ImageDB.getVersion = function(cb) {
16
+  client.get("db_version",function(err, out) {
17
+    if(err) cb(1);
18
+    else cb((parseInt(out)>0) ? parseInt(out) : 1);
19
+  });
20
+}
21
+ImageDB.updateDatabase = function(callback) {
22
+  var self = this;
23
+  self.getVersion(function(version) {
24
+    if(version == 1) {
25
+      version = 2;
26
+      self.log("Updating DB from version 1 to 2");
27
+      self.updateCloud(function(){
28
+        self.log("Done updating!");
29
+        client.set("db_version", 2, _.bind(self.updateDatabase, self));
30
+      });
31
+    }
32
+    else if(version == CURRENT_VERSION) { self.log("Latest DB version, nothing to do..."); if(_.isFunction(callback)) callback(); }
33
+  });
34
+}
35
+
36
+// CLOUD CODE
37
+
38
+ImageDB.isCloudTag = function(text) { return _(cloudTags).contains(text); }
39
+ImageDB.updateCloud = function(callback) {
40
+  var self = this;
41
+  async.each(cloudTags, function(item, cb) {
42
+    self.generateCloud(item, cb);
43
+  }, callback);
44
+}
45
+ImageDB.getCloud = function(name, cb) {
46
+  client.zrange("cloud:"+name,0,-1,'WITHSCORES',function(err, data) {
47
+    if(err) throw err;
48
+    var fixedData = {};
49
+    while(data.length > 0) {
50
+      var name = data.shift();
51
+      fixedData[name] = parseInt(data.shift());
52
+    }
53
+    cb(fixedData);
54
+  });
55
+}
56
+ImageDB.generateCloud = function(name, cb) {
57
+  this.log("(Re)generating tag cloud "+name+"...");
58
+  client.smembers(name+"s", function(err, out) {
59
+    if(err) throw err;
60
+    var counts = async.map(out, function(tagName, callback) {
61
+      client.scard(name+":"+tagName, function(err, out) { // Count
62
+        callback(err, {"name": tagName, "count": out});
63
+      });
64
+    }, function(err, out) {
65
+      if(err) throw err;
66
+      var output = {};
67
+      async.eachSeries(out, function(tag, callback) {
68
+        if(tag.count == 0 || tag.name == "") callback();
69
+        else client.zadd("cloud:"+name, tag.count, tag.name, callback);
70
+      }, cb);
71
+    });
72
+  });
73
+}
9 74
 
10 75
 ImageDB.get = function(id,callback) {
11 76
   client.get("data:"+id,function(err,out) {
@@ -144,7 +209,7 @@ ImageDB.unsetSearchData = function(id, data, callback) {
144 209
   async.series([
145 210
     _.bind(client.srem,client,"hashes",data.hash),
146 211
     _.bind(self.unsetTags,self,id,data.tags),
147
-    function(cb) { console.log("dbg"); cb(); },
212
+    function(cb) { cb(); },
148 213
     _.bind(self.delField,self,id,"author",data.author),
149 214
     _.bind(self.delField,self,id,"uploader",data.uploader),
150 215
     _.bind(self.delSize,self,id,"width"),
@@ -172,7 +237,8 @@ ImageDB.set = function(id,data,callback,noHashCheck) {
172 237
           async.parallel([
173 238
             _.bind(client.set,client,"data:"+id,JSON.stringify(data)),
174 239
             _.bind(client.sadd,client,"images",id),
175
-            _.bind(self.setSearchData,self,id,data)
240
+            _.bind(self.setSearchData,self,id,data),
241
+            _.bind(self.updateCloud,self)
176 242
           ], callback);
177 243
         };
178 244
         if(exists) self.get(id,function(data) { self.unset(id,s,true); });
@@ -189,10 +255,10 @@ ImageDB.unset = function(id,callback,dontTouchData) {
189 255
     async.parallel([
190 256
       function(callback) { if(!dontTouchData) client.del("data:"+id,callback); else callback(); },
191 257
       function(callback) { if(!dontTouchData) client.srem("images",id,callback); else callback(); },
192
-      _.bind(self.unsetSearchData,self,id,data)
258
+      _.bind(self.unsetSearchData,self,id,data),
259
+      _.bind(self.updateCloud,self)
193 260
     ],callback);
194 261
   });
195 262
 }
196 263
 
197
-
198 264
 exports.ImageDB = ImageDB;

+ 14
- 0
templates/tagcloud.html View File

@@ -0,0 +1,14 @@
1
+<div class="row padded-row">
2
+<div class="span12" style="text-align: center;">
3
+<h3><%= title %></h3>
4
+</div>
5
+</div>
6
+<div class="row">
7
+<div class="offset2 span8" style="text-align: center;">
8
+<%= tagCloud %>
9
+</div>
10
+</div>
11
+<script type="text/javascript">
12
+function pageLoad() { }
13
+function pageUnload() { }
14
+</script>

+ 1
- 0
util.js View File

@@ -17,3 +17,4 @@ exports.copyFile = function(src,dest) {
17 17
 exports.filesize = function(name) {
18 18
   return fs.statSync(name).size;
19 19
 }
20
+exports.time = function(){ return Math.round(new Date().getTime() / 1000); }

Loading…
Cancel
Save