UNPKG

@harryjwang/simplewordcloud

Version:

A simple word cloud generator supporting English and Chinese text

213 lines 8.57 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.WordCloud = void 0; const d3 = __importStar(require("d3")); const d3_cloud_1 = __importDefault(require("d3-cloud")); const tokenizers_1 = require("./tokenizers"); // Check if we're in a browser environment const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined'; /** * Default options for the word cloud */ const DEFAULT_OPTIONS = { width: 800, height: 600, fontFamily: 'Arial, sans-serif', maxWords: 100, colors: [...d3.schemeCategory10], padding: 5, minFontSize: 10, maxFontSize: 60, rotationAngles: [0, 90], rotationProbability: 0.3 }; /** * Word cloud generator for English and Chinese text */ class WordCloud { /** * Create a new word cloud generator * @param options Configuration options for the word cloud */ constructor(options = {}) { this.options = Object.assign(Object.assign({}, DEFAULT_OPTIONS), options); } /** * Generate a word cloud from text * @param text The input text * @param language The language of the text ('english' or 'chinese') * @returns An SVG element containing the word cloud (in browser) or SVG string (in Node.js) */ generate(text, language) { // Get the appropriate tokenizer for the language const tokenizer = (0, tokenizers_1.getTokenizer)(language); // Tokenize the text and get word frequencies const wordCounts = tokenizer.tokenize(text); // Convert to array and sort by frequency const words = Array.from(wordCounts.entries()) .sort((a, b) => b[1] - a[1]) .slice(0, this.options.maxWords) .map(([text, size]) => ({ text, size: this.scaleFontSize(size, wordCounts), rotate: this.getRotation() })); if (isBrowser) { // Browser environment - create DOM elements // Create SVG element const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('width', this.options.width.toString()); svg.setAttribute('height', this.options.height.toString()); svg.setAttribute('class', 'wordcloud'); // Generate the layout using d3-cloud const layout = (0, d3_cloud_1.default)() .size([this.options.width, this.options.height]) .words(words) .padding(this.options.padding) .rotate((d) => d.rotate) .font(this.options.fontFamily) .fontSize((d) => d.size) .on('end', (words) => this.draw(words, svg)); layout.start(); return svg; } else { // Node.js environment - return SVG string return this.generateSVGString(words); } } /** * Generate a word cloud and return it as an SVG string * @param text The input text * @param language The language of the text ('english' or 'chinese') * @returns A string containing the SVG markup */ generateSVG(text, language) { const result = this.generate(text, language); if (typeof result === 'string') { return result; // Already a string in Node.js environment } else { return result.outerHTML; // Convert SVG element to string in browser } } /** * Generate SVG string directly (for Node.js environment) * @param words The words to include in the cloud * @returns SVG markup as a string */ generateSVGString(words) { // Run the layout synchronously const layout = (0, d3_cloud_1.default)() .size([this.options.width, this.options.height]) .words(words) .padding(this.options.padding) .rotate((d) => d.rotate) .font(this.options.fontFamily) .fontSize((d) => d.size); // Force the layout to run synchronously layout.start(); const processedWords = layout.words(); // Generate SVG string manually const colorScale = d3.scaleOrdinal(this.options.colors); let svgString = `<svg width="${this.options.width}" height="${this.options.height}" class="wordcloud">`; svgString += `<g transform="translate(${this.options.width / 2},${this.options.height / 2})">`; processedWords.forEach((d, i) => { const color = colorScale(i.toString()); const text = d.text || ''; svgString += `<text text-anchor="middle" transform="translate(${d.x},${d.y}) rotate(${d.rotate})" font-size="${d.size}px" font-family="${this.options.fontFamily}" fill="${color}">${text}</text>`; }); svgString += '</g></svg>'; return svgString; } /** * Scale the font size based on word frequency * @param count The word count * @param wordCounts Map of all word counts * @returns The scaled font size */ scaleFontSize(count, wordCounts) { const counts = Array.from(wordCounts.values()); const minCount = Math.min(...counts); const maxCount = Math.max(...counts); // Linear scaling between min and max font size if (minCount === maxCount) { return this.options.maxFontSize; } return this.options.minFontSize + (count - minCount) / (maxCount - minCount) * (this.options.maxFontSize - this.options.minFontSize); } /** * Get a random rotation angle for a word * @returns The rotation angle in degrees */ getRotation() { if (Math.random() > this.options.rotationProbability) { return 0; } const angles = this.options.rotationAngles; return angles[Math.floor(Math.random() * angles.length)]; } /** * Draw the word cloud on the SVG element (browser only) * @param words The words to draw * @param svg The SVG element to draw on */ draw(words, svg) { if (!isBrowser) return; // Safety check const colorScale = d3.scaleOrdinal(this.options.colors); const g = document.createElementNS('http://www.w3.org/2000/svg', 'g'); g.setAttribute('transform', `translate(${this.options.width / 2},${this.options.height / 2})`); words.forEach((d, i) => { const text = document.createElementNS('http://www.w3.org/2000/svg', 'text'); text.setAttribute('text-anchor', 'middle'); text.setAttribute('transform', `translate(${d.x},${d.y}) rotate(${d.rotate})`); text.setAttribute('font-size', `${d.size}px`); text.setAttribute('font-family', this.options.fontFamily); text.setAttribute('fill', colorScale(i.toString())); text.textContent = d.text || ''; g.appendChild(text); }); svg.appendChild(g); } } exports.WordCloud = WordCloud; //# sourceMappingURL=wordcloud.js.map