saurabh's avatar

Vue interfering with HTML5 canvas somehow?

Hi!

So I have been trying to get a webpage working which displays thumbnails on the left side (side-navbar) and the main image on the right side (main content).

The expected functionality is - click on the thumbnail and the main image shows up on a canvas on the right. Then there are some controls like grayscaling etc which the user can use to change the way the image looks.

I have got a simple example of a button changing the canvas via Vuejs at jsbin - (http://jsbin.com/mexozuquho/edit?html,js,output ) which works fine.

However, this seems to, surprisingly, not work on my development environment which, admittedly, isn't the exact same code but I don't see anything in there which should affect the functionlity

Here is the relevant code snippet:

@section('content')
    <div class="container-fluid" id="app">
        <div class="row">
            <div class="col-sm-3 col-md-2 sidebar">
                <ul class="nav nav-sidebar">
                <template v-for="photo in photos">
                    <li @click="setActivePhoto(photo)">
                        <a href="#">
                            <img :src="getThumbLink(photo.filename)" class="img-responsive">
                        </a>
                    </li>
                </template>
                </ul>
            </div>

            <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
                <div class="row placeholders">
                    <canvas id="myCanvas" width="800" height="400" style="border:1px solid #d3d3d3;">
                    Your browser does not support the HTML5 canvas tag.</canvas>
                </div>


                <my-photo-canvas v-if="isPhotoActive"
                                :photo="activePhoto"
                ></my-photo-canvas>
            </div>
      </div>
    </div>
@endsection

and the corresponding javascript

<script type="text/javascript">
    var ctx = document.getElementById('myCanvas').getContext('2d');

    var canvasImg = new Image();

    canvasImg.onload = function() {
        ctx.drawImage(canvasImg, 0, 0);
    };

    canvasImg.src = 'https://upload.wikimedia.org/wikipedia/en/6/6b/Free_by_chris_anderson_bookcover.jpg';

    let vm = new Vue({
        el: '#app',

        data: {
            photos: {!! $photos !!},
            activePhoto: [],
        },

        computed: {
            isPhotoActive: function() {
                return this.activePhoto.id !== undefined;
            }
        },

        methods: {
            setActivePhoto: function (activePhoto) {
                // check if active photo exists previously
                if (this.activePhoto.id === undefined) {
                    this.activePhoto = activePhoto;
                } else {
                    // finally set active photo
                    this.activePhoto = activePhoto;
                }

                // check if photo attributes have been jsonified
                if (this.activePhoto.cleaned === undefined) {
                    this.activePhoto.attributes = JSON.parse(this.activePhoto.attributes);
                    this.activePhoto.cleaned = true;
                }

                this.updateCanvas(this.getMainLink(activePhoto.filename));
                // console.log(window.location.origin + this.getMainLink(activePhoto));
            },

            getThumbLink: function(filename) {
                return '/storage/thumbs/th-' + filename;
            },

            getMainLink: function(filename) {
                return '/storage/photos/' + filename;
            },

            updateCanvas: function(link) {
                canvasImg.src = window.location.origin + link;
                // console.log(window.location.origin + link);
            }
        }
    });
</script>

I have followed the runtime in chrome debug tools and the onload method on the canvasImg is called when a thumbnail is clicked. However, all I get is a blank canvas with border.

If I remove the Vue instance completely in the above example, the canvas does display the image which is immediately set after the declaration, but nothing comes with Vue in there.

What am I missing?

Thanks, Saurabh

0 likes
4 replies
CodeNathan's avatar

@saurabh this is strange but its only happening with version 2 of vue js but declare your canvas after your vue js instance and it should work

    var vm = new Vue({
      el : '#app',
      methods : {
        setImage: function() {
          canvasImg.src = 'https://upload.wikimedia.org/wikipedia/commons/9/91/Spain-Location-Map%282013%29-UNOCHA-no-logo.png';
        }
      }
    });

      var ctx = document.getElementById('myCanvas').getContext('2d');

    var canvasImg = new Image();

    canvasImg.onload = function() {
        ctx.drawImage(canvasImg, 0, 0);
    };

    canvasImg.src = 'https://upload.wikimedia.org/wikipedia/en/6/6b/Free_by_chris_anderson_bookcover.jpg';
1 like
saurabh's avatar

@CodeNathan thanks a lot!!

Indeed, moving the declaration to after Vue works!

Any guesses on what could be the reason for this? Should I file a bug at Vuejs?

1 like
CodeNathan's avatar

@saurah I think its worth a mention since it doesn't happen on v1. I'll let you do the honours :)

saurabh's avatar

Cool, I will do it!

I had the same issue open on vuejs forums and have posted your solution post link over there. If nobody else comes up with an explanation in a few hours, I will file away :)

Please or to participate in this conversation.