Created
March 1, 2019 22:39
-
-
Save d4hines/9cce1849b3b9bdf6e4ddeceb550629eb to your computer and use it in GitHub Desktop.
Perfect Square Gists
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns constrained.core | |
(:require [reagent.core :as reagent] | |
[goog.dom :as dom])) | |
(set! *warn-on-infer* true) | |
(defn collision? [x y w h other-rectangles] | |
(some | |
(fn a-collision? [{:keys [left top width height]}] | |
(and | |
(< x (+ left width)) | |
(> x (- left w)) | |
(< y (+ top height)) | |
(> y (- top h)))) | |
other-rectangles)) | |
(defn solve [current-x current-y target-x target-y w h other-rectangles] | |
(cond | |
(and (< current-x target-x) (not (collision? (inc current-x) current-y w h other-rectangles))) | |
(recur (inc current-x) current-y target-x target-y w h other-rectangles) | |
(and (> current-x target-x) (not (collision? (dec current-x) current-y w h other-rectangles))) | |
(recur (dec current-x) current-y target-x target-y w h other-rectangles) | |
(and (< current-y target-y) (not (collision? current-x (inc current-y) w h other-rectangles))) | |
(recur current-x (inc current-y) target-x target-y w h other-rectangles) | |
(and (> current-y target-y) (not (collision? current-x (dec current-y) w h other-rectangles))) | |
(recur current-x (dec current-y) target-x target-y w h other-rectangles) | |
:else | |
[current-x current-y])) | |
(defn move [{:keys [rectangles] :as app-state} idx target-x target-y] | |
(let [{:keys [left top width height]} (get rectangles idx) | |
other-rectangles (concat (take idx rectangles) | |
(drop (inc idx) rectangles)) | |
[next-x next-y] | |
(if (collision? target-x target-y width height other-rectangles) | |
(solve left top target-x target-y width height other-rectangles) | |
[target-x target-y])] | |
(update-in app-state [:rectangles idx] | |
assoc :left next-x :top next-y))) | |
(defn main-view [app-state] | |
(let [rectangles (:rectangles @app-state)] | |
[:div | |
[:h2 "Drag the rectangles around..."] | |
(into | |
[:div {:style {:position "relative"}}] | |
(map-indexed | |
(fn [idx {:keys [left top width] :as rectangle}] | |
[:div {:draggable true | |
:style (merge rectangle | |
{:position "absolute" | |
:display "flex" | |
:align-items "center" | |
:justify-content "center" | |
:color "blue" | |
:height width | |
:font-size "50px"}) | |
:on-drag-start | |
(fn rectangle-drag-start [^js/MouseEvent e] | |
(.setDragImage (.-dataTransfer e) (js/Image.) 0 0) | |
(swap! app-state assoc :drag-from | |
{:dx (- (.-clientX e) left) | |
:dy (- (.-clientY e) top)})) | |
:on-drag | |
(fn rectangle-drag [^js/MouseEvent e] | |
(let [{:keys [dx dy]} (:drag-from @app-state) | |
mouse-x (.-clientX e) | |
mouse-y (.-clientY e)] | |
;; TODO: better way to detect last event? | |
(when (or (not= mouse-x 0) (not= mouse-y 0)) | |
(let [target-x (- mouse-x dx) | |
target-y (- mouse-y dy)] | |
(swap! app-state move idx target-x target-y))))) | |
:on-drag-end | |
(fn rectangle-drag-end [e] | |
(swap! app-state dissoc :drag-from))} | |
[:span (/ width multiplier)]]) | |
rectangles))])) | |
(def multiplier 20) | |
(defn m [x] (* multiplier x)) | |
(defn random-rect [top left width color] | |
{:top (m top) :left (m left) | |
:width (m width) | |
:background-color color}) | |
(def rects [[22 14 10 "#090300"] | |
[0 0 18 "#db2d20"] | |
[0 18 15 "#fded02"] | |
[18 14 4 "#01a0e4"] | |
[15 18 7 "#a16a94"] | |
[15 25 8 "#01a252"] | |
[22 24 1 "#b5e4f4"] | |
[18 0 14 "#a5a2a2"] | |
[23 24 9 "turquoise"]]) | |
(def app-state | |
(reagent/atom | |
{:rectangles (vec (map #(apply random-rect %) rects))})) | |
(reagent/render-component [main-view app-state] | |
(dom/getElement "klipse-container")) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment