Archive for the Programming Category

Posted on Programming

Adding text to google maps markers

If you’ve ever used the Google Maps Javascript API, you’re probably aware that marker labels can only be one letter long. But sometimes you want them to say something meaningful, and often that takes more than a single character.

In case you’re looking for a way to display arbitrary strings in a Google Maps marker, good news, here’s how you can do it!

You can pass a data URL when you’re supplying an image for an marker, which is great. We can send it some SVG which includes our label text.

  1. Import your marker icon into Illustrator, or some other vector graphics software.
  2. Type in some sample text, formatted however you like.
  3. Export it as SVG.
  4. Create a function that replaces the sample text with whatever you want to display, and returns the adjusted SVG
  5. Pass that to the Google Maps API as a data URL.

// Generate a pin!
function createPin(text) {
	var svg = '...'; // Imagine there's SVG here.
	return 'data:image/svg+xml,' + svg.replace('sample-text', text);
}
// Create the map. Position and style it however you like
var map = new google.maps.Map(document.getElementById('maps_marker_text_example'), {
	center: {lat: 49.264691, lng: -123.100},
});
// Create the marker
var marker = new google.maps.Marker({
	map: map,
	icon: createPin('delicious burritos'), // Generate the SVG for this marker
	position: {lat: 49.2630584, lng: -123.0945}
});

Bam! You’re done. You’ve got map markers showing custom text.

One thing to be aware of is the <svg /> tag must include width and height attributes, otherwise weird things will happen. When I exported from Illustrator, my file had a viewBox attribute, but no width and height. So if yours is missing those, add them in.

 

Posted on Programming

Don’t starve together

I’ve been playing Don’t Starve Together lately, and it’s awesome. There’s a constant sense of pressure imposed by the passage of time, days turn to night, a mild Autumn to bleak Winter. It makes any wasted time seem at worst dire, or at best mildly frustrating.

There are so many items you can cobble together, with twigs, bunny-flesh, and the like. At least 144, by my count. But unless you memorize their positions and ingredients, you’re going to waste a lot of time searching through categories for some item you’re sure you’d seen but just can’t seem to find.

I, myself, often kept a wikia tab open on my secondary monitor. But as I’m sure you’re aware, Wikia is slow and prone to annoying ads blaring sound this way and that. And even so, didn’t provide an ideal interface for that sort of thing.

I wanted to type in “charcoal” and immediately see what I could make. Or “crock pot” and see what I needed. Or even “science” to see everything that’s in that category.

And now I can!

The What can I make page is where I spend most of my time. The What do I need page is for those situations where I’m starting a new game, and know I want to create, say, 2 crock pots and 1 bird cage. It’ll tell me everything I need to collect to fulfill my crafting dreams.

If you find anything that doesn’t work, let me know, I haven’t tested it all that much.


I made it just using jquery. Then I remade it using backbone. Then I remade it using webpack, sass and react. Because why not?

This is the backbone version, because the react interface felt strangely clunky.

 

Posted on Programming

Duplicate emails, chrome, and favicons

Switching away from Mandrill, I found Amazon SES was sending two emails from my PHP test script. This only happened when hit from the web, running the same script through the PHP-CLI sent one email, as expected.

Looking at Chromes network tab, turns out it was loading the script as well as favicon.ico. Alas, there was no favicon.ico, and in the sites-enabled config for that location the FallbackResource was set to /index.php. Turns out it was loading index.php twice, resulting in two emails.

I used Bradicon! to create a quick favicon, uploaded it, and bam!, just one email from then on.

 

Posted on Programming

Gently flickering flame, part 3

Now that we can talk to the lights, and choose colours, it’s time to make the lights flicker!

Hue doesn’t like you to send more than 10 commands per second. Since I have two lights I’m going to update them once every 200 milliseconds (5 times per second).

This is easy to do, using a normal game-type timing loop. In the constructor of your Main.hx, add addEventListener(Event.ENTER_FRAME, onFrame);.

Then create the onFrame function. Here’s mine:

private function onFrame(e:Event) {
	var n = Lib.getTimer();
	if ( n - _last >= 200 ) { // Don't send an update unless 200ms have elapsed
		if ( change ) { // I watch for colour and brightness changes, and set a this variable when they occur
			var data = {
				"bri": Math.round(Math.min( 254, cp.l*255 )), // brightness is between 0 and 254
				"hue": Math.round(Math.min(65535, cp.h*65535)), // hue is between 0 and 65535
				"sat":Math.round(Math.min( 254, cp.s*255 )) // saturation is between 0 and 254
			}
			var ds = Json.stringify(data);
			for (n in Reflect.fields(lights)) { // Loop through all the lights. We want the light keys, hence the reflection
				hue.update(n, 'state', ds); // Update the light
			}
			change = false;
		} else if (cp.flicker) { // This is the flickering part! cp is my colour picker/user interface's name
			var hsl = flicker.flick( cp.h, cp.s, cp.l );  // The magic flicker function!
			var data = {
				"bri": hsl[2],
				"hue": hsl[0],
				"sat": hsl[1],
				"transitiontime": 2
			}
			var ds = Json.stringify(data);
			for (n in Reflect.fields(lights)) {
				hue.update(n, 'state', ds); // Update the light
			}
		}
		_last = n;
	}
}

For the flicker itself, I kept it pretty simple. I might eventually try a normally distributed pseudo-random variance on the hue.

class Flicker {
	public function new() {}
	public function flick(h:Float, s:Float, l:Float) {
		var b = clamp(0, vary(l*254, 0.2), 254); // Vary brightness by 20%
		var h = clamp(0, vary(h*65535, 0.05), 65535); // Vary hue by 5%
		var s = clamp(0, h*254, 254);
		return [h, s, b];
	}
	function vary(orig:Float, variance:Float):Int {
		var max = orig * variance;
		var half = max/2;
		return Math.round(orig + Math.random()*max - half);
	}
	function clamp( min, val, max ) {
		return Math.round( Math.max( min, Math.min( max, val ) ) );
	}
}
Posted on Programming

Gently flickering flame, part 2 (colours)

Now the we can talk to the lights, It’s time to deal with colours. We can’t just send RGB to the API, so I made a class that displays a rectangle of colours, and can convert from HSL to RGB for displaying each one. The HslToRgb function I stole from stackoverflow.

package;

import openfl.display.Sprite;
import openfl.events.MouseEvent;
import openfl.events.Event;


class Colours extends Sprite {
	private var _width:Int = 60; // Number of hues
	private var _height:Int = 30; // Number of saturations
	private var size:Int = 10;
	
	public var h:Float;
	public var s:Float;
	
	
	public function new() {
		super();
		var l = .9;
		for(x in 0..._width) {
			for(y in 0..._height) {
				var h = _height/2;
				var lo = (1-(y/_height/2)); // This is so it fades into white rather than grey
			
				var rgb = hslToRgb( x*1.00/_width, y*1.00/_height, lo);
				var c = rgb[0];
				c = (c<<8) + rgb[1];
				c = (c<<8) + rgb[2];
				graphics.beginFill(c);
				graphics.drawRect(x*size,y*size,size, size);
				graphics.endFill();
			}
		}
		addEventListener(MouseEvent.CLICK, onclick);
		addEventListener(MouseEvent.MOUSE_MOVE, onmove); // So it picks up finger drags
	}
	
	private function onmove(e:MouseEvent) {	
		if ( !e.buttonDown ) return;
		onclick(e);
	}
	private function onclick(e:MouseEvent) {
		h = Math.min(1, e.localX/size/_width);
		s = Math.min(1, e.localY/size/_height);
		var l = 0.5; // This is alpha
		var rgb = hslToRgb(h,s,l); 
		dispatchEvent( new Event(Event.CHANGE) );
	}
	
	/**
	* Converts an HSL color value to RGB. Conversion formula
	* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
	* Assumes h, s, and l are contained in the set [0, 1] and
	* returns r, g, and b in the set [0, 255].
	*
	* @param   Number  h       The hue
	* @param   Number  s       The saturation
	* @param   Number  l       The lightness
	* @return  Array           The RGB representation
	*/
	public function hslToRgb(h:Float, s:Float, l:Float):Array{
		var r:Float, g:Float, b:Float;
	
		if(s == 0){
			r = g = b = l; // achromatic
		}else{
			var hue2rgb = function hue2rgb(p:Float, q:Float, t:Float):Float{
				if(t < 0) t += 1;
				if(t > 1) t -= 1;
				if(t < 1/6) return (p + (q - p) * 6 * t);
				if(t < 1/2) return (q);
				if(t < 2/3) return (p + (q - p) * (2/3 - t) * 6);
				return (p);
			}
	
			var q:Float = l < 0.5 ? l * (1 + s) : l + s - l * s;
			var p:Float = 2 * l - q;
			r = hue2rgb(p, q, h + 1/3);
			g = hue2rgb(p, q, h);
			b = hue2rgb(p, q, h - 1/3);
		}
	
		return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
	}
}