-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handle SVG sprite #32
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,15 @@ | ||
import { Injectable } from '@angular/core'; | ||
import { Http, Response } from '@angular/http'; | ||
|
||
import { Observable } from 'rxjs/Observable'; | ||
|
||
import 'rxjs/add/observable/of'; | ||
import 'rxjs/add/operator/do'; | ||
import 'rxjs/add/operator/finally'; | ||
import 'rxjs/add/operator/map'; | ||
import 'rxjs/add/operator/share'; | ||
import 'rxjs/add/operator/mergeMap'; | ||
import 'rxjs/add/operator/delay'; | ||
|
||
import { Http, Response } from '@angular/http'; | ||
|
||
import { Injectable } from '@angular/core'; | ||
import { Observable } from 'rxjs/Observable'; | ||
|
||
@Injectable() | ||
export class SvgIconRegistryService { | ||
|
@@ -19,28 +20,45 @@ export class SvgIconRegistryService { | |
constructor(private http:Http) { | ||
} | ||
|
||
loadSvg(url:string): Observable<SVGElement> { | ||
|
||
loadSvg(url:string, symbolID:string = ''): Observable<SVGElement> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prefer symbol rather than symbolID. |
||
const orgUrl = url; | ||
url += `#${symbolID}`; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This adds # to all Urls whether or not they are using sprite symbols. I would prefer that the original Url is kept as url and the sprite or symbol Url is changed, so something like: const symbolUrl = url + `#${symbol}`; |
||
// Icon is already loaded and cached (srpite or not) | ||
if (this.iconsByUrl.has(url)) { | ||
return Observable.of(this.iconsByUrl.get(url)); | ||
} else if (this.iconsLoadingByUrl.has(url)) { | ||
return this.iconsLoadingByUrl.get(url); | ||
} else { | ||
const o = <Observable<SVGElement>> this.http.get( url ) | ||
} | ||
// Sprite required, but sprite SVG is loading, delay loading (until sprite SVG is loaded) | ||
else if (symbolID && this.iconsLoadingByUrl.has(orgUrl)) { | ||
return Observable.of(true).delay(100).mergeMap(() => this.loadSvg(orgUrl, symbolID)); | ||
} | ||
// Sprite required, sprite SVG is loaded, but sprite isn't cache yet | ||
else if (symbolID && this.iconsByUrl.get(orgUrl)) { | ||
return Observable.of(this.getSprite(this.iconsByUrl.get(orgUrl), symbolID)); | ||
} | ||
// Else start load SVG file | ||
else | ||
{ | ||
const o = <Observable<SVGElement>> this.http.get( orgUrl ) | ||
.map( (res:Response) => { | ||
const div = document.createElement('DIV'); | ||
div.innerHTML = res.text(); | ||
return <SVGElement>div.querySelector('svg'); | ||
const svg = <SVGElement>div.querySelector('svg'); | ||
if (symbolID) { | ||
this.iconsByUrl.set(orgUrl, svg); | ||
return this.getSprite(svg, symbolID); | ||
} else { | ||
return svg; | ||
} | ||
}) | ||
.do(svg => { | ||
this.iconsByUrl.set(url, svg); | ||
}) | ||
.finally(() => { | ||
this.iconsLoadingByUrl.delete(url); | ||
this.iconsLoadingByUrl.delete(orgUrl); | ||
}) | ||
.share(); | ||
|
||
this.iconsLoadingByUrl.set(url, o); | ||
this.iconsLoadingByUrl.set(orgUrl, o); | ||
return o; | ||
} | ||
} | ||
|
@@ -51,4 +69,16 @@ export class SvgIconRegistryService { | |
} | ||
} | ||
|
||
// Extract sprite | ||
getSprite(svg: SVGElement, symbolID: string) { | ||
const svgElement = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); | ||
const spriteElement: SVGSVGElement = svg.querySelector(`#${symbolID}`); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Had difficulty getting this to build without explicit casting: const spriteElement:SVGSVGElement = <SVGSVGElement>svg.querySelector(`#${symbolID}`); |
||
svgElement.setAttribute('width', spriteElement.viewBox.baseVal.width + 'px'); | ||
svgElement.setAttribute('height', spriteElement.viewBox.baseVal.height + 'px'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Setting width and height circumvents width/height styling with CSS. So, please remove these two lines of code. If setting width and height is desirable, then maybe an additional parameter in the component to instruct setting the viewbox width and height as the size. |
||
svgElement.setAttribute('viewBox', spriteElement.getAttribute('viewBox')); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tab indent please. |
||
for (let i = 0 ; i < spriteElement.childNodes.length; i++) { | ||
svgElement.appendChild(spriteElement.childNodes[i].cloneNode(true)); | ||
} | ||
return svgElement; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add additional rxjs/operators to rollup.config.js.