-
Notifications
You must be signed in to change notification settings - Fork 377
Added Icon component to easily add dynamic composed marker icons #268
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
Conversation
src/components/LIcon.vue
Outdated
for (let i = 0; i < keys.length; i++) { | ||
this.$watch(keys[i], (newVal, oldVal) => { | ||
//TODO: why is watch triggered on foreign props when changing icon size in my example? | ||
if (JSON.stringify(newVal) === JSON.stringify(oldVal)) { |
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.
I'm relatively new to Vue, so if someone could help me out how to avoid this line, I would be very thankful!
Problem is, when sliding the slider in the example, the watcher is also triggered for the fourth icon elements properties, but it should only be called for the iconSize
and iconAnchor
properties of the third icon.
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.
Vue pass any prop written in the component template to the $props, even if not defined in the props definition.
Also you don't need this method, for an inspiration please take a look at how the function in utils/propsBinder.js
works and how is used in any other component.
The gist of it is that you can write a function in the methods called: setPROPNAME and that function will be called only when your props change.
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.
Thanks for your reply and your awesome code review!
I updated the code (marked all props as custom so the component functions will get called, because Icon doesn't have setters on an existing Icon), but when you check it out and test the example, you will notice that it still doesn't behave correct.
When changing the slider, the first icon will get recreated twice (because two props are affected by the slider), AND the second icon is also recreated (because of the iconAnchor prop). This prop shouldn't change.
Also when you change the text, again the first icon is recreated twice (because of the iconSize and iconAnchor props) and the second one also twice (first correctly because of the html change but then also because of the iconAnchor prop).
------ Page load:
1541353711324 - recreate icon 1 (initial)
1541353711327 - recreate icon 2 (initial)
------ Changing slider:
1541353713991 - recreate icon 1 (iconSize)
1541353713992 - recreate icon 1 (iconAnchor)
1541353713994 - recreate icon 2 (iconAnchor)
------ Changing text:
1541353720983 - recreate icon 1 (iconSize)
1541353720985 - recreate icon 1 (iconAnchor)
1541353720986 - recreate icon 2 (iconAnchor)
1541353720988 - recreate icon 2 (html slot)
So two problems:
- When two or more props on the same component are change simultanuosly, is it possible to trigger a recreation only once?
- Why are all props detected as changed (even on different icon components), when only one of them changes?
I hope you can help me out here too! :)
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.
@byWulf this could be an issue with the fact that the icon component gets recreated by his parent ( marker) you can check this by verifying that the mounted / updated lifecycle hooks get called.
there is a lot of performance issues with icon and markers but I have the feeling that you can get it right ( and I will help you to do so )
Really appreciate all your efforts and attitude to this!
If you want to discuss this more faster ping me on Discord, in VueLand you can find me by the name of DonNico
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.
@lordfuoco I spent the last night on analysing and tweaking the performance.
Problem 1 was in the example, that I didn't bind computed values to the component, but directly binded arrays (<l-icon :icon-anchor="[0, 50]" />
). This led to vue thinking the value has changed on every check. <l-icon :icon-anchor="iconAnchor" />
+ `computed: { iconAnchor() { return [0, 50]; }}`` solved this.
Problem 2 with the "if multiple props were affected by a single change, the icon gets recreated also multiple times" was solved by scheduling a recreation on $nextTick
and remember in a data variable, if recreation in this tick already happend, if multiple recreations were scheduled.
Also I added another tweak: If only the html content changed, I just swap the HTML in the DOM and don't recreate the icon itself.
In my real world project (880 markers, where only few of them have individual divIcons) it was recommended to put the default icons in data variables and bind them to the icon
prop of the marker and add an v-if
to the l-icon
component. Works like a charme now :)
Looking forward for your feedback/code review on the current status, so we could release it soon :)
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.
@byWulf Amazing work! I will need to go through it thoroughly, but I think that by the end of the day I should be able to check it
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.
Very good work! Please address my comments and then we can proceed to merge this.
We will need to do some performance tests but it seems okay to me.
Please remember to run npm run lint
or enable an automatic linter in your editor of choice :)
src/components/LIcon.vue
Outdated
name: 'LIcon', | ||
mixins: [Options], | ||
props: { | ||
iconUrl: String, |
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.
On the props please define the default value even if null
or undefined
this triggers linting errors :)
src/components/LIcon.vue
Outdated
for (let i = 0; i < keys.length; i++) { | ||
this.$watch(keys[i], (newVal, oldVal) => { | ||
//TODO: why is watch triggered on foreign props when changing icon size in my example? | ||
if (JSON.stringify(newVal) === JSON.stringify(oldVal)) { |
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.
Vue pass any prop written in the component template to the $props, even if not defined in the props definition.
Also you don't need this method, for an inspiration please take a look at how the function in utils/propsBinder.js
works and how is used in any other component.
The gist of it is that you can write a function in the methods called: setPROPNAME and that function will be called only when your props change.
@byWulf Merged, I did not find anything to complain about in the code ;) |
@lordfuoco Thanks again for the great review and response! |
@byWulf @lordfuoco - thanks for this. This is the exact feature I was looking for today - so glad it's been implemented. Seems to be working perfectly for me so far. |
@byWulf I am almost done writing the docs, the base of it. When I am done would you like to refine the section about l-icon ? with tips and stuff, since you wrote it :) |
@lordfuoco just let me know when I can help :) |
@byWulf the documentation is online :) the docs are run with docsify |
Hi all, I'm not sure the custom text is working in the div icons, it only seems to show an image – not the divIcon content. The example isn't showing text for me either |
@blackspike the example that you linked does not use the custom icon, maybe you linked not the one that you mentioned ? Can we see a bit of your component code ? |
Apologies the link does not go directly to the example, same page but last example in the list Custom Marker Icons , there's a text box called 'Custom text' that doesn't seem to work. |
On the example it seems to be throwing the same error I am getting in my project which seems to prevent it from working correctly: I am under the impression that the following should work: <l-marker :key="grid.id" :lat-lng="grid.getCenter()">
<l-icon class-name="zone-label">
<div class="zone-text">test</div>
</l-icon>
</l-marker> |
I will give a look here @blackspike @MagicTrevor. Sorry for the delay I am a bit swamped at the moment. if anyone wants to take this please let me know it would be really helpful |
Hey @DonNicoJs , just started looking into this when you wrote that (telapathy :D). And I found the bug and created a PR which fixes divIcons :) See #342 |
Thanks @byWulf! If this is resolved will there be a patch release? Or an updated 2.0.0-beta? |
@MagicTrevor I think I am releasing 2.0.0 as not beta soon with this fix included. In this week I think. I just need to update the docs |
As suggested in #267 I added a
LIcon
component which can be placed inside a marker for dynamically generating the icon.This way you can bind dynamic values to properties of the icon (f.e. icon size to make the icon smaller on zoom out) and you can place HTML code inside the
<l-icon>
tag to transform it into aL.divIcon
, which updates its content as Vue rerenders the slot template.I also added an example file (examples/src/components/Icon.vue) to see the different implementation possibilities.