Backend/Django

django 22. MagicGrid 소개 및 Articleapp 시작

meong_j 2021. 10. 10. 19:48
728x90
반응형

MagicGrid

  • 카드형 레이아웃 제공
  • 아래 Magic-Grid github 주소로 html, js, css 코드 복사

 

https://github.com/e-oj/Magic-Grid

 

GitHub - e-oj/Magic-Grid: A simple, lightweight Javascript library for dynamic grid layouts.

A simple, lightweight Javascript library for dynamic grid layouts. - GitHub - e-oj/Magic-Grid: A simple, lightweight Javascript library for dynamic grid layouts.

github.com

 

 

articleapp 생성

python manage.py startapp articleapp

 

 

settings.py 추가

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'bootstrap4',
    'accountapp',
    'profileapp',
    'articleapp',
]
  • 생성한 articleapp 앱 추가

 

메인 urls.py 추가

from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path, include

from pragmatic import settings

urlpatterns = [

    path('admin/', admin.site.urls),
    path('accounts/', include('accountapp.urls')),
    path('profiles/', include('profileapp.urls')),
    path('articles/', include('articleapp.urls')),

    # 미디어 사진 출력하기 위한 MEDIA 환경 설정 추가
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
  • articleapp url 주소 추가

 

 

urls.py

from django.urls import path

from django.views.generic import TemplateView

urlpatterns = [
    path('list/', TemplateView.as_view(template_name='articleapp/list.html'), name='list'),
]
  • articleapp의 urls.py 생성
  • 장고가 제공하는 TemplateView 설정, list.html로 지정
  • 템플릿만 지정해주면 장고가 알아서 만들어줌

 

 

/static/magicgrid.js

'use strict';

/**
 * @author emmanuelolaojo
 * @since 11/11/18
 */

/**
 * Validates the configuration object.
 *
 * @param config - configuration object
 */

var checkParams = function (config) {
  var DEFAULT_GUTTER = 25;
  var booleanProps = ["useTransform", "center"];


  if (!config) {
    throw new Error("No config object has been provided.");
  }

  for(var prop of booleanProps){
    if(typeof config[prop] !== "boolean"){
      config[prop] = true;
    }
  }


  if(typeof config.gutter !== "number"){
    config.gutter = DEFAULT_GUTTER;
  }

  if (!config.container) { error("container"); }
  if (!config.items && !config.static) { error("items or static"); }
};


/**
 * Handles invalid configuration object
 * errors.
 *
 * @param prop - a property with a missing value
 */
var error = function (prop) {
  throw new Error(("Missing property '" + prop + "' in MagicGrid config"));
};

/**
 * Finds the shortest column in
 * a column list.
 *
 * @param cols - list of columns
 *
 * @return shortest column
 */
var getMin = function (cols) {
  var min = cols[0];

  for (var col of cols) {
    if (col.height < min.height) { min = col; }
  }

  return min;
};

/**
 * @author emmanuelolaojo
 * @since 11/10/18
 *
 * The MagicGrid class is an
 * implementation of a flexible
 * grid layout.
 */

var MagicGrid = function MagicGrid (config) {
  checkParams(config);

  if (config.container instanceof HTMLElement) {
    this.container = config.container;
    this.containerClass = config.container.className;
  }
  else {
    this.containerClass = config.container;
    this.container = document.querySelector(config.container);
  }

  this.items = this.container.children;
  this.static = config.static || false;
  this.size = config.items;
  this.gutter = config.gutter;
  this.maxColumns = config.maxColumns || false;
  this.useMin = config.useMin || false;
  this.useTransform = config.useTransform;
  this.animate = config.animate || false;
  this.started = false;
  this.center = config.center;

  this.init();
};

/**
 * Initializes styles
 *
 * @private
 */
MagicGrid.prototype.init = function init () {
  if (!this.ready() || this.started) { return; }

  this.container.style.position = "relative";

  for (var i = 0; i < this.items.length; i++) {
    var style = this.items[i].style;

    style.position = "absolute";

    if (this.animate) {
      style.transition = (this.useTransform ? "transform" : "top, left") + " 0.2s ease";
    }
  }

  this.started = true;
};

/**
 * Calculates the width of a column.
 *
 * @return width of a column in the grid
 * @private
 */
MagicGrid.prototype.colWidth = function colWidth () {
  return this.items[0].getBoundingClientRect().width + this.gutter;
};

/**
 * Initializes an array of empty columns
 * and calculates the leftover whitespace.
 *
 * @return {{cols: Array, wSpace: number}}
 * @private
 */
MagicGrid.prototype.setup = function setup () {
  var width = this.container.getBoundingClientRect().width;
  var colWidth = this.colWidth();
  var numCols = Math.floor(width/colWidth) || 1;
  var cols = [];

  if (this.maxColumns && numCols > this.maxColumns) {
    numCols = this.maxColumns;
  }

  for (var i = 0; i < numCols; i++) {
    cols[i] = {height: 0, index: i};
  }

  var wSpace = width - numCols * colWidth + this.gutter;

  return {cols: cols, wSpace: wSpace};
};

/**
 * Gets the next available column.
 *
 * @param cols list of columns
 * @param i index of dom element
 *
 * @return {*} next available column
 * @private
 */
MagicGrid.prototype.nextCol = function nextCol (cols, i) {
  if (this.useMin) {
    return getMin(cols);
  }

  return cols[i % cols.length];
};

/**
 * Positions each item in the grid, based
 * on their corresponding column's height
 * and index then stretches the container to
 * the height of the grid.
 */
MagicGrid.prototype.positionItems = function positionItems () {
  var ref = this.setup();
    var cols = ref.cols;
    var wSpace = ref.wSpace;
  var maxHeight = 0;
  var colWidth = this.colWidth();

  wSpace = this.center ? Math.floor(wSpace / 2) : 0;

  for (var i = 0; i < this.items.length; i++) {
    var col = this.nextCol(cols, i);
    var item = this.items[i];
    var topGutter = col.height ? this.gutter : 0;
    var left = col.index * colWidth + wSpace + "px";
    var top = col.height + topGutter + "px";

    if(this.useTransform){
      item.style.transform = "translate(" + left + ", " + top + ")";
    }
    else{
      item.style.top = top;
      item.style.left = left;
    }

    col.height += item.getBoundingClientRect().height + topGutter;

    if(col.height > maxHeight){
      maxHeight = col.height;
    }
  }

  this.container.style.height = maxHeight + this.gutter + "px";
};

/**
 * Checks if every item has been loaded
 * in the dom.
 *
 * @return {Boolean} true if every item is present
 */
MagicGrid.prototype.ready = function ready () {
  if (this.static) { return true; }
  return this.items.length >= this.size;
};

/**
 * Periodically checks that all items
 * have been loaded in the dom. Calls
 * this.listen() once all the items are
 * present.
 *
 * @private
 */
MagicGrid.prototype.getReady = function getReady () {
    var this$1 = this;

  var interval = setInterval(function () {
    this$1.container = document.querySelector(this$1.containerClass);
    this$1.items = this$1.container.children;

    if (this$1.ready()) {
      clearInterval(interval);

      this$1.init();
      this$1.listen();
    }
  }, 100);
};

/**
 * Positions all the items and
 * repositions them whenever the
 * window size changes.
 */
MagicGrid.prototype.listen = function listen () {
    var this$1 = this;

  if (this.ready()) {
    var timeout;

    window.addEventListener("resize", function () {
      if (!timeout){
        timeout = setTimeout(function () {
          this$1.positionItems();
          timeout = null;
        }, 200);
      }
    });

    this.positionItems();
  }
  else { this.getReady(); }
};


let magicGrid = new MagicGrid({
  container: '.container',
  animate: true,
  gutter: 30,
  static: true,
  useMin: true
});

// js 추가, 이미지 레이아웃 형태 변경
// 새로고침 할때마다 레이아웃 재배치가 일어남
var masonrys = document.getElementsByTagName("img");

for (let i = 0; i < masonrys.length; i++){
    masonrys[i].addEventListener('load', function() {
        magicGrid.positionItems();
    }, false);
}

magicGrid.listen();
  • magic-grid의 Javascript 복사 후 static 폴더에 js파일 지정
  • 추가로 이미지 레이아웃 재배치 설정 js 추가

 

Picsum

  • 이미지 랜덤으로 제공해주는 사이트
  • url 주소로 요청을 보내면 랜덤한 이미지 보여줌

 

 https://picsum.photos/

 

Lorem Picsum

Lorem Ipsum... but for photos

picsum.photos

 

 

 

list.html

{% extends 'base.html' %}
{% load static %}

{% block content %}

<style>

.container div {
  width: 250px;
  background-color: antiquewhite;
  display: flex;
  justify-content: center;
  align-items: center;
  border-radius: 1rem;
}

.container img{
  width: 100%;
  border-radius: 1rem;

}


</style>

<div class="container">
  <div >
    <img src="https://picsum.photos/200/300">
  </div>
  <div >
    <img src="https://picsum.photos/200/340">
  </div>
  <div >
    <img src="https://picsum.photos/200/260">
  </div>
   <div >
    <img src="https://picsum.photos/200/400">
  </div>
    <div >
    <img src="https://picsum.photos/200/300">
  </div>
    <div >
    <img src="https://picsum.photos/200/250">
  </div>
   <div >
    <img src="https://picsum.photos/200/200">
  </div>
  <div >
    <img src="https://picsum.photos/200/440">
  </div>
    <div >
    <img src="https://picsum.photos/200/300">
  </div>
    <div >
    <img src="https://picsum.photos/200/200">
  </div>
   <div >
    <img src="https://picsum.photos/200/350">
  </div>
   <div >
    <img src="https://picsum.photos/200/430">
  </div>
    <div >
    <img src="https://picsum.photos/200/300">
  </div>
    <div >
    <img src="https://picsum.photos/200/400">
  </div>
    <div >
    <img src="https://picsum.photos/200/280">
  </div>


</div>

<script src="{% static 'js/magicgrid.js' %}"></script>

{% endblock %}
  • magic-grid html 소스 복사 붙여넣기
  • static/js 파일 경로 추가
  • picsum의 이미지 추가

 

 

페이지 화면

 

  • 새로고침 시 랜덤으로 사진 변경

 

 

 

반응형