開発環境
- OS X El Capitan - Apple (OS)
- Emacs (Text Editor)
- JavaScript (プログラミング言語)
- D3.js (JavaScript Library)
- Safari(Web browser)
- JavaScript 第6版 (David Flanagan(著)、村上 列(翻訳)、オライリージャパン)(参考書籍)
- インタラクティブ・データビジュアライゼーション(Scott Murray(著)、長尾 高弘(翻訳)、オライリージャパン)(参考書籍)
Pythonからはじめる数学入門 (Amit Saha (著)、黒川 利明 (翻訳)、オライリージャパン)の2章(データをグラフで可視化する)、2.6(プログラミングチャレンジ)、問題2-3(投射軌跡比較プログラムの拡張)をJavaScript(とD3.js)で取り組んでみる。(バージョンアップで D3.js にいろいろ変更点があったみたい。)
問題2-3(投射軌跡比較プログラムの拡張)
コード(Emacs)
HTML5
<div id="graph0"></div>
<div id="output0"></div>
<label forid="tranjectories0">How many tranjectories?</label>
<input id="tranjectories0" type="number" min="1" step="1" value="3">
<div id="velocities0"></div>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script>
<script src="sample3.js"></script>
JavaScript
(function () {
'use strict';
var g = 9.8,
input_tranjectories = document.querySelector('#tranjectories0'),
div_velocities = document.querySelector('#velocities0'),
div_output = document.querySelector('#output0'),
div_graph = document.querySelector('#graph0'),
class_velocities,
width = 600,
height = 400,
padding = 50,
frange,
toRadian,
getTranjectory,
getTranjectories,
appendVelocities,
drawGraph;
frange = function (start, end, step) {
var numbers = [],
i;
for (i = start; i < end; i += step) {
numbers.push(i);
}
return numbers;
};
toRadian = function (angle) {
return angle * Math.PI / 180;
};
getTranjectory = function (u, theta, t_flight) {
var intervals = frange(0, t_flight, 0.05),
xs,
ys,
xys = [],
i,
max;
xs = intervals.map(function (t) {
return u * Math.cos(theta) * t;
});
ys = intervals.map(function (t) {
return u * Math.sin(theta) * t - 0.5 * g * t * t;
});
for (i = 0, max = xs.length; i < max; i += 1) {
xys.push([xs[i], ys[i]]);
}
return xys;
};
getTranjectories = function () {
var tranjectories = parseInt(input_tranjectories.value, 10);
appendVelocities(tranjectories);
};
appendVelocities = function (tranjectories) {
var html = '',
i,
max;
div_velocities.innerHTML = '';
for (i = 1; i <= tranjectories; i += 1) {
html +=
'Enter the initial velocity ' + i + ' (m/s): ' +
'<input class="velocities" id="velocity' + i +
'" type="number" ' +
'min="1"step="1" value="' +
(Math.floor(Math.random() * 70) +20) +
'"><br>' +
'Enter the angle of projection ' + i + ' (degrees): ' +
'<input class="velocities" velocities id="projection' + i +
'" type="number" min="1" step="1" value="' +
(Math.floor(Math.random() * 70) + 20) + '"><br>';
}
div_velocities.innerHTML = html;
class_velocities = document.querySelectorAll('.velocities');
drawGraph();
for (i = 0, max = class_velocities.length; i < max; i += 1) {
class_velocities[i].onchange = drawGraph;
class_velocities[i].onkeyup = drawGraph;
}
};
drawGraph = function () {
var velocities = [],
angles = [],
velocity,
angle,
radian,
t_flight,
t,
x,
y,
xys = [],
plot = [],
plot_len,
indexes = [],
index = 0,
i,
max,
xmax,
ymax,
color,
colors = [],
svg,
xscale,
yscale,
xaxis,
yaxis;
for (i = 0, max = class_velocities.length; i < max; i += 1) {
if (i % 2 === 0) {
velocities.push(parseInt(class_velocities[i].value, 10));
} else {
angles.push(parseInt(class_velocities[i].value, 10));
}
}
div_output.innerHTML = '';
for (i = 0, max = velocities.length; i < max; i += 1) {
velocity = velocities[i];
angle = angles[i];
radian = toRadian(angle);
t_flight = 2 * velocity * Math.sin(radian) / g;
x = velocity * Math.cos(radian) * t_flight;
t = t_flight / 2;
y = velocity * Math.sin(radian) * t - 0.5 * g * t * t;
color = 'rgb(' +
Math.floor(Math.random() * 200) + ', ' +
Math.floor(Math.random() * 200) + ', ' +
Math.floor(Math.random() * 200) + ')';
colors.push(color);
div_output.innerHTML +=
'<span style="color:' + color + ';">----------</span><br>' +
'velocity: ' + velocity + ', angle: ' + angle + '<br>' +
' time: ' + t_flight +
', x: ' + x + ', y: ' + y + '<br>';
xys = getTranjectory(velocity, radian, t_flight);
plot = plot.concat(xys);
index += xys.length;
indexes.push(index - 1);
}
plot_len = plot.length;
indexes.push(plot_len - 1);
xmax = d3.max(plot.map(function (elem) {
return elem[0];
}));
xscale = d3.scaleLinear()
.domain([0, xmax])
.range([padding, width - padding]);
xaxis = d3.axisBottom().scale(xscale);
ymax = d3.max(plot.map(function (elem) {
return elem[1];
}));
yscale = d3.scaleLinear()
.domain([0, ymax])
.range([height - padding, padding]);
yaxis = d3.axisLeft().scale(yscale);
div_graph.innerHTML = '';
svg = d3.select('#graph0')
.append('svg')
.attr('width', width)
.attr('height', height);
color = colors.shift();
svg.selectAll('line')
.data(plot)
.enter()
.append('line')
.attr('x1', function (d, i) {
if (indexes.indexOf(i) !== -1) {
return xscale(0);
}
return xscale(d[0]);
})
.attr('y1', function (d, i) {
if (indexes.indexOf(i) !== -1) {
return yscale(0);
}
return yscale(d[1]);
})
.attr('x2', function (d, i) {
if (indexes.indexOf(i) !== -1) {
return xscale(0);
}
return xscale(plot[i+1][0]);
})
.attr('y2', function (d, i) {
if (indexes.indexOf(i) !== -1) {
return yscale(0);
}
return yscale(plot[i+1][1]);
})
.attr('stroke', function (d, i) {
if (indexes.indexOf(i) !== -1) {
color = colors.shift();
return 'white';
}
return color;
});
svg.append('g')
.attr('transform', 'translate(0, ' + (height - padding) + ')')
.call(xaxis);
svg.append('g')
.attr('transform', 'translate(' + padding + ', 0)')
.call(yaxis);
svg.append('text')
.attr('x', xscale(xmax / 2))
.attr('y', padding / 2)
.attr('text-anchor', 'middle')
.text('Projectile motion of a ball');
svg.append('text')
.attr('x', xscale(xmax / 2))
.attr('y', height - padding / 4)
.attr('text-anchor', 'middle')
.text('x');
svg.append('text')
.attr('x', padding / 5)
.attr('y', (height - padding) / 2 )
.attr('text-anchor', 'middle')
.text('y');
};
getTranjectories();
input_tranjectories.onchange = getTranjectories;
input_tranjectories.onkeyup = getTranjectories;
}());
0 コメント:
コメントを投稿