block by pnavarrc df555a89d8aa590d61aa

Moiré Patterns

Full Screen

Moiré Patterns

Moiré Patterns are patterns that results from overlapping two periodical patterns (series of straight lines, for instance). This demo allows to create Moiré patterns by changing the relative angle between the patterns, the number of bars, the bar width and the color of the bars.

Moiré Patterns

This demo uses D3 to create the patterns with SVG rectangles.

References

index.html

<html>
<head>
    <title>The Moiré Patterns</title>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
    <script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.4/d3.min.js" charset="utf-8"></script>

    <style>
        .footer {
            height: 100px;
        }

        .bar {
            stroke: none;
            stroke-width: 0;
        }
    </style>

</head>

<body>
    <div class="container">

        <h1>Moiré Pattern</h1>

        Moiré Patterns are patterns that results from overlapping two periodical patterns (series of straight lines, for instance). This demo allows to create Moiré patterns by changing the relative angle between the patterns, the number of bars, the bar width and the color of the bars.

        <form role="form">

            <div class="form-group">
                <label for="input-na">Bars</label>
                <input id="input-na" type="number" min="80" max="112" step="1" value="105">

                <label for="input-ta">Angle</label>
                <input id="input-ta" type="number" min="-90" max="90" step="0.1" value="0">

                <label for="input-pa">Padding</label>
                <input id="input-pa" type="number" min="0.05" max="0.95" step="0.05" value="0.5">

                <label for="input-ca">Color</label>
                <input id="input-ca" type="color" value="#FF6B6B">
            </div>

            <div class="form-group">
                <label for="input-nb">Bars</label>
                <input id="input-nb" type="number" min="80" max="112" step="1" value="100">

                <label for="input-tb">Angle</label>
                <input id="input-tb" type="number" min="-90" max="90" step="0.1" value="0">

                <label for="input-pb">Padding</label>
                <input id="input-pb" type="number" min="0.05" max="0.95" step="0.05" value="0.5">

                <label for="input-cb">Color</label>
                <input id="input-cb" type="color" value="#4ECDC4">
            </div>

        </form>

        <div id="patterns"></div>
        <div class="footer"></div>

    </div>

    <script src="bar-pattern.js"></script>
    <script src="main.js"></script>
</body>
</html>

bar-pattern.js

function barPattern() {
    'use strict';

    // Chart attributes
    var me = {
        width:  100,
        height: 100
    };

    function chart(selection) {
        selection.each(function(data) {

            var grp = d3.select(this);

            var items = d3.range(data.n),
                angle = data.angle,
                color = data.color;

            var xScale = d3.scale.ordinal()
                .domain(items)
                .rangeBands([0, me.width], data.padding);

            grp.transition().duration(1000)
                .attr('transform', 'rotate(' + angle + ')');

            var bars = grp.selectAll('rect.bar').data(items);

            bars.enter().append('rect').classed('bar', true)
                .attr('fill', color);

            bars.transition().duration(1000)
                .attr('x', function(d, i) { return xScale(i); })
                .attr('width', xScale.rangeBand())
                .attr('height', me.height)
                .attr('fill', color);

            bars.exit().remove();
        });
    }

    // Accessor methods

    chart.width = function(value) {
        if (!arguments.length) { return me.width; }
        me.width = value;
        return chart;
    };

    chart.height = function(value) {
        if (!arguments.length) { return me.height; }
        me.height = value;
        return chart;
    };

    return chart;
}

main.js

// Define the width and height
var width  = 800,
    height = 600;

// Select the container div and create the SVG element
var div = d3.select('#patterns'),
    svg = div.append('svg');

svg
    .attr('width', width)
    .attr('height', height);

// Create an instance of the bar pattern chart
var pattern = barPattern()
    .width(width)
    .height(height);

var data = [
    {n: 105, angle: 0, padding: 0.5, color: '#FF6B6B'},
    {n: 100, angle: 0, padding: 0.5, color: '#4ECDC4'}
];

function updatePattern() {
    var groups = svg.selectAll('g.pattern').data(data);
    groups.enter().append('g').classed('pattern', true);
    groups.call(pattern);
}

updatePattern();

// Update the pattern when the user changes the input value

d3.select('#input-na').on('input', function() {
    data[0].n = +this.value;
    updatePattern();
});

d3.select('#input-ta').on('input', function() {
    data[0].angle = +this.value;
    updatePattern();
});

d3.select('#input-pa').on('input', function() {
    data[0].padding = +this.value;
    updatePattern();
});

d3.select('#input-ca').on('input', function() {
    data[0].color = this.value;
    updatePattern();
});

d3.select('#input-nb').on('input', function() {
    data[1].n = +this.value;
    updatePattern();
});

d3.select('#input-tb').on('input', function() {
    data[1].angle = +this.value;
    updatePattern();
});

d3.select('#input-pb').on('input', function() {
    data[1].padding = +this.value;
    updatePattern();
});

d3.select('#input-cb').on('input', function() {
    data[1].color = this.value;
    updatePattern();
});