Skip to content
This repository
Browse code

[feature] widgets: add the parallax to the stdlib

  • Loading branch information...
commit 1572ce1fd3fcfba98d28b78d8a8c8c585129c02c 1 parent 827ba71
Jessica Castejon authored

Showing 1 changed file with 324 additions and 0 deletions. Show diff stats Hide diff stats

  1. +324 0 stdlib/widgets/parallax/parallax.opa
324 stdlib/widgets/parallax/parallax.opa
... ... @@ -0,0 +1,324 @@
  1 +/*
  2 + Copyright © 2011 MLstate
  3 +
  4 + This file is part of OPA.
  5 +
  6 + OPA is free software: you can redistribute it and/or modify it under the
  7 + terms of the GNU Affero General Public License, version 3, as published by
  8 + the Free Software Foundation.
  9 +
  10 + OPA is distributed in the hope that it will be useful, but WITHOUT ANY
  11 + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  12 + FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
  13 + more details.
  14 +
  15 + You should have received a copy of the GNU Affero General Public License
  16 + along with OPA. If not, see <http://www.gnu.org/licenses/>.
  17 +*/
  18 +
  19 +/**
  20 + * A configurable parallax widget.
  21 + *
  22 + * @author Jessica Castejon, 2011
  23 + * @category WIDGET
  24 + * @destination PUBLIC
  25 + * @stability EXPERIMENTAL
  26 + * @version 0.1
  27 + */
  28 +
  29 +package stdlib.widgets.parallax
  30 +
  31 +import stdlib.widgets.core
  32 +
  33 +/*
  34 + * {1 About this module}
  35 + *
  36 + * Parallax widget
  37 + * Inspired by https://github.com/500 and
  38 + * http://webdev.stephband.info/parallax_demos.html
  39 + *
  40 + */
  41 +
  42 +type WParallax.dim = {px_x: int; px_y: int}
  43 +
  44 +type WParallax.percent = {x: float; y: float}
  45 +
  46 +type WParallax.offset = {px: WParallax.dim}/{percent: WParallax.percent}
  47 +
  48 +type WParallax.src_type = {img: string} / {text: string}
  49 +
  50 +/**
  51 + *An element of the parallax
  52 + */
  53 +type WParallax.src = {
  54 + content: WParallax.src_type
  55 + id: string
  56 + depth: int
  57 + offset: WParallax.offset
  58 + content_style : WStyler.styler
  59 +}
  60 +
  61 +type WParallax.display = {vertical} / {horizontal} / {both}
  62 +
  63 +/**
  64 + *The configuration of a widget
  65 + */
  66 +type WParallax.config = {
  67 + display: WParallax.display
  68 + width: int
  69 + height: int
  70 + global_style: WStyler.styler
  71 +}
  72 +
  73 +WParallax = {{
  74 +
  75 +/**
  76 + *Default configuration of a widget
  77 + */
  78 + default_config : WParallax.config = {
  79 + display = {both}
  80 + width = 500
  81 + height = 200
  82 + global_style = WStyler.empty
  83 + }
  84 +
  85 +/**
  86 + *Main display function of the parallax
  87 + *
  88 + *@param config The widget configuration
  89 + *@param sources The elements configuration list
  90 + *@return The HTML corresponding to the widget
  91 + */
  92 + html(config: WParallax.config, sources: list(WParallax.src)): xhtml =
  93 + parallax = <div id=#parallax style="positon:absolute overflow:hidden" onready={_ -> configure(config,sources)}></div>
  94 + WStyler.add(config.global_style,parallax)
  95 +
  96 +/*
  97 + *Function that calculates a dimension(width of height) of a container inside
  98 + *the parallax, depending on its depth
  99 + *
  100 + *@param depth Depth of the element
  101 + *@param dimension Dimension (width or height) of the parallax
  102 + *@return The calculated dimension
  103 + */
  104 + @private
  105 + get_dimension(depth: int, dimension: int): int=
  106 + d = if depth>0
  107 + then float_of_int(depth)
  108 + else float_of_int((-1)*depth)
  109 + dim = float_of_int(dimension)
  110 + percent = dim / 20.
  111 + adjustment = d * percent
  112 + int_of_float(dim + adjustment)
  113 +
  114 +/*
  115 + *Sorts the elements depending on their depth
  116 + *
  117 + *@param sources The elements configuration list
  118 + *@return The sorted list
  119 + */
  120 + @private
  121 + sort_sources(sources: list(WParallax.src)): list(WParallax.src) =
  122 + rec division(list) = (match list with
  123 + |[] -> ([],[])
  124 + |[x] -> ([x],[])
  125 + |[x|[y|t]] -> (l1,l2)=division(t)
  126 + ([x|l1],[y|l2])
  127 + )
  128 + rec fusion(l1,l2) = (match (l1,l2) with
  129 + |(x,[]) -> x
  130 + |([],x) -> x
  131 + |([x|t1],[y|t2]) -> if (x.depth)<(y.depth)
  132 + then [y|[x|fusion(t1,t2)]]
  133 + else [x|[y|fusion(t1,t2)]]
  134 + )
  135 + match sources with
  136 + |[] -> []
  137 + |[x] -> [x]
  138 + |l -> (l1,l2)=division(l)
  139 + fusion(sort_sources(l1),sort_sources(l2))
  140 +
  141 +/*
  142 + *Function that gives the dimensions of a container inside the parallax,
  143 + *depending on its depth and the config (horizontal, vertical or both)
  144 + *
  145 + *@param config The widget configuration
  146 + *@param source The element configuration
  147 + *@return The calculated dimensions
  148 + */
  149 + @private
  150 + get_container_dimensions(config: WParallax.config, source: WParallax.src): WParallax.dim =
  151 + (w,h) = match config.display with
  152 + |{horizontal} -> (get_dimension(source.depth,config.width), config.height)
  153 + |{vertical} -> (config.width, get_dimension(source.depth,config.height))
  154 + | _ -> (get_dimension(source.depth,config.width),get_dimension(source.depth,config.height))
  155 + {px_x=w;px_y=h}
  156 +
  157 +/*
  158 + *Function that calculates the margins of an element of the parallax
  159 + *
  160 + *@param config The widget configuration
  161 + *@param source The element configuration
  162 + *@return The margins of the element
  163 + */
  164 + @private
  165 + get_margin(config: WParallax.config, source: WParallax.src): WParallax.dim=
  166 + match source.offset with
  167 + |~{px} -> px
  168 + |~{percent} -> offset_x = (percent.x / 2.) + 50.
  169 + offset_y = (percent.y / 2.) + 50.
  170 + dimensions = get_container_dimensions(config, source)
  171 + w = float_of_int(dimensions.px_x)
  172 + h = float_of_int(dimensions.px_y)
  173 + margin_left = int_of_float((w * offset_x) / 100.)
  174 + margin_top = int_of_float((h * offset_y) / 100.)
  175 + {px_x=margin_left;px_y=margin_top}
  176 +
  177 +/*
  178 + *Give the adjustment for an element
  179 + *
  180 + *@param pos The position of the mouse on the page
  181 + *@param off The offset of the parallax on the page
  182 + *@param dim The dimension of the parallax
  183 + *@return The adjustment (in percent)
  184 + */
  185 + @private
  186 + get_adjustment(pos: int, off: int, dim: int): float =
  187 + p = float_of_int(pos)
  188 + o = float_of_int(off)
  189 + d = float_of_int(dim)
  190 + offset = p - o
  191 + half = d / 2.
  192 + (offset - half) / half
  193 +
  194 +/*
  195 + *Add the style to an element of the parallax
  196 + *
  197 + *@param config The widget configuration
  198 + *@param source The element configuration
  199 + */
  200 + @private
  201 + configure_content(config: WParallax.config, source: WParallax.src): void =
  202 + margin = get_margin(config, source)
  203 + top = margin.px_y
  204 + left = margin.px_x
  205 + padding={t={none};
  206 + l={none};
  207 + b={none};
  208 + r={none}}
  209 + margin={t={some={px=top}};
  210 + l={some={px=left}};
  211 + b={none};
  212 + r={none}}
  213 + style = [{position={absolute}},{padding=padding},{margin=margin}]
  214 + dom_src = Dom.select_id("{source.id}_content")
  215 + Dom.set_style(dom_src,style)
  216 +
  217 +/*
  218 + *Add the style to the container of an element of the parallax
  219 + *
  220 + *@param config The widget configuration
  221 + *@param source The element configuration
  222 + */
  223 + @private
  224 + configure_container(config: WParallax.config, source: WParallax.src): void =
  225 + dimensions = get_container_dimensions(config, source)
  226 + w = dimensions.px_x
  227 + h = dimensions.px_y
  228 + margin_top = (config.height - h)/2
  229 + margin_left = (config.width - w)/2
  230 + margin={t={some={px=margin_top}};
  231 + l={some={px=margin_left}};
  232 + b={none};
  233 + r={none}}
  234 + style = [{position={absolute}},{width={px=w}},{height={px=h}},{margin=margin}]
  235 + dom_container = Dom.select_id(source.id)
  236 + Dom.set_style(dom_container,style)
  237 +
  238 +/*
  239 + *Add the style to the parallax and the HTML of the elements
  240 + *
  241 + *@param config The widget configuration
  242 + *@param sources The elements configuration list
  243 + */
  244 + @private
  245 + configure(config: WParallax.config, sources: list(WParallax.src)): void =
  246 + list_sources = sort_sources(sources)
  247 + dom_parallax = Dom.select_id("parallax")
  248 + do Dom.set_style(dom_parallax,[{position={relative}},{overflow={hidden}},{width={px=config.width}},{height={px=config.height}}])
  249 + do Dom.transform([#parallax <- get_content(config,list_sources)])
  250 + _ = Dom.bind(dom_parallax,{mousemove},handle(config,list_sources,_))
  251 + void
  252 +
  253 +
  254 +/*
  255 + *Function that generates the HTML correspondig to a elements list
  256 + *
  257 + *@param config The widget configuration
  258 + *@param sources The elements configuration list
  259 + *@return The HTML corresponding to the elements list
  260 + */
  261 + @private
  262 + get_content(config: WParallax.config, sources: list(WParallax.src)): xhtml=
  263 + add_src(source)=
  264 + src = match source.content with
  265 + |~{img} -> <img id="{source.id}_content" src={img} alt="" onready={_->configure_content(config,source)}/>
  266 + |~{text} -> <div id="{source.id}_content" onready={_->configure_content(config,source)}>{text}</div>
  267 + src = WStyler.add(source.content_style,src)
  268 + <div id={source.id} onready={_->configure_container(config,source)}>
  269 + {src}
  270 + </div>
  271 + list_src = List.map(add_src,sources)
  272 + <>{list_src}</>
  273 +
  274 +/*
  275 + *Function that applies the changes to the elements of the parallax
  276 + *
  277 + *@param config The widget configuration
  278 + *@param sources The elements configuration list
  279 + *@param event The event information
  280 + */
  281 + @private
  282 + handle(config: WParallax.config, sources: list(WParallax.src), event: Dom.event): void =
  283 + dimensions = event.mouse_position_on_page
  284 + offset = Dom.get_offset(Dom.select_id("parallax"))
  285 + percent_x = get_adjustment(dimensions.x_px,offset.x_px,config.width)
  286 + percent_y = get_adjustment(dimensions.y_px,offset.y_px,config.height)
  287 + adjust(source) = (
  288 + (w,h) = match config.display with
  289 + |{horizontal} -> (get_dimension(source.depth,config.width), config.height)
  290 + |{vertical} -> (config.width, get_dimension(source.depth,config.height))
  291 + | _ -> (get_dimension(source.depth,config.width),get_dimension(source.depth,config.height))
  292 + margin_top = float_of_int(config.height - h) / 2.
  293 + margin_left = float_of_int(config.width - w) / 2.
  294 + adj_x = int_of_float(percent_x * margin_left)
  295 + adj_y = int_of_float(percent_y * margin_top)
  296 + src = Dom.select_id("{source.id}")
  297 + style = match config.display with
  298 + |{horizontal} -> if source.depth>0
  299 + then [{left={px=adj_x}}]
  300 + else (
  301 + if source.depth<0
  302 + then [{left={px=-adj_x}}]
  303 + else []
  304 + )
  305 + |{vertical} -> if source.depth>0
  306 + then [{top={px=adj_y}}]
  307 + else (
  308 + if source.depth<0
  309 + then [{top={px=-adj_y}}]
  310 + else []
  311 + )
  312 + |_ -> if source.depth>0
  313 + then [{left={px=adj_x}},{top={px=adj_y}}]
  314 + else (
  315 + if source.depth<0
  316 + then [{left={px=-adj_x}},{top={px=-adj_y}}]
  317 + else []
  318 + )
  319 + Dom.set_style(src,style)
  320 + )
  321 + List.iter(adjust,sources)
  322 +
  323 +
  324 +}}

0 comments on commit 1572ce1

Please sign in to comment.
Something went wrong with that request. Please try again.