mirror of
https://github.com/google/pebble.git
synced 2025-03-15 16:51:21 +00:00
40 lines
No EOL
11 KiB
HTML
40 lines
No EOL
11 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<!--
|
|
This file acts as a simple benchmark to be executed in (phone) browsers.
|
|
It compiles tictoc.js (embedded) below using the generated compiler.
|
|
Just share this folder and point your browser to this file.
|
|
-->
|
|
<meta charset="UTF-8">
|
|
<title>js_tooling Benchmark page</title>
|
|
<script src="js_tooling.js"></script>
|
|
<script>
|
|
// enable logging
|
|
JS_TOOLING_LOGGING = true;
|
|
</script>
|
|
<script>
|
|
var tictoc = "\r\n\/*global Rocky:true *\/\r\n\/*eslint max-len: [2, 100, 4]*\/\r\n\r\nif (typeof (Rocky) === \'undefined\') {\r\n Rocky = {};\r\n}\r\n\r\n(function() {\r\n Rocky.WebAPIBinding = function(canvasElement) {\r\n var _private = {};\r\n this._private = _private;\r\n\r\n _private.subscriptions = {\r\n emit: function(name, event) {\r\n var f = this[name];\r\n if (typeof f === \'function\') {\r\n f(event);\r\n }\r\n }\r\n };\r\n\r\n \/\/ -----------------\r\n if (typeof Rocky.bindCanvas === \'function\') {\r\n _private.binding = Rocky.bindCanvas(canvasElement);\r\n } else if (typeof Rocky.bindNative === \'function\') {\r\n _private.binding = Rocky.bindNative(canvasElement);\r\n } else {\r\n throw new Error(\'cannot create a binding\');\r\n }\r\n _private.binding.update_proc = function(ctx, bounds) {\r\n var ctx2D = new Rocky.CanvasRenderingContext2D(_private.binding, ctx, bounds);\r\n _private.subscriptions.emit(\'draw\', {context: ctx2D});\r\n };\r\n this.requestDraw = function() {\r\n _private.binding.mark_dirty();\r\n };\r\n \/\/ -----------------\r\n };\r\n\r\n Rocky.WebAPIBinding.prototype.on = function(event, callback) {\r\n \/\/ workaround for speed reasons: this is a poor shadow of a real event emitter\u2026\r\n if ([\'draw\', \'minutechange\'].indexOf(event) < 0) {\r\n throw new Error(\'unknown event \' + event);\r\n }\r\n if (typeof this._private.subscriptions[event] !== \'undefined\') {\r\n throw new Error(\'event can only be bound once \' + event);\r\n }\r\n\r\n this._private.subscriptions[event] = callback.bind(this);\r\n\r\n if (event === \'minutechange\') {\r\n var tickService = new Rocky.TickService(callback);\r\n tickService.schedule();\r\n }\r\n };\r\n\r\n})();\r\n\r\n\/*global Rocky:true *\/\r\n\r\nif (typeof (Rocky) === \'undefined\') {\r\n Rocky = {};\r\n}\r\n\r\n(function() {\r\n\r\n Rocky.CanvasRenderingContext2D = function(rockyBinding, ctx, bounds) {\r\n this.binding = rockyBinding;\r\n this.cPtr = ctx;\r\n this.canvas = {\r\n clientWidth: bounds.w,\r\n clientHeight: bounds.h\r\n };\r\n this.beginPath();\r\n };\r\n\r\n Rocky.CanvasRenderingContext2D.prototype.fillRect = function(x, y, width, height) {\r\n this.binding.graphics_fill_rect(this.cPtr, [x, y, width, height], 0, 0);\r\n };\r\n\r\n Object.defineProperties(Rocky.CanvasRenderingContext2D.prototype, {\r\n \'fillStyle\': {\r\n get: function() {\r\n return \'not implement, yet\';\r\n },\r\n set: function(value) {\r\n var color = Rocky.GColorFromStyle(value);\r\n this.binding.graphics_context_set_fill_color(this.cPtr, color);\r\n }\r\n },\r\n \'strokeStyle\': {\r\n get: function() {\r\n return \'not implement, yet\';\r\n },\r\n set: function(value) {\r\n var color = Rocky.GColorFromStyle(value);\r\n this.binding.graphics_context_set_stroke_color(this.cPtr, color);\r\n }\r\n },\r\n \'lineWidth\': {\r\n get: function() {\r\n return \'not implement, yet\';\r\n },\r\n set: function(value) {\r\n this.binding.graphics_context_set_stroke_width(this.cPtr, value);\r\n }\r\n }\r\n });\r\n\r\n Rocky.CanvasRenderingContext2D.prototype.beginPath = function() {\r\n this.currentPath = new Rocky.Path2D();\r\n };\r\n\r\n Rocky.CanvasRenderingContext2D.prototype.stroke = function(path) {\r\n path = path || this.currentPath;\r\n \/\/ TODO: implement this fully\r\n this.binding.graphics_draw_line(this.cPtr, path.p0, path.p1);\r\n };\r\n\r\n \/\/ forward path calls to current Path2D instance\r\n [\'moveTo\', \'lineTo\'].forEach(function(s) {\r\n Rocky.CanvasRenderingContext2D.prototype[s] = function() {\r\n var f = this.currentPath[s];\r\n f.apply(this.currentPath, arguments);\r\n };\r\n });\r\n})();\r\n\r\n\/*global Rocky:true *\/\r\n\r\nif (typeof (Rocky) === \'undefined\') {\r\n Rocky = {};\r\n}\r\n\r\n(function() {\r\n var colorNames = {\r\n black: 0xC0,\r\n red: 0xF0,\r\n white: 0xFF\r\n };\r\n\r\n Rocky.GColorFromStyle = function(style) {\r\n \/\/ TODO: implement fully\r\n return colorNames[style];\r\n };\r\n})();\r\n\/*global Rocky:true *\/\r\n\r\nif (typeof (Rocky) === \'undefined\') {\r\n Rocky = {};\r\n}\r\n\r\n(function() {\r\n Rocky.Path2D = function() {\r\n };\r\n\r\n var rounded = function(v) {\r\n return Math.round(v * 8) \/ 8;\r\n };\r\n\r\n \/\/ TODO: implement this correctly\r\n Rocky.Path2D.prototype.moveTo = function(x, y) {\r\n this.p0 = [rounded(x), rounded(y)];\r\n };\r\n Rocky.Path2D.prototype.lineTo = function(x, y) {\r\n this.p1 = [rounded(x), rounded(y)];\r\n };\r\n\r\n})();\r\n\/*global Rocky:true *\/\r\n\r\nif (typeof (Rocky) === \'undefined\') {\r\n Rocky = {};\r\n}\r\n\r\n(function() {\r\n function clockwiseRad(fraction) {\r\n \/\/ TODO: figure out if this is actually correct orientation for Canvas APIs\r\n return (1.5 - fraction) * 2 * Math.PI;\r\n }\r\n\r\n Rocky.WatchfaceHelper = function(date) {\r\n date = date || new Date();\r\n var secondFraction = date.getSeconds() \/ 60;\r\n var minuteFraction = (date.getMinutes()) \/ 60;\r\n var hourFraction = (date.getHours() % 12 + minuteFraction) \/ 12;\r\n this.secondAngle = clockwiseRad(secondFraction);\r\n this.minuteAngle = clockwiseRad(minuteFraction);\r\n this.hourAngle = clockwiseRad(hourFraction);\r\n };\r\n})();\r\n\/*global Rocky:true *\/\r\n\r\nif (typeof (Rocky) === \'undefined\') {\r\n Rocky = {};\r\n}\r\n\r\n(function() {\r\n Rocky.TickService = function(listener) {\r\n this.listener = listener;\r\n };\r\n\r\n Rocky.TickService.Events = {\r\n SecondChange: \'secondchange\',\r\n MinuteChange: \'minutechange\',\r\n HourChange: \'hourchange\',\r\n DayChange: \'daychange\'\r\n };\r\n\r\n var segmentSizes = [\r\n [\'secondchange\', 1000],\r\n [\'minutechange\', 1000 * 60],\r\n [\'hourchange\', 1000 * 60 * 60],\r\n [\'daychange\', 1000 * 60 * 60 * 24]\r\n ];\r\n\r\n Rocky.TickService.prototype.eventObject = function(date) {\r\n var now = date.getTime();\r\n var result = {date: date};\r\n for (var i = 0; i < segmentSizes.length; i++) {\r\n var segment = segmentSizes[i];\r\n var eventName = segment[0];\r\n var segmentSize = segment[1];\r\n var msUntilEndOfSegment = segmentSize - now % segmentSize;\r\n result[eventName] = msUntilEndOfSegment === 0;\r\n }\r\n\r\n return result;\r\n };\r\n\r\n Rocky.TickService.prototype.schedule = function() {\r\n var now = new Date();\r\n\r\n var event = this.eventObject(now);\r\n this.listener(event);\r\n\r\n \/\/ we\'re iterating from the smaller to the larger segments\r\n \/\/ which is ok (as they are multiples)\r\n \/\/ we fire an event for the smallest segment\r\n var nowMs = now.getTime();\r\n \/\/ HACK! always assumes minute minute change!\r\n\r\n var segment = segmentSizes[1];\r\n var eventName = segment[0];\r\n var segmentSize = segment[1];\r\n\r\n var msUntilEndOfSegment = segmentSize - nowMs % segmentSize;\r\n\r\n \/\/ prepare the passed date object to reflect the future date\r\n var futureDate = new Date(nowMs + msUntilEndOfSegment);\r\n this.timeoutId = setTimeout(function() {\r\n this.listener(eventName, this.eventObject(futureDate));\r\n this.schedule();\r\n }.bind(this), msUntilEndOfSegment);\r\n };\r\n})();\r\nvar rocky = new Rocky.WebAPIBinding();\r\n\/*global rocky, Rocky:false *\/\r\n\/\/ in the future, we will replace the singleton\r\n\/\/ `rocky` as well as the namespace `Rocky`, e.g.\r\n\/\/ `Rocky.tween` and `Rocky.WatchfaceHelper` with modules\r\n\r\n\/\/ book keeping so that we can easily animate the two hands for the watchface\r\n\/\/ .scale\/.angle are updated by tween\/event handler (see below)\r\nvar renderState = {\r\n minute: {style: \'white\', scale: 0.80, angle: 0},\r\n hour: {style: \'red\', scale: 0.51, angle: 0}\r\n};\r\n\r\n\/\/ helper function for the draw function (see below)\r\n\/\/ extracted as a standalone function to satisfy common believe in efficient JS code\r\n\/\/ TODO: verify that this has actually any effect on byte code level\r\nvar drawHand = function(handState, ctx, cx, cy, maxRadius) {\r\n ctx.lineWidth = 8;\r\n ctx.strokeStyle = handState.style;\r\n ctx.beginPath();\r\n ctx.moveTo(cx, cy);\r\n ctx.lineTo(cx + Math.sin(handState.angle) * handState.scale * maxRadius,\r\n cy + Math.cos(handState.angle) * handState.scale * maxRadius);\r\n ctx.stroke();\r\n};\r\n\r\n\/\/ the \'draw\' event is being emitted after each call to rocky.requestDraw() but\r\n\/\/ at most once for each screen update, even if .requestDraw() is called frequently\r\n\/\/ the \'draw\' event might also fire at other meaningful times (e.g. upon launch)\r\nrocky.on(\'draw\', function(drawEvent) {\r\n var ctx = drawEvent.context;\r\n var w = ctx.canvas.clientWidth;\r\n var h = ctx.canvas.clientHeight;\r\n\r\n \/\/ clear canvas on each render\r\n ctx.fillStyle = \'black\';\r\n ctx.fillRect(0, 0, w, h);\r\n\r\n \/\/ center point\r\n var cx = w \/ 2;\r\n var cy = h \/ 2;\r\n var maxRadius = Math.min(w, h - 2 * 10) \/ 2;\r\n drawHand(renderState.minute, ctx, cx, cy, maxRadius);\r\n drawHand(renderState.hour, ctx, cx, cy, maxRadius);\r\n\r\n \/\/ Draw a 12 o clock indicator\r\n drawHand({style: \'white\', scale: 0, angle: 0}, ctx, cx, 8, 0);\r\n \/\/ overdraw center so that no white part of the minute hand is visible\r\n drawHand({style: \'red\', scale: 0, angle: 0}, ctx, cx, cy, 0);\r\n});\r\n\r\n\/\/ listener is called on each full minute and once immediately after registration\r\nrocky.on(\'minutechange\', function(e) {\r\n \/\/ WatchfaceHelper will later be extracted as npm module\r\n var wfh = new Rocky.WatchfaceHelper(e.date);\r\n renderState.minute.angle = wfh.minuteAngle;\r\n renderState.hour.angle = wfh.hourAngle;\r\n rocky.requestDraw();\r\n});\r\n";
|
|
function testGenerator(remainingCalls) {
|
|
var logLines = [];
|
|
var logOriginal = console.log;
|
|
console.log = function(s) {logLines.push(s);};
|
|
var result = createSnapshot(tictoc);
|
|
console.log = logOriginal;
|
|
document.writeln('<pre>');
|
|
logLines.forEach(function(s) {
|
|
document.writeln(s);
|
|
});
|
|
document.write(JSON.stringify(result));
|
|
document.writeln('</pre>');
|
|
if (remainingCalls > 0) {
|
|
setTimeout(function(){testGenerator(remainingCalls - 1);}, 200);
|
|
}
|
|
}
|
|
setTimeout(function(){testGenerator(3);}, 200);
|
|
</script>
|
|
</head>
|
|
<body>
|
|
|
|
</body>
|
|
</html> |