-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Markus Block
committed
Jul 16, 2024
1 parent
bdb2b0c
commit f76820e
Showing
9 changed files
with
266 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,68 @@ | ||
# NgxWordMorph | ||
# Ngx Word-Morph Component | ||
|
||
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.3.0. | ||
`@omnedia/ngx-word-morph` is an Angular library designed to facilitate word morphing animations within Angular applications. | ||
|
||
## Code scaffolding | ||
## Features | ||
- Morph words within your Angular application. | ||
- Easily customizable. | ||
|
||
Run `ng generate component component-name --project ngx-word-morph` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project ngx-word-morph`. | ||
> Note: Don't forget to add `--project ngx-word-morph` or else it will be added to the default project in your `angular.json` file. | ||
## Installation | ||
|
||
## Build | ||
Install the library using npm: | ||
|
||
Run `ng build ngx-word-morph` to build the project. The build artifacts will be stored in the `dist/` directory. | ||
```bash | ||
npm install @omnedia/ngx-word-morph | ||
``` | ||
|
||
## Publishing | ||
## Usage | ||
|
||
After building your library with `ng build ngx-word-morph`, go to the dist folder `cd dist/ngx-word-morph` and run `npm publish`. | ||
Import the `NgxWordMorphComponent` in your Angular module: | ||
|
||
## Running unit tests | ||
```typescript | ||
import { NgxWordMorphComponent } from '@omnedia/ngx-word-morph'; | ||
|
||
Run `ng test ngx-word-morph` to execute the unit tests via [Karma](https://karma-runner.github.io). | ||
@Component({ | ||
... | ||
imports: [ | ||
... | ||
NgxWordMorphComponent, | ||
], | ||
... | ||
}) | ||
``` | ||
|
||
## Further help | ||
Use the component in your template: | ||
|
||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. | ||
```html | ||
<om-word-morph [words]="['Hello', 'World']" styleClass="custom-class"></om-word-morph> | ||
``` | ||
|
||
## API | ||
|
||
```html | ||
<om-word-morph | ||
[words]="words" | ||
[morphDuration]="morphDuration" | ||
[morphDelay]="morphDelay" | ||
styleClass="your-custom-class" | ||
></om-word-morph> | ||
``` | ||
|
||
Starts the word morphing effect. | ||
|
||
- `words`: An array of strings to be animated. | ||
- `morphDuration`: (optional): The duration of the morphing animation in milliseconds. Default is 1000. | ||
- `morphDelay`: (optional): The delay between morphing one word to the next in milliseconds. Default is 5000. | ||
- `styleClass`: (optional): Add a class to the `<div>` wrapper tag. | ||
|
||
## Styling | ||
If you want to style the text, do it globally via the `styleClass`. <br> | ||
To change the font size make sure to change the `--om-word-morph-font-size` variable instead of directly changing the size. | ||
|
||
## Contributing | ||
|
||
Contributions are welcome. Please submit a pull request or open an issue to discuss your ideas. | ||
|
||
## License | ||
|
||
This project is licensed under the MIT License. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,24 @@ | ||
{ | ||
"name": "ngx-word-morph", | ||
"version": "0.0.1", | ||
"name": "@omnedia/ngx-word-morph", | ||
"version": "1.0.0", | ||
"peerDependencies": { | ||
"@angular/common": "^17.3.0", | ||
"@angular/core": "^17.3.0" | ||
}, | ||
"dependencies": { | ||
"tslib": "^2.3.0" | ||
}, | ||
"sideEffects": false | ||
"sideEffects": false, | ||
"keywords": [ | ||
"rxjs", | ||
"npm", | ||
"morph", | ||
"text", | ||
"animation" | ||
], | ||
"repository": { | ||
"url": "https://github.com/omnedia/ngx-word-morph" | ||
}, | ||
"author": "Markus Block ([email protected])", | ||
"license": "MIT" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<div class="om-word-morph" [ngClass]="styleClass"> | ||
<div id="words" class="words"> | ||
<p id="text1"></p> | ||
<p id="text2"></p> | ||
<p class="accessibility">{{ activeWord }}</p> | ||
</div> | ||
|
||
<svg id="filters"> | ||
<defs> | ||
<filter id="threshold"> | ||
<feColorMatrix | ||
in="SourceGraphic" | ||
type="matrix" | ||
values="1 0 0 0 0 | ||
0 1 0 0 0 | ||
0 0 1 0 0 | ||
0 0 0 255 -140" | ||
/> | ||
</filter> | ||
</defs> | ||
</svg> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
.om-word-morph { | ||
--om-word-morph-font-size: 8rem; | ||
|
||
width: fit-content; | ||
position: relative; | ||
|
||
.words { | ||
position: relative; | ||
margin: auto; | ||
width: fit-content; | ||
height: fit-content; | ||
top: 0; | ||
bottom: 0; | ||
|
||
-webkit-transition: 1s -webkit-filter linear; | ||
-moz-transition: 1s -moz-filter linear; | ||
-moz-transition: 1s filter linear; | ||
-ms-transition: 1s -ms-filter linear; | ||
-o-transition: 1s -o-filter linear; | ||
transition: 1s filter linear, 1s -webkit-filter linear; | ||
|
||
p { | ||
margin: 0; | ||
} | ||
|
||
.accessibility { | ||
font-size: var(--om-word-morph-font-size); | ||
visibility: hidden; | ||
} | ||
|
||
#text1, | ||
#text2 { | ||
position: absolute; | ||
width: 100%; | ||
display: inline-block; | ||
user-select: none; | ||
font-size: var(--om-word-morph-font-size); | ||
} | ||
} | ||
|
||
#filters { | ||
position: absolute; | ||
width: 0; | ||
height: 0; | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,131 @@ | ||
import { Component } from '@angular/core'; | ||
import { CommonModule } from "@angular/common"; | ||
import { Component, Input, OnDestroy, OnInit } from "@angular/core"; | ||
import { interval, of, repeat, Subject, takeUntil } from "rxjs"; | ||
|
||
@Component({ | ||
selector: 'lib-ngx-word-morph', | ||
selector: "om-word-morph", | ||
standalone: true, | ||
imports: [], | ||
template: ` | ||
<p> | ||
ngx-word-morph works! | ||
</p> | ||
`, | ||
styles: `` | ||
imports: [CommonModule], | ||
templateUrl: "./ngx-word-morph.component.html", | ||
styleUrl: "./ngx-word-morph.component.scss", | ||
}) | ||
export class NgxWordMorphComponent { | ||
export class NgxWordMorphComponent implements OnInit, OnDestroy { | ||
@Input("styleClass") | ||
styleClass?: string; | ||
|
||
@Input("words") | ||
set wordsInput(words: string[]) { | ||
this.words = words; | ||
this.textIndex = this.words.length - 1; | ||
} | ||
|
||
@Input("morphDuration") | ||
morphDuration = 1000; | ||
|
||
@Input("morphDelay") | ||
morphDelay = 5000; | ||
|
||
words!: string[]; | ||
activeWord!: string; | ||
|
||
private elts!: any; | ||
|
||
private fontSize!: number; | ||
|
||
private textIndex: number = 0; | ||
|
||
ngOnInit(): void { | ||
if (!this.words || this.words.length <= 0) { | ||
throw new Error("om-word-morph: No words were passed to the component!"); | ||
} | ||
|
||
if (this.words.length === 1) { | ||
this.words = [...this.words, ...this.words]; | ||
} | ||
|
||
this.elts = { | ||
words: document.getElementById("words") as HTMLElement, | ||
text1: document.getElementById("text1") as HTMLElement, | ||
text2: document.getElementById("text2") as HTMLElement, | ||
}; | ||
|
||
this.fontSize = parseFloat( | ||
window | ||
.getComputedStyle(this.elts.text1, null) | ||
.getPropertyValue("font-size") | ||
); | ||
|
||
this.activeWord = this.words[1]; | ||
|
||
this.initMorph(); | ||
} | ||
|
||
destroy$ = new Subject<void>(); | ||
|
||
ngOnDestroy(): void { | ||
this.destroy$.next(); | ||
this.destroy$.complete(); | ||
} | ||
|
||
initMorph(): void { | ||
this.elts.text2.style.filter = ""; | ||
this.elts.text2.style.opacity = "100%"; | ||
|
||
this.elts.text1.style.filter = ""; | ||
this.elts.text1.style.opacity = "0%"; | ||
|
||
this.morphText(); | ||
|
||
interval(this.morphDelay + this.morphDuration) | ||
.pipe(takeUntil(this.destroy$)) | ||
.subscribe(() => { | ||
this.morphText(); | ||
}); | ||
} | ||
|
||
private morphText() { | ||
let fraction = 0; | ||
|
||
this.elts.words.style.filter = "url(#threshold) blur(0.6px)"; | ||
|
||
this.elts.text1.textContent = | ||
this.words[this.textIndex % this.words.length]; | ||
this.elts.text2.textContent = | ||
this.words[(this.textIndex + 1) % this.words.length]; | ||
|
||
of([]) | ||
.pipe( | ||
repeat({ count: 100, delay: this.morphDuration / 100 }), | ||
takeUntil(this.destroy$) | ||
) | ||
.subscribe(() => { | ||
fraction += 1; | ||
this.setMorph(fraction / 100); | ||
|
||
if (fraction === 50) { | ||
this.activeWord = | ||
this.words[(this.textIndex + 1) % this.words.length]; | ||
} | ||
|
||
if (fraction === 100) { | ||
this.textIndex++; | ||
this.elts.words.style.filter = ""; | ||
} | ||
}); | ||
} | ||
|
||
private setMorph(fraction: number) { | ||
this.elts.text2.style.filter = `blur(${Math.min( | ||
8 / fraction - 8, | ||
this.fontSize | ||
)}px)`; | ||
this.elts.text2.style.opacity = `${Math.pow(fraction, 0.4) * 100}%`; | ||
|
||
fraction = 1 - fraction; | ||
this.elts.text1.style.filter = `blur(${Math.min( | ||
8 / fraction - 8, | ||
this.fontSize | ||
)}px)`; | ||
this.elts.text1.style.opacity = `${Math.pow(fraction, 0.4) * 100}%`; | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters