Browse Source

Agregando la nube de palabras de las Bitacoras de los microtalleres

master
kleper 2 years ago
parent
commit
d33895f604
8 changed files with 14511 additions and 203 deletions
  1. +1
    -2
      css/datos_visuales.css
  2. +196
    -201
      index.html
  3. +26
    -0
      js/LICENSE.d3
  4. +26
    -0
      js/LICENSE.d3.layout.cloud
  5. +4489
    -0
      js/bitacorasmt.json
  6. +9215
    -0
      js/d3.js
  7. +401
    -0
      js/d3.layout.cloud.js
  8. +157
    -0
      js/d3.wordcloud.js

+ 1
- 2
css/datos_visuales.css View File

@@ -19,10 +19,9 @@ background-color: #E6E7E8;
margin-bottom: 50px;
padding: 20px 40px;
}
r

.subtitulo {
display: block;
display: block;
height: 10px;
border-bottom: dotted 2px #D1D3D4;
text-align: center;

+ 196
- 201
index.html
File diff suppressed because it is too large
View File


+ 26
- 0
js/LICENSE.d3 View File

@@ -0,0 +1,26 @@
Copyright (c) 2010-2014, Michael Bostock
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* The name Michael Bostock may not be used to endorse or promote products
derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 26
- 0
js/LICENSE.d3.layout.cloud View File

@@ -0,0 +1,26 @@
Copyright (c) 2013, Jason Davies.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* The name Jason Davies may not be used to endorse or promote products
derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL JASON DAVIES BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 4489
- 0
js/bitacorasmt.json
File diff suppressed because it is too large
View File


+ 9215
- 0
js/d3.js
File diff suppressed because it is too large
View File


+ 401
- 0
js/d3.layout.cloud.js View File

@@ -0,0 +1,401 @@
// Word cloud layout by Jason Davies, http://www.jasondavies.com/word-cloud/
// Algorithm due to Jonathan Feinberg, http://static.mrfeinberg.com/bv_ch03.pdf
(function() {
function cloud() {
var size = [600, 600],
text = cloudText,
font = cloudFont,
fontSize = cloudFontSize,
fontStyle = cloudFontNormal,
fontWeight = cloudFontNormal,
rotate = cloudRotate,
padding = cloudPadding,
spiral = archimedeanSpiral,
words = [],
timeInterval = Infinity,
event = d3.dispatch("word", "end"),
timer = null,
cloud = {};

cloud.start = function() {
var board = zeroArray((size[0] >> 5) * size[1]),
bounds = null,
n = words.length,
i = -1,
tags = [],
data = words.map(function(d, i) {
d.text = text.call(this, d, i);
d.font = font.call(this, d, i);
d.style = fontStyle.call(this, d, i);
d.weight = fontWeight.call(this, d, i);
d.rotate = rotate.call(this, d, i);
d.size = ~~fontSize.call(this, d, i);
d.padding = padding.call(this, d, i);
return d;
}).sort(function(a, b) { return b.size - a.size; });

if (timer) clearInterval(timer);
timer = setInterval(step, 0);
step();

return cloud;

function step() {
var start = +new Date,
d;
while (+new Date - start < timeInterval && ++i < n && timer) {
d = data[i];
d.x = (size[0] * (Math.random() + .5)) >> 1;
d.y = (size[1] * (Math.random() + .5)) >> 1;
cloudSprite(d, data, i);
if (d.hasText && place(board, d, bounds)) {
tags.push(d);
event.word(d);
if (bounds) cloudBounds(bounds, d);
else bounds = [{x: d.x + d.x0, y: d.y + d.y0}, {x: d.x + d.x1, y: d.y + d.y1}];
// Temporary hack
d.x -= size[0] >> 1;
d.y -= size[1] >> 1;
}
}
if (i >= n) {
cloud.stop();
event.end(tags, bounds);
}
}
}

cloud.stop = function() {
if (timer) {
clearInterval(timer);
timer = null;
}
return cloud;
};

cloud.timeInterval = function(x) {
if (!arguments.length) return timeInterval;
timeInterval = x == null ? Infinity : x;
return cloud;
};

function place(board, tag, bounds) {
var perimeter = [{x: 0, y: 0}, {x: size[0], y: size[1]}],
startX = tag.x,
startY = tag.y,
maxDelta = Math.sqrt(size[0] * size[0] + size[1] * size[1]),
s = spiral(size),
dt = Math.random() < .5 ? 1 : -1,
t = -dt,
dxdy,
dx,
dy;

while (dxdy = s(t += dt)) {
dx = ~~dxdy[0];
dy = ~~dxdy[1];

if (Math.min(dx, dy) > maxDelta) break;

tag.x = startX + dx;
tag.y = startY + dy;

if (tag.x + tag.x0 < 0 || tag.y + tag.y0 < 0 ||
tag.x + tag.x1 > size[0] || tag.y + tag.y1 > size[1]) continue;
// TODO only check for collisions within current bounds.
if (!bounds || !cloudCollide(tag, board, size[0])) {
if (!bounds || collideRects(tag, bounds)) {
var sprite = tag.sprite,
w = tag.width >> 5,
sw = size[0] >> 5,
lx = tag.x - (w << 4),
sx = lx & 0x7f,
msx = 32 - sx,
h = tag.y1 - tag.y0,
x = (tag.y + tag.y0) * sw + (lx >> 5),
last;
for (var j = 0; j < h; j++) {
last = 0;
for (var i = 0; i <= w; i++) {
board[x + i] |= (last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0);
}
x += sw;
}
delete tag.sprite;
return true;
}
}
}
return false;
}

cloud.words = function(x) {
if (!arguments.length) return words;
words = x;
return cloud;
};

cloud.size = function(x) {
if (!arguments.length) return size;
size = [+x[0], +x[1]];
return cloud;
};

cloud.font = function(x) {
if (!arguments.length) return font;
font = d3.functor(x);
return cloud;
};

cloud.fontStyle = function(x) {
if (!arguments.length) return fontStyle;
fontStyle = d3.functor(x);
return cloud;
};

cloud.fontWeight = function(x) {
if (!arguments.length) return fontWeight;
fontWeight = d3.functor(x);
return cloud;
};

cloud.rotate = function(x) {
if (!arguments.length) return rotate;
rotate = d3.functor(x);
return cloud;
};

cloud.text = function(x) {
if (!arguments.length) return text;
text = d3.functor(x);
return cloud;
};

cloud.spiral = function(x) {
if (!arguments.length) return spiral;
spiral = spirals[x + ""] || x;
return cloud;
};

cloud.fontSize = function(x) {
if (!arguments.length) return fontSize;
fontSize = d3.functor(x);
return cloud;
};

cloud.padding = function(x) {
if (!arguments.length) return padding;
padding = d3.functor(x);
return cloud;
};

return d3.rebind(cloud, event, "on");
}

function cloudText(d) {
return d.text;
}

function cloudFont() {
return "'Slabo 27px', serif";
}

function cloudFontNormal() {
return "normal";
}

function cloudFontSize(d) {
return Math.sqrt(d.value);
}

function cloudRotate() {
return (~~(Math.random() * 6) - 3) * 0;
}

function cloudPadding() {
return 1;
}

// Fetches a monochrome sprite bitmap for the specified text.
// Load in batches for speed.
function cloudSprite(d, data, di) {
if (d.sprite) return;
c.clearRect(0, 0, (cw << 5) / ratio, ch / ratio);
var x = 0,
y = 0,
maxh = 0,
n = data.length;
--di;
while (++di < n) {
d = data[di];
c.save();
c.font = d.style + " " + d.weight + " " + ~~((d.size + 1) / ratio) + "px " + d.font;
var w = c.measureText(d.text + "m").width * ratio,
h = d.size << 1;
if (d.rotate) {
var sr = Math.sin(d.rotate * cloudRadians),
cr = Math.cos(d.rotate * cloudRadians),
wcr = w * cr,
wsr = w * sr,
hcr = h * cr,
hsr = h * sr;
w = (Math.max(Math.abs(wcr + hsr), Math.abs(wcr - hsr)) + 0x1f) >> 5 << 5;
h = ~~Math.max(Math.abs(wsr + hcr), Math.abs(wsr - hcr));
} else {
w = (w + 0x1f) >> 5 << 5;
}
if (h > maxh) maxh = h;
if (x + w >= (cw << 5)) {
x = 0;
y += maxh;
maxh = 0;
}
if (y + h >= ch) break;
c.translate((x + (w >> 1)) / ratio, (y + (h >> 1)) / ratio);
if (d.rotate) c.rotate(d.rotate * cloudRadians);
c.fillText(d.text, 0, 0);
if (d.padding) c.lineWidth = 2 * d.padding, c.strokeText(d.text, 0, 0);
c.restore();
d.width = w;
d.height = h;
d.xoff = x;
d.yoff = y;
d.x1 = w >> 1;
d.y1 = h >> 1;
d.x0 = -d.x1;
d.y0 = -d.y1;
d.hasText = true;
x += w;
}
var pixels = c.getImageData(0, 0, (cw << 5) / ratio, ch / ratio).data,
sprite = [];
while (--di >= 0) {
d = data[di];
if (!d.hasText) continue;
var w = d.width,
w32 = w >> 5,
h = d.y1 - d.y0;
// Zero the buffer
for (var i = 0; i < h * w32; i++) sprite[i] = 0;
x = d.xoff;
if (x == null) return;
y = d.yoff;
var seen = 0,
seenRow = -1;
for (var j = 0; j < h; j++) {
for (var i = 0; i < w; i++) {
var k = w32 * j + (i >> 5),
m = pixels[((y + j) * (cw << 5) + (x + i)) << 2] ? 1 << (31 - (i % 32)) : 0;
sprite[k] |= m;
seen |= m;
}
if (seen) seenRow = j;
else {
d.y0++;
h--;
j--;
y++;
}
}
d.y1 = d.y0 + seenRow;
d.sprite = sprite.slice(0, (d.y1 - d.y0) * w32);
}
}

// Use mask-based collision detection.
function cloudCollide(tag, board, sw) {
sw >>= 5;
var sprite = tag.sprite,
w = tag.width >> 5,
lx = tag.x - (w << 4),
sx = lx & 0x7f,
msx = 32 - sx,
h = tag.y1 - tag.y0,
x = (tag.y + tag.y0) * sw + (lx >> 5),
last;
for (var j = 0; j < h; j++) {
last = 0;
for (var i = 0; i <= w; i++) {
if (((last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0))
& board[x + i]) return true;
}
x += sw;
}
return false;
}

function cloudBounds(bounds, d) {
var b0 = bounds[0],
b1 = bounds[1];
if (d.x + d.x0 < b0.x) b0.x = d.x + d.x0;
if (d.y + d.y0 < b0.y) b0.y = d.y + d.y0;
if (d.x + d.x1 > b1.x) b1.x = d.x + d.x1;
if (d.y + d.y1 > b1.y) b1.y = d.y + d.y1;
}

function collideRects(a, b) {
return a.x + a.x1 > b[0].x && a.x + a.x0 < b[1].x && a.y + a.y1 > b[0].y && a.y + a.y0 < b[1].y;
}

function archimedeanSpiral(size) {
var e = size[0] / size[1];
return function(t) {
return [e * (t *= .1) * Math.cos(t), t * Math.sin(t)];
};
}

function rectangularSpiral(size) {
var dy = 4,
dx = dy * size[0] / size[1],
x = 0,
y = 0;
return function(t) {
var sign = t < 0 ? -1 : 1;
// See triangular numbers: T_n = n * (n + 1) / 2.
switch ((Math.sqrt(1 + 4 * sign * t) - sign) & 3) {
case 0: x += dx; break;
case 1: y += dy; break;
case 2: x -= dx; break;
default: y -= dy; break;
}
return [x, y];
};
}

// TODO reuse arrays?
function zeroArray(n) {
var a = [],
i = -1;
while (++i < n) a[i] = 0;
return a;
}

var cloudRadians = Math.PI / 180,
cw = 1 << 11 >> 5,
ch = 1 << 11,
canvas,
ratio = 1;

if (typeof document !== "undefined") {
canvas = document.createElement("canvas");
canvas.width = 1;
canvas.height = 1;
ratio = Math.sqrt(canvas.getContext("2d").getImageData(0, 0, 1, 1).data.length >> 2);
canvas.width = (cw << 5) / ratio;
canvas.height = ch / ratio;
} else {
// Attempt to use node-canvas.
canvas = new Canvas(cw << 5, ch);
}

var c = canvas.getContext("2d"),
spirals = {
archimedean: archimedeanSpiral,
rectangular: rectangularSpiral
};
c.fillStyle = c.strokeStyle = "red";
c.textAlign = "center";

if (typeof module === "object" && module.exports) module.exports = cloud;
else (d3.layout || (d3.layout = {})).cloud = cloud;
})();

+ 157
- 0
js/d3.wordcloud.js View File

@@ -0,0 +1,157 @@
// easy d3-based word cloud plugin https://github.com/wvengen/d3-wordcloud
// requires https://github.com/jasondavies/d3-cloud
// based on https://github.com/shprink/d3js-wordcloud
(function() {
function wordcloud() {
var selector = '#wordcloud',
element = d3.select(selector),
transitionDuration = 200,
scale = 'sqrt',
fill = d3.scale.category20b(),
layout = d3.layout.cloud(),
fontSize = null,
svg = null,
vis = null,
onwordclick = undefined;

wordcloud.element = function(x) {
if (!arguments.length) return element;
element = x == null ? '#wordcloud' : x;
return wordcloud
};

wordcloud.selector = function(x) {
if (!arguments.length) return selector;
element = d3.select(x == null ? selector : x);
return wordcloud;
};

wordcloud.transitionDuration = function(x) {
if (!arguments.length) return transitionDuration;
transitionDuration = typeof x == 'function' ? x() : x;
return wordcloud;
};

wordcloud.scale = function(x) {
if (!arguments.length) return scale;
scale = x == null ? 'sqrt' : x;
return wordcloud;
};

wordcloud.fill = function(x) {
if (!arguments.length) return fill;
fill = x == null ? d3.scale.category20b() : x;
return wordcloud;
};

wordcloud.onwordclick = function (func) {
onwordclick = func;
return wordcloud;
}

wordcloud.start = function() {
init();
layout.start(arguments);
return wordcloud;
};

function init() {
layout
.fontSize(function(d) {
return fontSize(+d.size);
})
.text(function(d) {
return d.text;
})
.on("end", draw);

svg = element.append("svg");
vis = svg.append("g").attr("transform", "translate(" + [layout.size()[0] >> 1, layout.size()[1] >> 1] + ")");

update();
svg.on('resize', function() { update() });
}

function draw(data, bounds) {
var w = layout.size()[0],
h = layout.size()[1];

svg.attr("width", w).attr("height", h);

scaling = bounds ? Math.min(
w / Math.abs(bounds[1].x - w / 2),
w / Math.abs(bounds[0].x - w / 2),
h / Math.abs(bounds[1].y - h / 2),
h / Math.abs(bounds[0].y - h / 2)) / 2 : 1;

var text = vis.selectAll("text")
.data(data, function(d) {
return d.text.toLowerCase();
});
text.transition()
.duration(transitionDuration)
.attr("transform", function(d) {
return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
})
.style("font-size", function(d) {
return d.size + "px";
});
text.enter().append("text")
.attr("text-anchor", "middle")
.attr("transform", function(d) {
return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
})
.style("font-size", function(d) {
return d.size + "px";
})
.style("opacity", 1e-6)
.transition()
.duration(transitionDuration)
.style("opacity", 1);
text.style("font-family", function(d) {
return d.font || layout.font() || svg.style("font-family");
})
.style("fill", function(d) {
return fill(d.text.toLowerCase());
})
.text(function(d) {
return d.text;
})
// clickable words
.style("cursor", function(d, i) {
if (onwordclick !== undefined) return 'pointer';
})
.on("mouseover", function(d, i) {
if (onwordclick !== undefined) {
d3.select(this).transition().style('font-size', d.size + 3 + 'px');
}
})
.on("mouseout", function(d, i) {
if (onwordclick !== undefined) {
d3.select(this).transition().style('font-size', d.size + 'px');
}
})
.on("click", function(d, i) {
if (onwordclick !== undefined) {
onwordclick(d,i);
}
});

vis.transition()
.attr("transform", "translate(" + [w >> 1, h >> 1] + ")scale(" + scaling + ")");
};

function update() {
var words = layout.words();
fontSize = d3.scale[scale]().range([10, 100]);
if (words.length) {
fontSize.domain([+words[words.length - 1].size || 1, +words[0].size]);
}
}

return d3.rebind(wordcloud, layout, 'on', 'words', 'size', 'font', 'fontStyle', 'fontWeight', 'spiral', 'padding');
}

if (typeof module === "object" && module.exports) module.exports = wordcloud;
else d3.wordcloud = wordcloud;
})();

Loading…
Cancel
Save