I'm using couple of polymer's iron-icons from each category and would prefer not importing the whole set. is there a possibility (or tooling/plugin for vulcanize) to only import the ones i need? and have a smaller HTML file to serve?
You can use the Polymer Iconset Generator tool to create your own custom subset of the default iron-icons. It's really handy and it sounds like exactly what you need.
To import only the one you need you can create your own file custom-icons.html that will have the same base as the iron-icons.html.
You just have to change the 'name' attribute from the <iron-iconset-svg></iron-iconset-svg> node to match the custom name you will use. I will use 'custom-icons' you will use this name to insert an icon after.
Your file will looks like this :
<link rel="import" href="../bower_components/iron-iconset-svg/iron-iconset-svg.html">
<link rel="import" href="../bower_components/iron-icon/iron-icon.html">
<iron-iconset-svg name="custom-icons" size="24">
<svg>
<defs>
.
.
.
</defs>
</svg>
</iron-iconset-svg>
Inside the <defs>...</defs> node you just have to copy from the iron-icons set or from the other icons set (device, editor, notification...) the <g> node, that correspond to the icon you want to use, and insert it inside your custom-icons.html file.
For example we want the menu icon from the iron-icons.html file.
Just copy this element :
<g id="menu"><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/></g>
and paste it inside the <defs>...</defs> node inside your custom file.
You will have this :
<link rel="import" href="../bower_components/iron-iconset-svg/iron-iconset-svg.html">
<link rel="import" href="../bower_components/iron-icon/iron-icon.html">
<iron-iconset-svg name="custom-icons" size="24">
<svg>
<defs>
<g id="menu"><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/></g>
</defs>
</svg>
</iron-iconset-svg>
Now in your application just import this file instead of the iron-icons and use the icon like this :
<iron-icon icon="custom-icons:menu"></iron-icon>
If you change the 'id' attribute value in the <g></g> node (menu2 for example), use it like this :
<iron-icon icon="custom-icons:menu2"></iron-icon>
For more details go check the Rob Dodson polycast : Custom icons with Iron Iconsets
You can also download them directly and individually, in the format your want, independently of Polymer, from Google's Material Design website:
https://material.io/icons/
This way you'll get the new added icons, too.
Related
Edit: trying to create a mcve I wasn't able to repro the issue. Now I'm completely baffled. Works on codesandbox, not in my project.
Initial question
I want to create a dynamic inline SVG element and map its rotation to an [(ngModel)]. Nothing fancy.
The fancy part is that I want to use a <filter> with a <feDropShadow>. And I want the shadow to be dynamic (always point up, regardless of the needle's rotation). It's something I've done before using Vue.
Here's a fiddle demonstrating the effect: https://jsfiddle.net/websiter/y4ghan0k/
But, for the life of me, I can't get the <feDropShadow> to work in Angular when the <svg> is inlined in the template. It just won't display. No error or warning. If I insert it as <img src="path/to/svg"> it works as expected (the shadow is displayed), but then I can't rotate the path anymore, as the element transformed needs to be a child of the element bearing the filter.
Note it's not because of this url() filter issue - I am prefixing the filter with this.location.path().
Here's the gist of my Angular code:
component.ts:
import { Location } from '#angular/common';
export class SomeComponent {
constructor(private location: Location) {}
dsLink = `url(${this.location.path()}#drop-shadow)`;
}
component.html:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="180" y="100"
viewBox="0 0 180 100" xml:space="preserve">
<defs>
<filter xmlns="http://www.w3.org/2000/svg" id="drop-shadow" height="130%">
<feDropShadow dx="0" dy="-4" flood-color="rgba(0,0,0,.65)"/>
</filter>
</defs>
<g [attr.filter]="dsLink">
<path fill="#fff" d="M102.2,89.5c0-0.1,0-0.1,0-0.2c0-0.2,0-0.4-0.1-0.6L92.9,6.8c-0.1-0.8-3.2-0.9-3.3,0
L78.7,88.5c-0.1,0.2-0.1,0.4-0.1,0.6c0,0.1,0,0.1,0,0.2l0,0.1c0,0,0,0.1,0.1,0.1c0.5,2.4,5.6,4.4,11.7,4.4
c6.2,0.1,11.2-1.8,11.8-4.2c0,0,0.1-0.1,0.1-0.1L102.2,89.5z">
</path>
</g>
</svg>
For simplicity, I've removed the [(ngModel)] from path which is supposed to rotate the needle.
The filter url() appears to be correct, there's no error. But the shadow is not displayed.
Is there anything special I need to do/know in order to make Angular handle <svg> elements inline?
What am I missing?
I finally cracked it so I'm posting it here, hoping it will help others.
In short: use unique ids for filters in each of your component instances. Otherwise, each instance will use the first filter found in DOM (with that id) and if that filter happens to be inside a parent with display: none, visibility:hidden or opacity: 0, applying the filter will make whatever you apply it to invisible as well.
The issue had to do with the fact I was using the same component in different tabs. This created separate instances of the component, each of them using the same id (#drop-shadow). While having duplicate ids is obviously invalid HTML, this wouldn't actually have been a problem if we weren't dealing with filters. Because, since the <defs> are identical, it wouldn't really matter if the component on the 4th tab would use the <defs> defined by the component on the first tab.
Except when dealing with <filter>s, because they are actually calculating, pixel by pixel, the rendering result, dynamically. Which means that, when the <svg> defining the <filter> is not rendered, using the filter will make the browser calculate (pixel by pixel) the result applying the filter and it always result in all the pixels being invisible.
So the solution is to assign a unique id in each separate instance of the component.
<circle
r="3"
:cx="airport.x"
:cy="airport.y"
class="airport__marker"
/>
Is this the same as v-bind:cx and v-bind:cy ?
This code looks like it comes from a Vue app. Specifically a Vue template.
:cx="airport.x" is a shortcut form of v-bind:cx="airport.x"
Which is saying get the value of attribute cx from the variable airport.x in the code.
So if airport.x = 100 then the generated SVG would have cx="100".
You can read more about this here: https://v2.vuejs.org/v2/guide/syntax.html#Shorthands
Is it possible to change default color of the TimePickerAndroid component ?
You would have to change it from the styles.xml file of android. Here's what you do:
1) Open up styles.xml: "android/app/src/main/res/values/styles.xml"
2) you'll need to add a few lines:
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="android:timePickerDialogTheme">#style/Dialog.Theme</item>
</style>
<style name="Dialog.Theme" parent="Theme.AppCompat.Light.Dialog">
<item name="colorAccent">#FF0000</item>
<item name="android:textColorPrimary">#0000FF</item>
</style>
In styles.xml you should already have:
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
If you do just add the remaining lines. If not go ahead and add them.
4) Lastly, just recompile the app. "react-native run-android". You should see the color change right away.
Using React-native, unfortunately no.
However, by changing some java files in RN and using this solution from SO you might be able to do it.
If you succeed doing this, I suggest you create a Pull Request on RN's repository as it might be very useful for other users.
You could also develop it as a module and open source via NPM.
I'm converting some existing code to use React Router.
The code currently uses <a href="#" ...>, which I am changing to <Link to=??>.
My question is:
What should I use for the "to" parameter? If I use to="#", the application routes to "/", which is not what I want.
It works if I use the current route name, but the whole idea of href="#" is that the code doesn't have to know how it is accessed.
I am using React Router 2 with history=browserHistory.
Here are a few solutions that worked for me:
<Link to={{}}>
to can take an object; sending an empty object stays on the current page
<Link to={{ search: '' }}>
In my specific case, I wanted to stay on the same page but wipe the search params, which is what this does
<Link to={window.location.pathname}>
Similar to the suggestion in Damien Leroux's answer, without the hash
<Link to="#">
This seemed to work fine for me, maybe because I'm using react-router v6
What didn't work for me:
<Link to={this.props.route.path}
I'm using functional components, so I don't have any this.props. Maybe there's another way in the react-router API to get the path.
<Link to=".">
This linked to / for me
For me this was the solution:
I used the npm module react-router-hash-link. It is quite easy to use. Docs here
import { HashLink as Link } from 'react-router-hash-link';
<Link smooth to="/#services">Services</Link>
And wrap your <App> component in <HashRouter> from npm module react-router-dom
stackoverflow answer
I think you could try something more or less like that:
<Link to={window.location.pathname} hash="/#">HASH</Link>
See there : https://github.com/reactjs/react-router/blob/master/docs/API.md#hash
This works because "this.props.route.path" is the route to the current page:
<Link to={this.props.route.path} ...
Note that if you have nested React components, you have to pass "this.path" down from the outer components, as described at https://facebook.github.io/react/docs/transferring-props.html
<Link to='#' />
this works but it will still stack your history
It works for me:
<Link className="dropdown-item" to="javascript:void()">
Link Title
</Link>
If you need to go to a specified section of your "/" path (even from another path), you can make it work with the anchor tag as well, like this:
Go to Section
Hope this helps.
I've run into a problem while attempting to use SVG marker elements in an SVG based visualization. I'm adding my changes to a web application which happens to include a base tag on every page, so that any references to CSS files, javascript files, etc can be relative.
I have some example code below which reproduces the issue. There is a line element, and a marker element defined. The marker element is referenced by the line in its 'marker-end' attribute, via uri and id of marker. Without the base tag, the arrow displays fine. With the base tag, it is not shown. The reason is because the base tag changes the way the browser resolves urls.. even for the simple id based url specified in the marker-end attribute of the line.
Is there any way I can get around this problem without having to remove the base tag?
I can't really remove it because the use of it is fairly ingrained in the product I'm working on. I need to support Firefox, Chrome and IE9+ for my webapp. Firefox and chrome both produce this problem. IE works fine (ie. arrow marker displays).
<html>
<head>
<base href=".">
<style>
.link { stroke: #999; stroke-opacity: .6; }
marker#arrow { fill: black; }
</style>
</head>
<body>
<svg width="100%" height="100%">
<defs>
<marker id="arrow" viewBox="0 -5 10 10" refX="0" refY="0" markerWidth="20" markerHeight="20" orient="auto">
<path d="M0,-5L10,0L0,5"></path>
</marker>
</defs>
<line x1="100" y1="100" x2="333" y2="333" marker-start="url(#arrow)" class="link"></line>
</svg>
</body>
</html>
The HTML <base> element is used to say "resolve all relative URLs relative not to this page, but to a new location". In your case, you've told it to resolve relative to the directory with the HTML page.
The SVG marker-mid="url(…)" attribute is a FuncIRI Reference. When you use a value like url(#foo) that relative IRI is normally resolved relative to the current page, finding the element with the foo id. But, when you use <base>, you change where it looks.
To solve this problem, use a better value. Since your base reference is the current directory, you can simply use the name of the current file:
<line … marker-mid="url(this_page_name.html#arrow)" />
If you have a different <base> href, than what you've shown, like:
<base href="http://other.site.com/whee/" />
then you will need to use an absolute href, e.g.
<line … marker-mid="url(http://my.site.com/this_page_name.html#arrow)" />
Try with javascript:
<line id="something" />
With native:
document.getElementById('something').setAttribute('marker-mid', 'url(' + location.href + '#arrow)');
With jQuery:
$('#something').attr('marker-mid', 'url(' + location.href + '#arrow)');
It just works.
In the context of a rich web app like one built on Angular, where you need to set the <base> tag to make HTML5-style navigation work, it can get messy to try to fix that in a permanent way.
In my case, the app I was working on was showing a SVG-based interactive diagram builder that would change the app url as I selected elements therein.
What I did was to add a global event handler that would fix all url(#...) inline styles in any <path> element found in the page:
$rootScope.$on 'fixSVGReference', ->
$('path').each ->
$path = $ this
if (style = $path.attr 'style')?
$path.attr 'style', style.replace /url\([^)#]*#/g, "url(#{location.href}\#"
Then trigger this handler in key places, like when the app state changes (I'm using ui-router)
$rootScope.$on '$stateChangeSuccess', ->
$timeout (-> $rootScope.$emit 'fixSVGReference'), 5
As well as anywhere where I know there'd be new/updated paths like these. Here, the $timeout thing is to account for the fact that the DOM nodes really are changed asynchronously sometime after the $stateChangeSuccess event is triggered.
In Angular 2+, you can inject the base path in your app module instead of using the <base> tag. This resolved the issue in Edge and Firefox for me.
import { APP_BASE_HREF } from '#angular/common';
#NgModule({
providers: [{
provide: APP_BASE_HREF,
useValue: '/'
}]
})
export class AppModule { }
https://angular.io/docs/ts/latest/api/common/index/APP_BASE_HREF-let.html
Ember 2.7 will replace the <base> tag with rootURL which should fix this issue.
In the meantime in my d3 for gradients I'm using the following:
.attr('fill', `url(${Ember.$(location).attr('href')}#my-gradient)`);
If you don't do this, the item you are targeting will seem to be transparent.
On Windows currently (04-2017) all Browsers behave as expected ( mask=url("#svgmask") ). Chrome, Firefox, even IE 11!! - but Edge comes up with an error.
So for Microsoft Edge you still need to give the absolute path ( mask="url(path/to/this-document.htm#svgmask)" ) for your mask ID´s when you are using a base tag in your document:
<svg viewBox="0 0 600 600" >
<defs>
<mask id="svgmask">
<image width="100%" height="100%" xlink:href="path/to/mask.svg" ></image>
</mask>
</defs>
<image mask="url(path/to/this-document.htm#svgmask)" width="600" height="600" xlink:href="path/to/image.jpg"></image>
</svg>
If you do not want want to modify / animate the svg there is a simpler solution than changing the url() parameter.
Include the svg as image:
<img src="yourpath/image.svg">
You can archive it with:
$("[marker-mid]").attr("marker-mid", function () {
return $(this).attr("marker-mid").replace("url(", "url(" + location.href);
});