3

So, basically, my problem is that at the start of my program, the jQuery .css() works just fine, tested by this:

$("#canvas").css("border", "3px solid red");

Just after that, when I try to add a div - which does indeed get added whenever it is required - .css() stops working for that element. Like this:

var elem = $("<div/>", {"class": "circle"});
elem.css({'background-color': color})
    .appendTo($("#circles"));

This just appends a <div class="circle"></div>, with no style and which can't later be .remove()'d-

Fiddle: http://jsfiddle.net/bh79fe87/

The full code looks like this (LiveScript):

O = Rx.Observable

## Extensions

Rx.Observable.repeatFunc = -> Rx.Observable.return null .map it .repeat!
Rx.Observable.prototype.scanCount = -> this.map 1 .scan 0 (+) .startWith 0

## Utils

write = (t, s) --> t.html t.html! + s + '<br />'

pairs-to-obj = -> {[p[0], p[1]] for p in it}

assoc = (m, t) -->
  for k, v of m
    if k of t then [k, t[k]]
              else [k, v]
  |> (++ [[k, v] for k, v of t if k not of m])
  |> pairs-to-obj

toLocal = (e, x, y) ->
  o = $(e).offset!
  {x: x - o.left, y: y - o.top}

## Game

createCircle = ->
  x = Math.random! * ($(canvas).width() - 20)
  y = -40 + Math.random! * 10
  color = ['#FF0000', '#00FF00', '#0000FF'][Math.floor Math.random! * 3]
  do
    x: x
    y: y
    color: color

createCircleStream = ($canvas, $circles) ->
  elem = $ '<div/>', class: 'circle'
  elemclicks = O.fromEvent elem, 'click'
    .map -> true
    .first!      # Kill the event after a click.
  stream = O.interval 16
    .scan createCircle!, (obj, click) -> assoc obj, y: obj.y + 1
    .takeWhile -> it.y < $canvas.height! + 1
  killstream = stream
    .filter -> it.y > $canvas.height!
    .merge elemclicks
    .map -> true
    .first!
  do
    clicks: elemclicks
    stream: stream
    kill: killstream
    elem: elem

$ ->
  $canvas = $ '#canvas'
  $hits = $ '#hits'
  $missclicks = $ '#missclicks'
  $misses = $ '#misses'
  $circles = $ '#circles'

  $canvas.css 'border', '3px solid red'

  # Events
  canvasclicks = O.fromEvent $canvas, 'click'
    .map -> toLocal canvas, it.pageX, it.pageY

  # Data streams
  circlestream = O.return 1 # O.repeatFunc -> createCircleStream $canvas, $circles
    .repeat!
    .controlled!

  circles = circlestream.map -> createCircleStream $canvas, $circles

  circleclicks = circles
    .flatMap (circle) ->
      circle.clicks
        .map -> circle

  circleupdates = circles
    .flatMap (circle) ->
      circle.stream
        .map -> assoc it, elem: circle.elem
        .takeUntil circle.kill

  circlekills = circles
    .flatMap (circle) ->
      circle.kill
        .map -> circle.elem

  hits = circleclicks.scanCount!
  missclicks = canvasclicks.scanCount!.combineLatest hits, (-)
  misses = circlekills.scanCount!.combineLatest hits, (-)

  # Side effects
  circles.subscribe ->
    it.elem.css 'background-color': it.color
           .appendTo $circles
    $('#canvas').css 'background-color': it.color

  circleupdates.subscribe ->
    it.elem.css do
      'left': it.x
      'top': it.y
      'background-color': it.color

  circlekills.subscribe ->
    it.remove!
    circlestream.request 1

  hits.subscribe       -> $hits.html "Hits: #it"
  missclicks.subscribe -> $missclicks.html "Missed clicks: #it"
  misses.subscribe     -> $misses.html "Missed circles: #it"

  # Kick off the game.
  circlestream.request 5

Also the HTML:

<html>
    <head>
        <title>RxTest</title>
        <script type="text/javascript" src="libs/jquery-1.11.1.min.js"></script>
        <script type="text/javascript" src="libs/rx.all.js"></script>
        <script type="text/javascript" src="js/rxtest.js"></script>

        <style>
            #canvas {
                position: relative;
                width: 640px; height: 360px; background: #000000;
                color: #FFFFFF;
                overflow: hidden;
            }

            .game-container {
                position: absolute;
                background: transparent;
                color: #FFFFFF;
            }

            .circle {
                position: absolute;
                border-radius: 50%;
                width: 30px;
                height: 30px;
            }
        </style>
    </head>
    <body>
        <div id="canvas">
            <div id="circles" class="game-container"></div>
            <div id="stats" class="game-container">
                <div id="hits"></div>
                <div id="missclicks"></div>
                <div id="misses"></div>
            </div>
        </div>
    </body>
</html>
seequ
  • 456
  • 2
  • 13

3 Answers3

0

Try removing the $() in appendTo and just putting "#circles" there instead

theodore hogberg
  • 312
  • 3
  • 11
0

class is a reserved word in JavaScript (see: ECMA-262 sec. 7.6.1.2) and using it probably stops your script from further execution. The are few ways to get around this. For example you can use .addClass() method to set your class.

Try changing this:

var elem = $("<div/>", {class: "circle"});
elem.css({'background-color': color})
    .appendTo($("#circles"));

to this:

var elem = $("<div/>").addClass("circle");
elem.css({'background-color': color})
    .appendTo($("#circles"));

and see if it helps.

rsp
  • 107,747
  • 29
  • 201
  • 177
  • That was just a typo in the question. – seequ Dec 17 '14 at 07:50
  • Also of note: the script works perfectly, disregarding rendering. – seequ Dec 17 '14 at 07:53
  • @Sieg Put your example on [JSFiddle](http://jsfiddle.net/), [JS Bin](http://jsbin.com/) or [CodePen](http://codepen.io/) so everyone can see what works and how. Giving limited info and making typos in the code in your question certainly don't help in diagnosing your problem. Posting live code example will probably get it solved in a minute. – rsp Dec 17 '14 at 08:04
0

Ookay, so, I was way off. Apparently, RxJS creates a new circle div for every subscriber. In this case, 4 event subscriptions were made for each circle. I solved this by using Rx.Observable.prototype.publish().

Working JSFiddle: http://jsfiddle.net/u3Lf6d26/1/

seequ
  • 456
  • 2
  • 13