-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtagcloud.js
123 lines (103 loc) · 3.72 KB
/
tagcloud.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
function TagCloud(w, h, context) {
"use strict";
this.ctx = context;
this.canvasWidth = w;
this.canvasHeight = h;
this.fontSize = this.canvasHeight / 3;
this.shape = "rectangle";
}
TagCloud.prototype.setShape = function () {
this.shape = "circle";
};
TagCloud.prototype.render = function (tags) {
this.ctx.textBaseline = "top";
tags.forEach(function (tag) {
this.placeTag(tag[0]);
}, this);
};
TagCloud.prototype.placeTag = function (tag) {
var placement;
while (!(placement = this._getNonOverlappingPlaceWithBestSize(this.fontSize, tag)))
this.fontSize *= 0.9;
this.ctx.fillStyle = this._getRandomColor();
this.ctx.fillText(tag, placement.x, placement.y);
};
TagCloud.prototype._getNonOverlappingPlaceWithBestSize = function (fontSize, tag) {
this.ctx.font = "" + fontSize + "pt " + "Arial";
var lineHeight=this.getLineHeight(fontSize);
var tagWidth = this.ctx.measureText(tag).width;
var base = new BasePlacement(
(this.canvasWidth - tagWidth) * Math.random(),
(this.canvasHeight - lineHeight) * Math.random(),
lineHeight
);
var placement;
/* jshint ignore:start */
while (placement = base.nextPlaceToTry()) {
if (this._isPlaceEmpty(placement, tagWidth, lineHeight))
break;
}
/* jshint ignore:end */
return placement;
};
TagCloud.prototype.getLineHeight = function (fontSize) {
return this.ctx.measureText('M').width * 1.2;
}
TagCloud.prototype._getRandomColor = function (){
var colors = ["aqua", "black", "blue", "fuchsia", "gray", "green", "lime", "maroon", "navy", "olive", "orange", "purple", "red", "silver", "teal"];
return colors[Math.floor(colors.length * Math.random())];
};
TagCloud.prototype._isPlaceEmpty = function (placement, width, height) {
if (placement.x < 0 || placement.y < 0 || placement.x + width > this.canvasWidth || placement.y + height > this.canvasHeight)
return false;
var pix = this.ctx.getImageData(placement.x, placement.y, width, height).data;
for (var i = 0, n = pix.length; i < n; i += 4)
if (pix[i+3])
return false;
return [[placement.x, placement.y],
[placement.x + width, placement.y],
[placement.x, placement.y + height],
[placement.x + width, placement.y + height]].every(
function(pos) {
var a = this.canvasWidth / 2;
var b = this.canvasHeight / 2;
var X = pos[0] - a;
var Y = pos[1] - b;
return (X * X / a / a + Y * Y / b / b < 1);
}, this);
};
TagCloud.prototype.getCoverage = function () {
var pix = this.ctx.getImageData(0, 0, this.canvasWidth, this.canvasHeight).data;
var pixCount = 0;
for (var i = 0, n = pix.length; i < n; i += 4) {
if (pix[i+3])
pixCount++;
}
return pixCount * 100 / this.canvasWidth / this.canvasHeight;
};
function BasePlacement(x, y, h) {
var baseX = x,
baseY = y,
scale = h,
tryNumber = 0;
this.nextPlaceToTry = function() {
if (tryNumber < this._spiralOffsets.length)
return {
x : baseX + this._spiralOffsets[tryNumber][0] * scale,
y : baseY + this._spiralOffsets[tryNumber++][1] * scale
};
};
}
function generateSpiralOffsets() {
var spiralOffsets = [];
var radius = 0;
var dr = 0.2;
for (var i = 0; radius < 40; i+=0.4, radius += dr) {
spiralOffsets.push([
radius * Math.sin(i),
radius * Math.cos(i)
]);
}
return spiralOffsets;
}
BasePlacement.prototype._spiralOffsets = generateSpiralOffsets();