'How to import this old library called TagCanvas?
I am attempting to utilize an old library with React/Typescript to make a Sphere Word Cloud as seen here.
This is what I've done thus far.
Create a path node_modules/tagcanvas/dist/tagcanvas.js with this file.
Follow the installation instructions.
With the following code, we enter the catch block and myCanvasContainer element.style.display becomes none which means TagCanvas.Start fails to instantiate in the try block.
When I log TagCanvas, it's an empty object.
I've tried different ways of importing TagCanvas. ex. import * as TagCanvas
import * as React from 'react';
import TagCanvas from 'tagcanvas/dist/tagcanvas';
const Test: React.FC = () => {
console.log('tagCanvas', TagCanvas)
React.useEffect(() => {
try {
TagCanvas.Start('myCanvas');
} catch(e) {
// something went wrong, hide the canvas container
document.getElementById('myCanvasContainer').style.display = 'none';
}
});
return (
<div>
<div id="myCanvasContainer">
<canvas width="300" height="300" id="myCanvas">
<p>Anything in here will be replaced on browsers that support the canvas element</p>
<ul>
<li><a href="http://www.google.com" target="_blank">Google</a></li>
<li><a href="/fish">Fish</a></li>
<li><a href="/chips">Chips</a></li>
<li><a href="/salt">Salt</a></li>
<li><a href="/vinegar">Vinegar</a></li>
</ul>
</canvas>
</div>
</div>
);
};
Solution 1:[1]
I know you asked this long back but since I was facing the same problem, here's how I solved it.
So the problem is that we cannot import the tagcanvas.js file any of the conventional import statements because it is written as a bunch of function definitions that are get executed when import through tag. That way you're able to call those functions from Vanilla js, eg TagCanvas.Start(). Here's what you can do instead.
Link the js file to your index.html using tag.
<script src="/js/tagcanvas.js"></script>
Now since you're not importing the library from a react component, your useEffect will give an error because TagCanvas is not defined in the scope. We can use a neat js trick here which is the eval() function. The eval function accepts a code snippet as a string and executes it in the browser.
useEffect(() => {
eval(
`try {
TagCanvas.Start(
'myCanvas',
'',
{textColour: '${props.theme.fontPrimary}',outlineColour: '#0000'}
);
}
catch(e) {
document.getElementById('myCanvasContainer').style.display = 'none';
}`
);
}, [props.theme]);
This also gives you the flexibility to re-render the canvas from states and props like in the example above.
Solution 2:[2]
I had some issues implementing the Snehil's solution, so here's how I solved it.
I loaded the minified.js (tagcanvas.min.js) in my <head> and I implemented useEffect to apply the js that would populate the canvas.
import Head from 'next/head';
import React, { useEffect } from "react";
import skillsStyles from "../styles/Skills.module.css"
const skills = [
{ href: "#git_", title: "Git" },
{ href: "#json_", title: "JSON" },
{ href: "#solidity_", title: "Solidity" },
{ href: "#html_", title: "HTML" },
{ href: "#react_", title: "React" },
{ href: "#python_", title: "Python" },
{ href: "#sql_", title: "SQL" },
{ href: "#shopify_", title: "Shopify" },
{ href: "#aws_", title: "AWS" },
{ href: "#wordpress_", title: "WordPress" },
{ href: "#npm_", title: "npm" },
{ href: "#css_", title: "CSS" },
{ href: "#jquery_", title: "jQuery" },
{ href: "#js_", title: "JavaScript" },
{ href: "#c++_", title: "C++" },
{ href: "#java_", title: "Java" },
{ href: "#php_", title: "PHP" },
{ href: "#selenium_", title: "Selenium" },
{ href: "#remix_", title: "Remix" },
{ href: "#ganache_", title: "Ganache" },
{ href: "#hubspot_", title: "HubSpot" },
{ href: "#node.js_", title: "Node.js" },
{ href: "#hiveos_", title: "HiveOS" },
{ href: "#crypto_", title: "Crypto" },
{ href: "#mining_", title: "Mining" },
{ href: "#photoshop_", title: "Photoshop" },
{ href: "#illustrator_", title: "Illustrator" },
{ href: "#premier-pro_", title: "Premier Pro" },
{ href: "#truffle_", title: "Truffle" },
{ href: "#pyqt_", title: "PyQT" },
{ href: "#hardhat_", title: "Hardhat" }
];
export const Skills = () => {
useEffect(() => {
console.log("Loading TagCanvas...");
TagCanvas.wheelZoom = false;
TagCanvas.textFont = "Raleway, sans-serif";
TagCanvas.textColour = "white";
TagCanvas.textHeight = 26;
TagCanvas.outlineMethod = "size";
TagCanvas.outlineIncrease = 10;
TagCanvas.maxSpeed = 0.03;
TagCanvas.minBrightness = 0.2;
TagCanvas.depth = 0.92;
TagCanvas.pulsateTo = 0.6;
TagCanvas.initial = [0.1, -0.1];
TagCanvas.decel = 0.98;
TagCanvas.reverse = true;
TagCanvas.hideTags = false;
TagCanvas.shadow = false;
TagCanvas.shadowBlur = 3;
TagCanvas.weight = false;
TagCanvas.imageScale = null;
TagCanvas.fadeIn = 1000;
TagCanvas.clickToFront = 600;
TagCanvas.width = window.innerWidth;
TagCanvas.height = window.innerHeight;
try {
TagCanvas.Start("tagcanvas", "taglist");
} catch (e) {
console.log("Canvas error.");
console.log(e);
}
}, [])
return (
<>
<Head>
<script type="text/javascript" src="/utils/tagcanvas.min.js"></script>
</Head>
<div id="skill-sphere" className={`${skillsStyles.tagcanvas} flex`}>
<canvas
id="tagcanvas"
width="820"
height="600"
style={{
maxWidth: '1000px',
width: '100%',
zIndex: '99',
position: 'relative',
margin: '0 auto'
}}
className="to-fade-in fast-anim"
>
</canvas>
</div>
<div id="taglist" style={{ display: 'none' }}>
<ul>
{skills.map(skill => (
<li key={skill.title}><a href={skill.href}>{skill.title}</a></li>
))}
</ul>
</div>
</>
)
}
Solution 3:[3]
Add the script in the html head section:
<script type="text/javascript" src="/utils/tagcanvas.min.js"></script>
Now, inside the react functional component:
import { useEffect } from 'react';
const skills = [
{ href: '#git_', title: 'Git' },
{ href: '#json_', title: 'JSON' },
{ href: '#solidity_', title: 'Solidity' },
{ href: '#html_', title: 'HTML' },
{ href: '#react_', title: 'React' },
{ href: '#python_', title: 'Python' },
];
const Skills = ({ ...rest }) => {
useEffect(() => {
console.log('Loading TagCanvas...');
const TagCanvas = window.TagCanvas;
const tagCanvasOptions = {
textColour: '#08FDD8',
outlineThickness: 0.5,
outlineColour: '#FE0853',
maxSpeed: 0.06,
freezeActive: true,
shuffleTags: true,
shape: 'sphere',
zoom: 0.8,
wheelZoom: false,
noSelect: true,
textFont: null,
freezeDecel: true,
fadeIn: 3000,
initial: [0.3, -0.1],
depth: 1.1,
};
try {
TagCanvas.Start('tagcanvas', 'taglist', tagCanvasOptions);
} catch (e) {
console.log('Canvas error.');
console.log(e);
}
}, []);
return (
<div className='container'>
<canvas
id='tagcanvas'
width='820'
height='600'
style={{
maxWidth: '1000px',
width: '100%',
zIndex: '99',
position: 'relative',
margin: '0 auto',
}}
className='to-fade-in fast-anim'
></canvas>
<div id='taglist' style={{ display: 'none' }}>
<ul>
{skills.map((skill) => (
<li key={skill.title}>
<a href={skill.href}>{skill.title}</a>
</li>
))}
</ul>
</div>
</div>
);
};
export default Skills;
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Snehil |
| Solution 2 | |
| Solution 3 | Bihan Chakraborty |
