GithubHelp home page GithubHelp logo

sgratzl / chartjs-chart-wordcloud Goto Github PK

View Code? Open in Web Editor NEW
96.0 5.0 16.0 13.31 MB

Chart.js Word Clouds

Home Page: https://www.sgratzl.com/chartjs-chart-wordcloud/

License: MIT License

JavaScript 20.94% TypeScript 79.06%
javascript chartjs chartjs-plugin wordcloud tag-cloud word-cloud d3-cloud

chartjs-chart-wordcloud's Introduction

Chart.js Word Clouds

NPM Package Github Actions

Chart.js module for charting word or tag clouds. Adding new chart type: wordCloud.

word cloud example

Related Plugins

Check out also my other chart.js plugins:

Install

npm install --save chart.js chartjs-chart-wordcloud

Usage

see Examples

or at this Open in CodePen

Word Cloud

Data Structure

const config = {
  type: 'wordCloud',
  data: {
    // text
    labels: ['Hello', 'world', 'normally', 'you', 'want', 'more', 'words', 'than', 'this'],
    datasets: [
      {
        label: 'DS',
        // size in pixel
        data: [90, 80, 70, 60, 50, 40, 30, 20, 10],
      },
    ],
  },
  options: {},
};

Styling of elements

A word has the basic FontSpec styling options (family, color, ...). In addition it has several options regarding rotating the text.

Controller options:

export interface IWordCloudControllerDatasetOptions
extends IControllerDatasetOptions,
ScriptableAndArrayOptions<IWordElementOptions>,
ScriptableAndArrayOptions<ICommonHoverOptions> {
/**
* whether to fit the word cloud to the map, by scaling to the actual bounds
* @default true
*/
fit: boolean;
}

Word element options:

export interface IWordElementOptions extends IFontSpec {
/**
* rotation of the word
* @default undefined then it will be randomly derived given the other constraints
*/
rotate: number;
/**
* number of rotation steps between min and max rotation
* @default 2
*/
rotationSteps: number;
/**
* angle in degree for the min rotation
* @default -90
*/
minRotation: number;
/**
* angle in degree for the max rotation
* @default 0
*/
maxRotation: number;
/**
* padding around each word while doing the layout
* @default 1
*/
padding: number;
}

ESM and Tree Shaking

The ESM build of the library supports tree shaking thus having no side effects. As a consequence the chart.js library won't be automatically manipulated nor new controllers automatically registered. One has to manually import and register them.

Variant A:

import { Chart } from 'chart.js';
import { WordCloudController, WordElement } from 'chartjs-chart-wordcloud';

Chart.register(WordCloudController, WordElement);
...

new Chart(ctx, {
  type: WordCloudController.id,
  data: [...],
});

Variant B:

import { WordCloudChart } from 'chartjs-chart-wordcloud';

new WordCloudChart(ctx, {
  data: [...],
});

Development Environment

npm i -g yarn
yarn install
yarn sdks vscode

Common commands

yarn compile
yarn test
yarn lint
yarn fix
yarn build
yarn docs

chartjs-chart-wordcloud's People

Contributors

dependabot[bot] avatar sgratzl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

chartjs-chart-wordcloud's Issues

Uncaught TypeError: Cannot read property 'y' of undefined

No chart drawn, exception thrown.

To Reproduce
I use Laravel Mix to build js assets. Used libs (package.json dependencies):

"dependencies": {
        "@sgratzl/chartjs-esm-facade": "^3.0.0-alpha.21",
        "@ttskch/select2-bootstrap4-theme": "^1.3.4",
        "bootstrap": "4.5.3",
        "chart.js": "^3.0.0-beta.11",
        "chartjs-chart-wordcloud": "^3.0.0-beta.9",
        "datatables.net-bs4": "^1.10.23",
        "datatables.net-buttons-bs4": "^1.6.5",
        "datatables.net-colreorder-bs4": "^1.5.3",
        "datatables.net-fixedcolumns-bs4": "^3.3.2",
        "datatables.net-fixedheader-bs4": "^3.1.8",
        "datatables.net-keytable-bs4": "^2.6.0",
        "datatables.net-responsive-bs4": "^2.2.7",
        "datatables.net-rowgroup-bs4": "^1.1.2",
        "datatables.net-rowreorder-bs4": "^1.2.7",
        "datatables.net-scroller-bs4": "^2.0.3",
        "datatables.net-searchbuilder-bs4": "^1.0.1",
        "datatables.net-searchpanes-bs4": "^1.2.2",
        "datatables.net-select-bs4": "^1.3.1",
        "jqcloud2": "^2.0.3",
        "jquery": "3.5.1",
        "jszip": "^3.6.0",
        "owl.carousel": "2.3.4",
        "pdfmake": "^0.1.70",
        "popper.js": "1.16.1",
        "select2": "^4.0.13",
        "wordcloud": "^1.1.2"
    }

HTML file:

<div id="container" style="width: 75%">
    <canvas id="test-canvas"></canvas>
</div>

JS file, composed with webpack:

import { WordCloudChart } from 'chartjs-chart-wordcloud';
import { Chart, LinearScale } from 'chart.js';

Chart.register(LinearScale);

const words = [
            { key: 'word', value: 10 },
            { key: 'words', value: 8 },
            { key: 'sprite', value: 7 },
            { key: 'placed', value: 5 },
            { key: 'layout', value: 4 },
            { key: 'algorithm', value: 4 },
        ];

const data = {
    labels: words.map((d) => d.key),
    datasets: [
        {
        label: '',
        data: words.map((d) => 10 + d.value * 10),
        },
    ],
};

new WordCloudChart(document.getElementById('test-canvas').getContext('2d'), {
    data: data,
    options: {
        title: {
            display: true,
            text: 'Chart.js Word Cloud',
        },
    },
});

Exception:
image

Place in code (i tried to use available fields of ctx object, but this leads to another error with fit property somewhere):
image

  • Version: 3.0.0-beta.9
  • Browser: Google Chrome 88.0.4324.190 (64-bit)

fit:true seems not to be the default - am I confused?

looking at the code

* whether to fit the word cloud to the map, by scaling to the actual bounds
* @default true
*/
fit: boolean;
}

it implies this will be defaulting to true, but when I instanciate a wordcloud without explicility including fit: true in the options, it seems to behave the same as if it was false.

not sure if I’m missing something obvious (quite likely!) or if this is an easy fix?

packing density / auto-scaling?

I've noticed quite a few of the clouds that I have generated are fairly sparse compared to the samples (see eg below).

Do you have any recommendations to either force it to try a few more passes for better fitment, and/or suggestions to adjust the pixel scales in the data to optimally fill the available space?

It seems that it likes to rotate things when perhaps different rotations would fit the layout/space better?

image

Page freezes on init

On initialising and creating the chart instance, the webpage freezes, and has to be force closed

To Reproduce

  1. Happening only on production

Expected behavior

Wordcloud should initialize and render

Screenshots

Context

  • Version: v3.0.0_Beta-7
  • Browser: Any

Additional context

borders and background colors?

is it possible to specify borders/background colors for the words - either within WordCloud instantiation or using existing ChartJS callbacks to get the dimensions and position of each word?

would be handy to help differentiate the words when there's a cluster of similar sized/colored words (and a handy extension if multi-line words are also possible)

Can I make sure all words always fit into canvas?

I use word clouds with some data i can't make any assumption on its weigths distribution. It's also i don't know min and max possible weights and can only assume weights scale, for example, logarithmic. But as i understood, i have to scale weights myself before feeding data into word cloud chart.
Like with line charts, scale may be changed automatically that so all the data fit on canvas. Is there some way to achieve similar behaviour in word cloud chart?

Thanks for response!

We are getting an error "ERROR Error: Canvas is already in use. Chart with ID '2' must be destroyed before the canvas can be reused." while **rebinding** the chart from API,

We are getting an error "ERROR Error: Canvas is already in use. Chart with ID '2' must be destroyed before the canvas can be reused." while rebinding the chart from API,

we have used
ctx.clear(); and ctx.destroy()
method for clearing the canvas but getting errors while used
ERROR TypeError: ctx.destroy is not a functin

ERROR Error: Canvas is already in use. Chart with ID '2' must be destroyed before the canvas can be reused.
at new Chart (chart.esm.js:5354:1)
at new WordCloudChart (index.umd.js:747:1)
at EmployeeComponent.wordcloudChart (employee.component.ts:281:21)
at employee.component.ts:339:14
at Object.next (Subscriber.js:110:1)
at SafeSubscriber._next (Subscriber.js:60:1)
at SafeSubscriber.next (Subscriber.js:31:1)
at map.js:7:1
at OperatorSubscriber._next (OperatorSubscriber.js:9:1)
at OperatorSubscriber.next (Subscriber.js:31:1)

React implementation

I'm having the following question. How can this be included in a React project as a component.
My problem is basically understanding how could I access the ctx (document.getElementById) from a React functional component. It is returning me null.

Screenshots / Sketches

This is my WordsCloud.js file for reference.

const data = {
    labels: initialWords.map((d) => d.key),
    datasets: [
      {
        label: '',
        data: initialWords.map((d) => 10 + d.value * 10),
      },
    ],
  };
  const options = {
    title: {
      display: true,
      text: 'Chart.js Word Cloud',
    },
  };
  const ctx = document.getElementById('cloudmap').getContext('2d');
  const chart = new WordCloudChart(ctx, {
    data,
    options,
  });
  return (
    <div>
      <div>
        <canvas id='cloudmap'></canvas>
      </div>
      <chart />
    </div>
  );

Context

  • Version:
  • Browser:

Additional context

make tries/factor on resize a user controlled option

in the WordCloudController there is some code to control scaling of the wordcloud:

if (tags.length < labels.length) {
if (tries > 0) {
// try again with a factor of 1.2
return run(factor * 1.2, tries - 1);
} else {
console.warn('cannot fit all text elements in three tries');
}
}
const wb = bounds[1].x - bounds[0].x;

is it possible to make the tries, and factor, options that can be passed from the users code?
(going to try and find some time to explore the logic, but not tried editing/building one of these plug-ins yet)

alternatively, is it possible to guestimate a better initial factor based on the difference between the initial pass and the available space (I’ve tried following the maths but couldn’t see an obvious answer to this!)

at the moment, I can’t see a way in the instanciating code to know that it had a problem with fitting all the elements so can’t (eg) manually scale the values myself and try again.

How to use it without npm?

Is it possible to use chartjs-chart-wordcloud without npm? For exemple by downloading it (or CDN) and then adding it to my project manually?

Documentation on options

In the documentation there is a basic example of the wordcloud plugin. What's missing for me is an explanation of how to use the options. For example, how can the colors and orientation of the words be changed? The supplied link to the source is not enough for me to see how the options parameter should be filled.

The CodePen example does not work

The codepen example does not work, the canvas stays blank. There is the following error message in the console:

chartjs-chart-wordcloud@3:1 Uncaught TypeError: a.default is not a function
    at new s (chartjs-chart-wordcloud@3:1:1910)
    at bn.buildOrUpdateControllers (chart.js@3:13:91691)
    at bn.update (chart.js@3:13:92264)
    at bn.<anonymous> (chart.js@3:13:88470)
    at bn._doResize (chart.js@3:7:5357)
    at bn._resize (chart.js@3:13:89762)
    at bn.resize (chart.js@3:13:89353)
    at n (chart.js@3:13:98477)
    at chart.js@3:13:39499
    at chart.js@3:7:5247
  • Browser: tested in Chromium and Firefox

chartjs-plugin-zoom doesn't seem to work (React)

I implemented both packages and the dependecies, followed the guide of chartjs-plugin-zoom and tried different combinations of options but nothing happened, the zoom don't work. I'm working with React and test the site on Google.

Packages:

"chart.js": "^4.3.0",
"chartjs-chart-wordcloud": "^4.2.0",
"chartjs-plugin-zoom": "^2.0.1",
"hammerjs": "^2.0.8",
"react": "^18.2.0",
"react-chartjs-2": "^5.2.0",

Below my simplified code:

General WordCloudComponent for reuse:

import { Chart } from 'react-chartjs-2';
import { Chart as ChartJS, ArcElement, CategoryScale, BarElement, LinearScale, Tooltip } from 'chart.js';
import { WordCloudChart, WordCloudController, WordElement } from 'chartjs-chart-wordcloud';
import zoomPlugin from 'chartjs-plugin-zoom';

function WordCloudComponent({ options, data }) {
  ChartJS.register(WordCloudChart, WordCloudController, WordElement, ArcElement, CategoryScale, BarElement, LinearScale, Tooltip, zoomPlugin);

  return (
    <div style={{ width: windowWidth, height: '600px', display: 'grid' }}>
      <div style={{ width: windowWidth, placeSelf: 'center', height: '600px' }}>
        <Chart type="wordCloud" options={options} data={data} />
      </div>
    </div>
  );
}

export default WordCloudComponent;

Component calling WordCloudComponent:

import { useState, useEffect } from 'react';
import { Button, Grid, OutlinedInput, Slider, Typography } from '@mui/material';
import WordCloudComponent from './WordCloudComponent';

function WordCloud() {

  const [option, setOption] = useState({});
  const [data, setData] = useState({});
  const [complete, setComplete] = useState(false);

  useEffect(() => {
    if (tagcloud) {
      setOption({
        plugins: {
          legend: {
            display: false,
          },
          zoom: {
            zoom: {
              wheel: {
                enabled: true,
              },
              pinch: {
                enabled: true,
              },
              mode: 'xy',
            },
          },
        },
        color: 'black',
      });

      const totalWeight = tagcloud.reduce((sum, item) => sum + item.weight, 0);

      setData({
        labels: tagcloud.map((tag) => tag.word),
        datasets: [
          {
            data: tagcloud
              .filter((tag) => (tag.weight >= rangedFilter[0] && tag.weight <= rangedFilter[1] ? (tag.weight / totalWeight) * calculateScalingFactor(tag.weight / totalWeight) : 0)).map((tag) => (tag.weight / totalWeight) * calculateScalingFactor(tag.weight / totalWeight)),
          },
        ],
      });
      setComplete(true);
    }
  }, [tagcloud, complete]);

  const resetFilter = () => {
    setRangedFilter([0, Math.max(...tagcloud.map((tag) => tag.weight))]);
    setComplete(false);
  };

  return (
    <>
      <Button onClick={() => setComplete(false)}>{t('common.word.filter')}</Button>
      <Button onClick={resetFilter}>{t('common.word.noFilter')}</Button>
      {complete && <WordCloudComponent options={option} data={data} />}
    </>
  );
}

export default WordCloud;

I tried the solution suggested here chartjs/chartjs-plugin-zoom#64 but nothing changes.

Also, if I similarly implement a chart directly from chart.js, the zoom works, so it's not a problem with the code.
The same problem appears with another of your package: https://github.com/sgratzl/chartjs-chart-geo

Could not find the label and dataset value in click event

options: {

    onClick: (e) => {
      
  const canvasPosition = ctx.helpers.getRelativePosition(e, ctx);

}

Getting below error

core.mjs:6461 ERROR TypeError: Cannot read properties of undefined (reading 'getRelativePosition')
at Chart.onClick (app.component.ts:37:42)
at callback (helpers.segment.js:92:1)
at Chart._handleEvent (chart.esm.js:6090:17)
at Chart._eventHandler (chart.esm.js:6072:1)
at listener (chart.esm.js:5952:1)
at Chart.event (chart.esm.js:3214:1)
at helpers.segment.js:28:1
at timer (zone.js:2561:1)
at ZoneDelegate.invokeTask (zone.js:406:1)
at Object.onInvokeTask (core.mjs:25444:1)

Word cloud showing value(weight) with Key(word)

Hi, Wordcloud is showing numbers along with words. The numbers are display in small size. How can I hide the numbers (i.e. the value field)?

Here's my code:
const chart = new Chart(document.getElementById(visual.VisualId).getContext("2d"), {
type: "wordCloud",
data: {
labels: words2.map((d) => d.key),
datasets: [
{
label: "",
data: words2.map((d) =>d.value)
}
]
},
options: {
color: ThemeCols[0].toString(),
fit:true,
padding: 2,
title: {
display: false,
},
plugins: {
legend: {
display: false
}
}
}
});

image

I am using ChartJs version 3.5.1
and word cloud version 3
Thanks

Stroke width control

Control over the stroke width on text to enhance it's usability.

User story

For my specific wordcloud with anywhere between 10-10,000 words a heavier stroke width could improve my data-visualization beauty. A way to make it so text-stroke is outside also seems desirable for smaller font-size words.

Additional context

Stroke width can be achieved fairly easy with some additional logic here

if (options.strokeStyle) {
  if(options.strokeWidth){
    ctx.lineWidth=options.strokeWidth;
  }
  ctx.strokeStyle = options.strokeStyle;
  ctx.strokeText(props.text, 0, 0);
}

Similarly it looks like outside text-stroke can be achieved via miter-limit configuration ability.

I can probably PR something up for this. These extra configs seem like low-effort non-breaking upgrades with high yield in additional utility.

Are multi-line "words" possible?

I'm working on something at the moment where I'd like to include some secondary information with the word in the word cloud...

for example, the "word" could be the name of a country, but I want on a second line (ideally in a smaller font, perhaps different color etc, and in an idea world an option to set the minimum font/pixel size for the second line at which point it disappears) the population (or gender breakdown, or other ... user can toggle what's displayed)

I've been experimenting, both with the existing code and trying to kludge something together with DataLabel overlays, but not had any luck getting something viable.

I realize it's a very niche, but maybe someone has solved the problem before

use with vue-chart-3

I'm having the following question...
How to use chartjs-chart-wordcloud with vue-chart-3 without errors?

main.ts - Vue render file

import { WordCloudController, WordElement } from 'chartjs-chart-wordcloud'
Chart.register(WordCloudController, WordElement)

Vue component file
<template>
            ...
            <div class="md:flex-1 w-full min-h-full">
                <WordCloudChart :chartData="chartData" />
            </div>
            ...
</template>

<script lang="ts">
import { computed, defineComponent, ref, watch, onMounted } from 'vue'
import { ChartData } from 'chart.js'
import { WordCloudChart } from "chartjs-chart-wordcloud";
...

export default defineComponent({
    components: { WordCloudChart},
...
    setup(props) {
         ...

        const wordsValues = computed(() => {
            return words.value.map((d) => d.value)
        })
        
        const wordsTitles = computed(() => {
            return words.value.map((d) => d.key)
        })

        onMounted(() => {
            getdpWordCloudData()
        })


        ...
        const chartData = computed<ChartData<"wordCloud">>(() => (<ChartData<"wordCloud">><unknown>{
            labels: words.value.map((e) => e.key),
            datasets: [
                {
                    label: "",
                    data: wordsValues.value,
                }
            ]
        }));

        return {chartData}
    },
})
</script>

I get this error on browser console:

       Uncaught (in promise) TypeError: Class constructor WordCloudChart cannot be invoked without 'new'
    at renderComponentRoot (runtime-core.esm-bundler.js:475:19)
    at ReactiveEffect.componentUpdateFn [as fn] (runtime-core.esm-bundler.js:4332:57)
    at ReactiveEffect.run (reactivity.esm-bundler.js:160:29)
    at setupRenderEffect (runtime-core.esm-bundler.js:4458:9)
    at mountComponent (runtime-core.esm-bundler.js:4241:9)
    at processComponent (runtime-core.esm-bundler.js:4199:17)
    at patch (runtime-core.esm-bundler.js:3791:21)
    at mountChildren (runtime-core.esm-bundler.js:3987:13)
    at mountElement (runtime-core.esm-bundler.js:3896:17)
    at processElement (runtime-core.esm-bundler.js:3868:13)

How to use hoverStyle

In your documentation you point to a part in your file where hoverStyle take a string.

export interface IWordElementHoverOptions {
  hoverColor: string;
  hoverSize: number;
  hoverStyle: string;
  hoverWeight: string;
}

I can't see anywhere where you give an example of what this string should look like or include. I'm trying to change the cursor to a pointer on hover over the word.

What string is hoverStyle expecting? is it possible to show a pointer when hovering over the words?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.