Skip to content

Commit 4b981c7

Browse files
authored
Merge pull request #105 from peterhry/split-hook
Support a custom splitter function
2 parents cae2937 + 2b8f2ee commit 4b981c7

File tree

10 files changed

+87
-173
lines changed

10 files changed

+87
-173
lines changed

README.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ A CircleType instance creates a circular text element.
3434
**Kind**: global class
3535

3636
* [CircleType](#CircleType)
37-
* [new CircleType(elem)](#new_CircleType_new)
37+
* [new CircleType(elem, [splitter])](#new_CircleType_new)
3838
* [.radius(value)](#CircleType+radius)[<code>CircleType</code>](#CircleType)
3939
* [.radius()](#CircleType+radius) ⇒ <code>number</code>
4040
* [.dir(value)](#CircleType+dir)[<code>CircleType</code>](#CircleType)
@@ -48,11 +48,12 @@ A CircleType instance creates a circular text element.
4848

4949
<a name="new_CircleType_new"></a>
5050

51-
### new CircleType(elem)
51+
### new CircleType(elem, [splitter])
5252

5353
| Param | Type | Description |
5454
| --- | --- | --- |
5555
| elem | <code>HTMLElement</code> | A target HTML element. |
56+
| [splitter] | <code>function</code> | An optional function used to split the element's text content into individual characters |
5657

5758
**Example**
5859
```js
@@ -61,6 +62,14 @@ const circleType = new CircleType(document.getElementById('myElement'));
6162

6263
// Set the text radius and direction. Note: setter methods are chainable.
6364
circleType.radius(200).dir(-1);
65+
66+
// Provide your own splitter function to handle emojis
67+
// @see https://github.com/orling/grapheme-splitter
68+
const splitter = new GraphemeSplitter()
69+
new CircleType(
70+
document.getElementById('myElement'),
71+
splitter.splitGraphemes.bind(splitter)
72+
);
6473
```
6574
<a name="CircleType+radius"></a>
6675

assets/stylesheets/screen.css

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,9 @@ h3 {
5151

5252
code {
5353
display: block;
54-
background: #101010;
55-
color: #fff;
56-
font-family: "Andale Mono", AndaleMono, monospace;
57-
font-size: 12px;
58-
padding: 1em;
54+
font-size: 14px;
55+
padding: 1em !important;
5956
margin: 0 0 4em;
60-
white-space: pre;
6157
}
6258

6359
footer {
1.21 KB
Loading
16.4 KB
Loading

dist/circletype.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.html

Lines changed: 40 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
<script src="https://use.typekit.net/fbl0lhq.js"></script>
1010
<link rel="shortcut icon" type="image/x-icon" href="assets/favicon.ico">
1111
<link rel="stylesheet" href="assets/stylesheets/screen.css">
12+
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/monokai-sublime.min.css">
13+
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
1214
</head>
1315
<body>
1416
<div class="container">
@@ -31,175 +33,75 @@ <h2 class="strong">Features</h2>
3133
<a href="https://github.com/peterhry/circletype" class="btn">Download on GitHub</a>
3234
</p>
3335

34-
<ins
35-
class="adsbygoogle"
36-
style="display:block"
37-
data-ad-format="fluid"
38-
data-ad-layout="text-only"
39-
data-ad-layout-key="-gw-c+2p-30-2w"
40-
data-ad-client="ca-pub-2609593449239823"
41-
data-ad-slot="9041076570">
42-
</ins>
43-
<script>
44-
(adsbygoogle = window.adsbygoogle || []).push({});
45-
</script>
46-
4736
<h2 class="strong">Demos</h2>
4837
<h3 class="puffy">Basic Arc</h3>
4938
<p>Here’s some curved text that flows clockwise.</p>
5039
<div class="demo-box" id="demo-box1">
5140
<h2 id="demo1" class="demo strong">Here’s some curved text flowing clockwise.</h2>
5241
</div>
53-
<code>&lt;h2 id="demo1"&gt;Here’s some curved text flowing clockwise.&lt;/h2&gt;
54-
new CircleType(document.getElementById('demo1')).radius(384);</code>
55-
56-
<ins
57-
class="adsbygoogle"
58-
style="display:block"
59-
data-ad-format="fluid"
60-
data-ad-layout="text-only"
61-
data-ad-layout-key="-gw-c+2p-30-2w"
62-
data-ad-client="ca-pub-2609593449239823"
63-
data-ad-slot="9041076570">
64-
</ins>
65-
<script>
66-
(adsbygoogle = window.adsbygoogle || []).push({});
67-
</script>
68-
42+
<pre><code class="javascript">// &lt;h2 id="demo1">Here’s some curved text flowing clockwise.&lt;/h2&gt;
43+
new CircleType(document.getElementById('demo1'))
44+
.radius(384);</code></pre>
6945
<h3 class="puffy" id="reverse">Reversed Arc</h3>
7046
<p>By setting dir to -1, the text will flow counter-clockwise instead.</p>
7147
<div class="demo-box" id="demo-box2">
7248
<h2 id="demo2" class="demo strong">Here’s some curved text flowing counter-clockwise.</h2>
7349
</div>
74-
<code>&lt;h2 id="demo2"&gt;Here’s some curved text flowing counter-clockwise.&lt;/h2&gt;
75-
new CircleType(document.getElementById('demo2')).dir(-1).radius(384);</code>
76-
77-
<ins
78-
class="adsbygoogle"
79-
style="display:block"
80-
data-ad-format="fluid"
81-
data-ad-layout="text-only"
82-
data-ad-layout-key="-gw-c+2p-30-2w"
83-
data-ad-client="ca-pub-2609593449239823"
84-
data-ad-slot="9041076570">
85-
</ins>
86-
<script>
87-
(adsbygoogle = window.adsbygoogle || []).push({});
88-
</script>
89-
50+
<pre><code class="js">// &lt;h2 id="demo2">Here’s some curved text flowing counter-clockwise.&lt;/h2&gt;
51+
new CircleType(document.getElementById('demo2'))
52+
.dir(-1)
53+
.radius(384);</code></pre>
9054
<h3 class="puffy" id="auto">Auto Radius</h3>
9155
<p>By leaving the radius empty, CircleType.js will find the perfect radius so the text makes a complete rotation.</p>
9256
<div class="demo-box" id="demo-box3">
9357
<h2 id="demo3" class="demo strong">This text makes a complete rotation no matter how long it is. </h2>
9458
</div>
95-
<code>&lt;h2 id="demo3"&gt;This text makes a complete rotation no matter how long it is. &lt;/h2&gt;
96-
new CircleType(document.getElementById('demo3'));</code>
97-
98-
<ins
99-
class="adsbygoogle"
100-
style="display:block"
101-
data-ad-format="fluid"
102-
data-ad-layout="text-only"
103-
data-ad-layout-key="-gw-c+2p-30-2w"
104-
data-ad-client="ca-pub-2609593449239823"
105-
data-ad-slot="9041076570">
106-
</ins>
107-
<script>
108-
(adsbygoogle = window.adsbygoogle || []).push({});
109-
</script>
110-
59+
<pre><code class="js">// &lt;h2 id="demo3">This text makes a complete rotation no matter how long it is. &lt;/h2&gt;
60+
new CircleType(document.getElementById('demo3'));</code></pre>
11161
<h3 class="puffy" id="fluid">Fluid</h3>
11262
<p>Update the radius when the window is resized to create a fluid effect (try resizing your window).</p>
11363
<div class="demo-box" id="demo-box4">
11464
<h2 id="demo4" class="demo strong">This curved type shrinks and expands to fit inside its container. </h2>
11565
</div>
116-
<code>&lt;h2 id="demo4"&gt;This curved type shrinks and expands to fit inside its container. &lt;/h2&gt;
66+
<pre><code class="js">// &lt;h2 id="demo4">This curved type shrinks and expands to fit inside its container. &lt;/h2&gt;
11767
var demo4 = new CircleType(document.getElementById('demo4'));
11868
window.addEventListener('resize', function updateRadius() {
11969
demo4.radius(demo4.element.offsetWidth / 2);
12070
});
121-
updateRadius();</code>
122-
123-
<ins
124-
class="adsbygoogle"
125-
style="display:block"
126-
data-ad-format="fluid"
127-
data-ad-layout="text-only"
128-
data-ad-layout-key="-gw-c+2p-30-2w"
129-
data-ad-client="ca-pub-2609593449239823"
130-
data-ad-slot="9041076570">
131-
</ins>
132-
<script>
133-
(adsbygoogle = window.adsbygoogle || []).push({});
134-
</script>
135-
71+
updateRadius();</code></pre>
13672
<h3 class="puffy" id="fitText">Using FitText.js</h3>
137-
<p>Here’s how you can use <a href="http://fittextjs.com" target="_blank">FitText.js</a> to make the text scale (try resizing your window)</p>
73+
<p>Here’s how you can use <a href="http://fittextjs.com" target="_blank">FitText.js</a> to make the text scale (try resizing your window).</p>
13874
<div class="demo-box" id="demo-box5">
13975
<h2 id="demo5" class="demo strong">I play well with FitText.js too! </h2>
14076
</div>
141-
<code>&lt;h2 id="demo5"&gt;I play well with FitText.js too! &lt;/h2&gt;
142-
var demo5 = new CircleType(document.getElementById('demo5')).radius(180);
143-
$(demo5.element).fitText();</code>
144-
145-
<ins
146-
class="adsbygoogle"
147-
style="display:block"
148-
data-ad-format="fluid"
149-
data-ad-layout="text-only"
150-
data-ad-layout-key="-gw-c+2p-30-2w"
151-
data-ad-client="ca-pub-2609593449239823"
152-
data-ad-slot="9041076570">
153-
</ins>
154-
<script>
155-
(adsbygoogle = window.adsbygoogle || []).push({});
156-
</script>
157-
77+
<pre><code class="js">// &lt;h2 id="demo5">I play well with FitText.js too! &lt;/h2&gt;
78+
var demo5 = new CircleType(document.getElementById('demo5'))
79+
.radius(180);
80+
$(demo5.element).fitText();</code></pre>
15881
<h3 class="puffy" id="fitText">Destroy</h3>
15982
<p>Here’s how you can remove the effect from an element.</p>
16083
<div class="demo-box" id="demo-box6">
16184
<p><a href="#" class="btn" id="destroyButton">Destroy Me</a></p>
16285
<h2 id="demo6" class="demo strong">Easily remove the effect.</h2>
16386
</div>
164-
<code>&lt;button id="destroyButton">Destroy Me&lt;/button&gt;
165-
&lt;h2 id="demo6"&gt;Easily remove the effect.&lt;/h2&gt;
166-
var demo6 = new CircleType(document.getElementById('demo6')).radius(180);
167-
document.getElementById('destroyButton').addEventListener('click', demo6.destroy.bind(demo6));</code>
168-
169-
<ins
170-
class="adsbygoogle"
171-
style="display:block"
172-
data-ad-format="fluid"
173-
data-ad-layout="text-only"
174-
data-ad-layout-key="-gw-c+2p-30-2w"
175-
data-ad-client="ca-pub-2609593449239823"
176-
data-ad-slot="9041076570">
177-
</ins>
178-
<script>
179-
(adsbygoogle = window.adsbygoogle || []).push({});
180-
</script>
181-
87+
<pre><code class="js">// &lt;button id="destroyButton"&gt;Destroy Me&lt;/button&gt;
88+
// &lt;h2 id="demo6"&gt;Easily remove the effect.&lt;/h2&gt;
89+
var demo6 = new CircleType(document.getElementById('demo6'))
90+
.radius(180);
91+
document.getElementById('destroyButton')
92+
.addEventListener('click', demo6.destroy.bind(demo6));</code></pre>
18293
<h3 class="puffy" id="emoji">Emojis</h3>
183-
<p>I work with emojis!</p>
94+
<p>I work with emojis but you’ll need to provide your own splitter function. Here is an example that uses GraphemeSplitter:</p>
18495
<div class="demo-box" id="demo-box7">
185-
<h2 id="demo7" class="demo strong">🍩🍩🍩🍩🍩🍩🍩🍩🍩🍩🍩🍩🍩🍩🍩🍩🍩🍩</h2>
96+
<h2 id="demo7" class="demo strong">👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦</h2>
18697
</div>
187-
<code>&lt;h2 id="demo7"&gt;🍩🍩🍩🍩🍩🍩🍩🍩🍩🍩🍩🍩🍩🍩🍩🍩🍩🍩&lt;/h2&gt;
188-
var demo7 = new CircleType(document.getElementById('demo7'));</code>
189-
190-
<ins
191-
class="adsbygoogle"
192-
style="display:block"
193-
data-ad-format="fluid"
194-
data-ad-layout="text-only"
195-
data-ad-layout-key="-gw-c+2p-30-2w"
196-
data-ad-client="ca-pub-2609593449239823"
197-
data-ad-slot="9041076570">
198-
</ins>
199-
<script>
200-
(adsbygoogle = window.adsbygoogle || []).push({});
201-
</script>
202-
98+
<pre><code class="js">// &lt;script src="https://cdn.rawgit.com/orling/grapheme-splitter/b4500feb/index.js"&gt;&lt;/script&gt;
99+
// &lt;h2 id="demo7"&gt;👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦&lt;/h2&gt;
100+
var splitter = new GraphemeSplitter()
101+
var demo7 = new CircleType(
102+
document.getElementById('demo7'),
103+
splitter.splitGraphemes.bind(splitter)
104+
);</code></pre>
203105
<h2 class="strong">Browser Support</h2>
204106
<ul class="bullets">
205107
<li>Chrome, Firefox, Safari, Opera, Edge (last 2 versions)</li>
@@ -213,6 +115,7 @@ <h2 class="strong">Browser Support</h2>
213115
</div>
214116
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.slim.min.js"></script>
215117
<script src="https://cdnjs.cloudflare.com/ajax/libs/FitText.js/1.2.0/jquery.fittext.min.js"></script>
118+
<script src="https://cdn.rawgit.com/orling/grapheme-splitter/b4500feb/index.js"></script>
216119
<script src="dist/circletype.min.js"></script>
217120
<script>
218121
try {
@@ -280,7 +183,11 @@ <h2 class="strong">Browser Support</h2>
280183
/**
281184
* Emojis
282185
*/
283-
var demo7 = new CircleType(document.getElementById('demo7'));
186+
var splitter = new GraphemeSplitter()
187+
var demo7 = new CircleType(
188+
document.getElementById('demo7'),
189+
splitter.splitGraphemes.bind(splitter)
190+
);
284191
}
285192
</script>
286193
<script type="text/javascript">
@@ -297,5 +204,6 @@ <h2 class="strong">Browser Support</h2>
297204
<script
298205
async
299206
src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
207+
<script>hljs.initHighlightingOnLoad();</script>
300208
</body>
301209
</html>

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "circletype",
3-
"version": "2.2.1",
3+
"version": "2.3.0",
44
"description": "A JavaScript library that lets you curve type on the web.",
55
"main": "dist/circletype.min.js",
66
"files": [

src/class.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,39 @@ const { PI, max, min } = Math;
1010
* A CircleType instance creates a circular text element.
1111
*
1212
* @param {HTMLElement} elem A target HTML element.
13+
* @param {Function} [splitter] An optional function used to split the element's
14+
* text content into individual characters
1315
*
1416
* @example
1517
* // Instantiate `CircleType` with an HTML element.
1618
* const circleType = new CircleType(document.getElementById('myElement'));
1719
*
1820
* // Set the text radius and direction. Note: setter methods are chainable.
1921
* circleType.radius(200).dir(-1);
22+
*
23+
* // Provide your own splitter function to handle emojis
24+
* // @see https://github.com/orling/grapheme-splitter
25+
* const splitter = new GraphemeSplitter()
26+
* new CircleType(
27+
* document.getElementById('myElement'),
28+
* splitter.splitGraphemes.bind(splitter)
29+
* );
30+
*
2031
*/
2132
class CircleType {
22-
constructor(elem) {
33+
constructor(elem, splitter) {
2334
this.element = elem;
2435
this.originalHTML = this.element.innerHTML;
2536

2637
const container = document.createElement('div');
38+
const fragment = document.createDocumentFragment();
2739
container.setAttribute('aria-label', elem.innerText);
2840
container.style.position = 'relative';
2941
this.container = container;
3042

31-
this._letters = splitNode(elem);
32-
this._letters.forEach(letter => container.appendChild(letter));
43+
this._letters = splitNode(elem, splitter);
44+
this._letters.forEach(letter => fragment.appendChild(letter));
45+
container.appendChild(fragment);
3346

3447
this.element.innerHTML = '';
3548
this.element.appendChild(container);

src/utils/__tests__/splitNode-test.js

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,6 @@ describe('splitNode', () => {
4545
});
4646
});
4747

48-
it('handles any node', () => {
49-
const testText = 'Some test text.';
50-
const { length } = testText;
51-
const nodeTypes = [ 'div', 'a', 'time', 'asdf' ];
52-
const nodes = nodeTypes.map(type => createNode(testText, type));
53-
54-
nodes.forEach(node => expect(splitNode(node)).toHaveLength(length));
55-
});
56-
5748
it('handles nodes with no text content', () => {
5849
expect(splitNode(createNode(''))).toHaveLength(0);
5950
});
@@ -62,18 +53,12 @@ describe('splitNode', () => {
6253
expect(splitNode(createNode(' '))).toHaveLength(0);
6354
});
6455

65-
it('allows chars to be wrapped by any tag', () => {
66-
const testText = 'X';
67-
const node = createNode(testText);
68-
const [ anchor ] = splitNode(node, 'a');
69-
const [ div ] = splitNode(node, 'div');
70-
const [ button ] = splitNode(node, 'button');
71-
const [ unknown ] = splitNode(node, 'asdf');
72-
73-
expect(anchor).toBeInstanceOf(HTMLAnchorElement);
74-
expect(div).toBeInstanceOf(HTMLDivElement);
75-
expect(button).toBeInstanceOf(HTMLButtonElement);
76-
expect(unknown).toBeInstanceOf(HTMLUnknownElement);
56+
it('accepts a custom splitter function', () => {
57+
const spans = splitNode(
58+
createNode('one-two-three-four'),
59+
string => string.split('-'),
60+
);
61+
expect(spans).toHaveLength(4);
7762
});
7863

7964
it('handles all emojis (chars whose length might be `2`)', () => {

0 commit comments

Comments
 (0)