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>
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/