読者です 読者をやめる 読者になる 読者になる

Debuginfo

思考とアウトプット

AngularJSでMasonryを使う

Masonryとはレンガのように要素を並べるJQueryプラグインです。 NHKスタジオパークで使われてるように大きさによって動的に要素を並べてくれます。

参考:なんだこれ!!「NHKスタジオパーク」のレスポンシブ・ウェブデザインが凄まじくレスポンシブ!!

これをAngularJSで使います。今回は余白なしのものを作りました。

ng-repeatを使ってcssでイメージwidthを100%にすればできました。

以下、コード。

journey-repeat-directiveはng-repeatで要素を作成したあとにMasonryをApplyするため。

# view
<div id="mason">
  <div class="grid-sizer"></div>
  <div class="mason_item" ng-repeat="journey in journeys" ng-model="journeys" journey-repeat-directive>
    <a href="/#/journey/{{journey.id}}"><img src="{{ journey.image }}"></a>
    <a class="overlay" style="text-decoration:none;" href="/#/journey/{{journey.id}}"><h3 class="title">{{ journey.title }}</h3><p>{{journey.description}}</p></a>
  </div>
</div>

scope.$lastを用いて終了を受け取る。

'use strict';

angular.module('myApp')
.directive('journeyRepeatDirective', function() {
    return function(scope, element, attrs) {
        if (scope.$last){

            var $container = $('#mason');
            $container.imagesLoaded(function(){ 
                $container.masonry({
                    columnWidth: ".grid-sizer",
                    itemSelector: '.mason_item'
                })
            });
        }
    };
});

データはAPI側から取得。

# controller
 $http({method: 'GET', url: '/api/top/contents' }).
    success(function(res, status, headers, config) {
        $scope.journeys = res;
    }).
    error(function(res, status, headers, config) {
    // error here
    });

CSS. ポイントは.mason_item img { width: 100% }

# stylesheet

.grid-sizer { width: 25%; }
.mason_item { width: 25%; }

.mason_item img { width: 100% }

@media screen and (max-width: 1224px) {
  .grid-sizer { width: 25%; }
  .mason_item { width: 25%; }
}

@media screen and (max-width: 720px) {
  .grid-sizer { width: 50%; }
  .mason_item { width: 50%; }
}

@media screen and (max-width: 480px) {
  .grid-sizer { width: 100%; }
  .mason_item { width: 100%; }
}
.overlay {
    width: 100%;
    /* background-color: rgba(0,0,0,0.5); */
    position: absolute;
    bottom: 0;
    left: 0;
    text-decoration: none;
    color: #fff;
    display:block;
    /* http://www.colorzilla.com/gradient-editor/ */
    /* IE9 SVG, needs conditional override of 'filter' to 'none' */
    background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzAwMDAwMCIgc3RvcC1vcGFjaXR5PSIwIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiMwNTA1MDUiIHN0b3Atb3BhY2l0eT0iMC44Ii8+CiAgPC9saW5lYXJHcmFkaWVudD4KICA8cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBmaWxsPSJ1cmwoI2dyYWQtdWNnZy1nZW5lcmF0ZWQpIiAvPgo8L3N2Zz4=);
    background: -moz-linear-gradient(top,  rgba(0,0,0,0) 0%, rgba(5,5,5,0.8) 100%); /* FF3.6+ */
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(0,0,0,0)), color-stop(100%,rgba(5,5,5,0.8))); /* Chrome,Safari4+ */
    background: -webkit-linear-gradient(top,  rgba(0,0,0,0) 0%,rgba(5,5,5,0.8) 100%); /* Chrome10+,Safari5.1+ */
    background: -o-linear-gradient(top,  rgba(0,0,0,0) 0%,rgba(5,5,5,0.8) 100%); /* Opera 11.10+ */
    background: -ms-linear-gradient(top,  rgba(0,0,0,0) 0%,rgba(5,5,5,0.8) 100%); /* IE10+ */
    background: linear-gradient(to bottom,  rgba(0,0,0,0) 0%,rgba(5,5,5,0.8) 100%); /* W3C */
    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00000000', endColorstr='#cc050505',GradientType=0 ); /* IE6-8 */

}

.overlay .title {
    text-align: center;
    font-size: 16px;
    font-weight: 350;
    margin-top: 20px;
}

.overlay p {
    margin-left: 20px;
    margin-right: 20px;
    font-weight: 100;
}

.mason_item:hover .overlay {
    color: white;
}