Agregando la nube de palabras de las Bitacoras de los microtalleres

This commit is contained in:
kleper 2017-11-26 14:35:59 -05:00
parent d4638253df
commit d33895f604
8 changed files with 14511 additions and 203 deletions

View File

@ -19,10 +19,9 @@ background-color: #E6E7E8;
margin-bottom: 50px; margin-bottom: 50px;
padding: 20px 40px; padding: 20px 40px;
} }
r
.subtitulo { .subtitulo {
display: block; display: block;
height: 10px; height: 10px;
border-bottom: dotted 2px #D1D3D4; border-bottom: dotted 2px #D1D3D4;
text-align: center; text-align: center;

View File

@ -9,9 +9,12 @@
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet"> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet">
<!-- jQuery Content Delivery Network --> <!-- jQuery Content Delivery Network -->
<script src="https://code.jquery.com/jquery.js"></script> <script src="https://code.jquery.com/jquery.js"></script>
<script src="https://cdn.wordart.com/wordart.min.js" async defer></script> <script src="https://cdn.wordart.com/wordart.min.js" async defer></script>
<!-- Java Script cdn --> <!-- Java Script cdn -->
<script src="js/d3.js" charset="utf-8"></script>
<script src="js/d3.layout.cloud.js"></script>
<script src="js/d3.wordcloud.js"></script>
<script src="js/bitacorasmt.json"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<link href="css/datos_visuales.css" rel="stylesheet"> <link href="css/datos_visuales.css" rel="stylesheet">
@ -80,17 +83,15 @@
<!--/convenciones colores casa de cultura--> <!--/convenciones colores casa de cultura-->
<div class="col-sm-6"> <div class="col-sm-6">
<img class="img-responsive logo"src="https://casasdecultura.bibliolabs.cc/milfs/images/secure/?file=600/a12167d2f257539b33cd2ca3ac619f20.png" alt="logo-SIP-Equipamentos-Culturales"> <img class="img-responsive logo"src="https://casasdecultura.bibliolabs.cc/milfs/images/secure/?file=600/a12167d2f257539b33cd2ca3ac619f20.png" alt="logo-SIP-Equipamentos-Culturales">
<p>* Los datos contenidos en las siguientes visualizaciones, son resultado de la <p>* Los datos contenidos en las siguientes visualizaciones, son resultado de la
información colectada, entregada, consolidada y procesada información colectada, entregada, consolidada y procesada
a través del SIP.</p> a través del SIP.</p>
</div> </div>
<!--/convenciones colores casa de cultura--> <!--/convenciones colores casa de cultura-->
<div class="col-sm-6"> <div class="col-sm-6">
<p>Con el SIP buscamos mediante un modelo de manejo de <strong>Datos Abiertos</strong>, colectar datos de forma ágil para dar accesibilidad a todos los vinculados e interesados en los procesos de los equipamentos; se puede ver como un sistema para la creación de formularios que realmente se convierten en aplicaciones web y móbil que al manejar el ingreso de datos de manera semántica permite su posterior interpretación y procesamiento para generar gráficas, estadísticas, visualizaciones, adelantar reportes e informes, medir tendencias, comprender impacto, hacer seguimiento.</p> <p>Con el SIP buscamos mediante un modelo de manejo de <strong>Datos Abiertos</strong>, colectar datos de forma ágil para dar accesibilidad a todos los vinculados e interesados en los procesos de los equipamentos; se puede ver como un sistema para la creación de formularios que realmente se convierten en aplicaciones web y móbil que al manejar el ingreso de datos de manera semántica permite su posterior interpretación y procesamiento para generar gráficas, estadísticas, visualizaciones, adelantar reportes e informes, medir tendencias, comprender impacto, hacer seguimiento.</p>
<p> <p>
Nuestra estrategia para la capturar de toda la información que generan los Equipamentos y almacenarla de manera estructurada, que permita articular cientos de hojas electrónicas y documentos desorganizados en un sistema de datos mediante un subsistema de importación que permite subir datos almacenados en un archivo CSV.</p> Nuestra estrategia para la capturar de toda la información que generan los Equipamentos y almacenarla de manera estructurada, que permita articular cientos de hojas electrónicas y documentos desorganizados en un sistema de datos mediante un subsistema de importación que permite subir datos almacenados en un archivo CSV.</p>
<div class="row"> <div class="row">
<div class="col-8 col-sm-6"> <div class="col-8 col-sm-6">
<svg width="80" height="50"> <svg width="80" height="50">
@ -126,7 +127,6 @@ Nuestra estrategia para la capturar de toda la información que generan los Equ
Lo sentimos, su navegador no soporta svg en línea Lo sentimos, su navegador no soporta svg en línea
</svg> </svg>
<span>Popular</span></br> <span>Popular</span></br>
<svg width="80" height="50"> <svg width="80" height="50">
<rect x="50" y="20" width="80" height="50" style="fill:#949494;" /> <rect x="50" y="20" width="80" height="50" style="fill:#949494;" />
Lo sentimos, su navegador no soporta svg en línea Lo sentimos, su navegador no soporta svg en línea
@ -175,15 +175,12 @@ Nuestra estrategia para la capturar de toda la información que generan los Equ
</div> </div>
</div> </div>
</div> </div>
</section> </section>
<section> <section>
<div class="container"> <div class="container">
<p class="linea-texto"> <p class="linea-texto">
<span>Estrategia de Datos Abiertos</span> <span>Estrategia de Datos Abiertos</span>
</p> </p>
</div>
<div class="col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2 col-lg-8 col-lg-offset-2 text-center"> <div class="col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2 col-lg-8 col-lg-offset-2 text-center">
@ -242,9 +239,8 @@ Nuestra estrategia para la capturar de toda la información que generan los Equ
</div> </div>
</div> </div>
</div> </div>
</div>
</section> </section>
<!--Sección Activaciones --> <!--Sección Activaciones -->
<section class="container-fluid" id="activaciones"> <section class="container-fluid" id="activaciones">
<div class="col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2 col-lg-8 col-lg-offset-2 text-center"> <div class="col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2 col-lg-8 col-lg-offset-2 text-center">
@ -253,28 +249,22 @@ Nuestra estrategia para la capturar de toda la información que generan los Equ
</p> </p>
<p class="lead">Conozcamos cómo van las activaciones, herramienta indispensable de la gestión cultural de los equipamentos, identificate, observa, compara y concluye, lo más importante es encontrar elementos que nos permitan informarnos para tomar mejores decisiones </p> <p class="lead">Conozcamos cómo van las activaciones, herramienta indispensable de la gestión cultural de los equipamentos, identificate, observa, compara y concluye, lo más importante es encontrar elementos que nos permitan informarnos para tomar mejores decisiones </p>
<!-- <h1>Word Cloud</h1> -->
<!-- <h1>Word Cloud</h1> --> <div id='nubeactivaciones'></div>
<div id='wordcloud'></div>
<div style="width: 1000px; height: 800px;" data-wordart-src="https://cdn.wordart.com/json/h1zzzt36dt3f" ></div> <div style="width: 1000px; height: 800px;" data-wordart-src="https://cdn.wordart.com/json/h1zzzt36dt3f" ></div>
<!--Subtítulo Presupuesto --> <!--Subtítulo Presupuesto -->
<p class="subtitulo"> <p class="subtitulo">
<span>Presupuesto</span> <span>Presupuesto</span>
</p> </p>
<div> <div>
<p>Cantidad de Activaciones por equipamento en relación al presupuesto y la cantidad de beneficiarios potenciales.</p> <p>Cantidad de Activaciones por equipamento en relación al presupuesto y la cantidad de beneficiarios potenciales.</p>
<img src="svg/PresupuestoParticipantesActivaciones.svg" class="img-responsive" alt="Relación de Público y Presupuesto Microtalleres"> <img src="svg/PresupuestoParticipantesActivaciones.svg" class="img-responsive" alt="Relación de Público y Presupuesto Microtalleres">
</div> </div>
</div> </div>
</div> </div>
</section > </section >
<!--Sección Microtalleres -->
<!--Sección Microtalleres -->
<section class="container-fluid" id="microtalleres"> <section class="container-fluid" id="microtalleres">
<div class="col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2 col-lg-8 col-lg-offset-2 text-center"> <div class="col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2 col-lg-8 col-lg-offset-2 text-center">
<p class="linea-texto"> <p class="linea-texto">
@ -282,15 +272,13 @@ Nuestra estrategia para la capturar de toda la información que generan los Equ
</p> </p>
<p class="lead">Conoce la lectura del portal de Open Data del SIP de los Equipamentos y como ha sido el trabajo en torno a los Microtalleres</p> <p class="lead">Conoce la lectura del portal de Open Data del SIP de los Equipamentos y como ha sido el trabajo en torno a los Microtalleres</p>
<!-- <h1>Word Cloud</h1> --> <!-- <h1>Word Cloud</h1> -->
<div id='wordcloud'></div> <div id='nubemicrotalleres'></div>
<div style="width: 1000px; height: 800px;" data-wordart-src="https://cdn.wordart.com/json/8wqa464050pr" ></div> <div style="width: 1000px; height: 800px;" data-wordart-src="https://cdn.wordart.com/json/8wqa464050pr" ></div>
<!--Subtítulo Presupuesto --> <!--Subtítulo Presupuesto -->
<p class="subtitulo"> <p class="subtitulo">
<span>Presupuesto</span> <span>Presupuesto</span>
</p> </p>
<div class="row"> <div class="row">
<div class="col-md-7"> <div class="col-md-7">
<p>Cantidad de Microtalleres por Equipamento en relación al presupuesto y la cantidad de beneficiarios potenciales.</p> <p>Cantidad de Microtalleres por Equipamento en relación al presupuesto y la cantidad de beneficiarios potenciales.</p>
@ -300,24 +288,31 @@ Nuestra estrategia para la capturar de toda la información que generan los Equ
<img src="svg/Presupuesto-Circulos_microtalleres.svg" class="img-responsive" alt="Relación de Público y Presupuesto Microtalleres"> <img src="svg/Presupuesto-Circulos_microtalleres.svg" class="img-responsive" alt="Relación de Público y Presupuesto Microtalleres">
<p>* La falta de registro de datos, así como registros faltantes de beneficiarios potenciales, afectan el resultado de la visualización. </p> <p>* La falta de registro de datos, así como registros faltantes de beneficiarios potenciales, afectan el resultado de la visualización. </p>
</div> </div>
</div> </div>
<!--Sección Género --> <!--Sección Género -->
<p class="subtitulo"> <p class="subtitulo">
<span>Género</span> <span>Género</span>
</p> </p>
<img style="display: inline-block !important;"src="svg/Hombres-Mujeres_microtalleres.svg" class="img-responsive float-right" alt="Relación de Público y Presupuesto Microtalleres"> <img style="display: inline-block !important;"src="svg/Hombres-Mujeres_microtalleres.svg" class="img-responsive float-right" alt="Relación de Público y Presupuesto Microtalleres">
<!--Sección Público Objetivo & Categorías -->
<!--Sección Público Objetivo & Categorías --> <p class="subtitulo">
<p class="subtitulo">
<span>Público Objetivo & Categorías </span> <span>Público Objetivo & Categorías </span>
</p> </p>
<img style="display: inline-block !important;"src="svg/Publicos-Disciplinas_microtalleres.svg" class="img-responsive float-right" alt="Relación de Público y Presupuesto Microtalleres"> <img style="display: inline-block !important;"src="svg/Publicos-Disciplinas_microtalleres.svg" class="img-responsive float-right" alt="Relación de Público y Presupuesto Microtalleres">
</section > <div id='wordcloud'></div>
<script>
d3.wordcloud()
.size([900, 600])
.fill(d3.scale.ordinal().range(["#2099a7", "#a4cc39", "#e5842c", "#b80d6b"]))
.words(words)
.onwordclick(function(d, i) {
if (d.href) { window.location = d.href; }
})
.start();
</script>
</div>
<!-- Bootstrap core JavaScript <!-- Bootstrap core JavaScript

26
js/LICENSE.d3 Normal file
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.

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
js/bitacorasmt.json Normal file

File diff suppressed because it is too large Load Diff

9215
js/d3.js vendored Normal file

File diff suppressed because it is too large Load Diff

401
js/d3.layout.cloud.js Normal file
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
js/d3.wordcloud.js Normal file
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;
})();