Skip to content

Commit

Permalink
create
Browse files Browse the repository at this point in the history
  • Loading branch information
marucc committed Aug 28, 2019
0 parents commit ac55803
Show file tree
Hide file tree
Showing 4 changed files with 466 additions and 0 deletions.
20 changes: 20 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# http://editorconfig.org

root = true

[*]

# Change these settings to your own preference
indent_style = space
indent_size = 2

# We recommend you to keep these unchanged
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false
303 changes: 303 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,303 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>フレーム計算</title>
<meta charset="utf-8">
<meta name="description" content="">
<meta name="author" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="">
<script src="./vue.min.js"></script>
<script src="./lodash.min.js"></script>
<style>
.container {
display: flex;
}
.item {
}
.preview {
width: 500px;
height: 500px;
}
.form {
}
ul li {
list-style: none;
}
label {
display: inline-block;
width: 14em;
}
input {
margin: 1px;
padding: 4px;
font-size: 14px;
border: 1px solid gray;
border-radius: 3px;
}
input[readonly] {
outline: 0;
border: none;
border-bottom: 1px solid gray;
border-radius: 0;
}
.error {
color: red;
}
.error input {
border: 1px solid red;
outline-color: red;
}
.border {
border-bottom: 1px solid black;
margin: 5px 0;
}
h1 {
font-size: 22px;
}
</style>
</head>
<body>
<h1>フレーム計算</h1>
<div id="app">
<div class="container">
<div class="item preview">
<canvas id="canvas" width="500" height="500" />
</div>
<div class="item form">
<ul>
<li v-bind:class="{ error: errors.frameSize }"><label>フレームサイズ: </label><input type="number" v-model="frameSize" />mm</li>
<li v-bind:class="{ error: errors.slopeSize }"><label>スローピング マイナス長: </label><input type="number" v-model="slopeSize" />mm</li>
<li v-bind:class="{ error: errors.horizontalTopTube }"><label>水平換算トップチューブ長: </label><input type="number" v-model="horizontalTopTube" />mm</li>
<li v-bind:class="{ error: errors.seatAngle }"><label>シート角度: </label><input type="number" v-model="seatAngle" />°</li>
<li v-bind:class="{ error: errors.headAngle }"><label>ヘッド角度: </label><input type="number" v-model="headAngle" />°</li>
<li v-bind:class="{ error: errors.forkOffset }"><label>フォークオフセット: </label><input type="number" v-model="forkOffset" />mm</li>
<li v-bind:class="{ error: errors.bbDrop }"><label>ハンガー下がり: </label><input type="number" v-model="bbDrop" />mm</li>
<li v-bind:class="{ error: errors.headCrown }"><label>ヘッド クラウン: </label><input type="number" v-model="headCrown" />mm</li>
<li v-bind:class="{ error: errors.headParts }"><label>ヘッドパーツ: </label><input type="number" v-model="headParts" />mm</li>
<li v-bind:class="{ error: errors.headTubeUp }"><label>ヘッドチューブ 上サイズ: </label><input type="number" v-model="headTubeUp" />mm</li>
<li v-bind:class="{ error: errors.headTubeDown }"><label>ヘッドチューブ 下サイズ: </label><input type="number" v-model="headTubeDown" />mm</li>
<li v-bind:class="{ error: errors.forkSize }"><label>フォーク長: </label><input type="number" v-model="forkSize" />mm</li>
<li class="border"></li>
<li v-bind:class="{ error: errors.headTube }"><label>ヘッドチューブ: </label><input type="number" v-model="headTube" readonly />mm</li>
<li v-bind:class="{ error: errors.downAngle }"><label>ダウン角度: </label><input type="number" v-model="downAngle" readonly />°</li>
<li v-bind:class="{ error: errors.frontCenter }"><label>フロント-センター: </label><input type="number" v-model="frontCenter" readonly />mm</li>
<li v-bind:class="{ error: errors.headTopAngle }"><label>ヘッド - トップ角度: </label><input type="number" v-model="headTopAngle" readonly />°</li>
<li v-bind:class="{ error: errors.topSeatAngle }"><label>トップ - シート角度: </label><input type="number" v-model="topSeatAngle" readonly />°</li>
</ul>
</div>
</div>
</div>
<script>
var data = {
frameSize: '540',
slopeSize: '40',
horizontalTopTube: '540',
seatAngle: '74.5',
headAngle: '72',
forkOffset: '45',
bbDrop: '70',
headCrown: '15',
headParts: '14',
headTubeUp: '20',
headTubeDown: '20',
forkSize: '350',

headTube: null,
downAngle: null,
frontCenter: null,
headTopAngle: null,
topSeatAngle: null,

errors: {
},
};
var scale = 0.5;
var drowLine = function (context, isFrame, startX, startY, relativeEndX, relativeEndY) {
var lineColor = isFrame ? 'black' : 'blue';
var lineWidth = isFrame ? 3 : 1;
context.beginPath();
context.lineWidth = lineWidth;
context.moveTo(startX * scale - 0.5, startY * scale - 0.5);
context.lineTo((startX + relativeEndX) * scale - 0.5, (startY + relativeEndY) * scale - 0.5);
context.closePath();
context.strokeStyle = lineColor;
context.stroke();
};
var drow = _.debounce(function () {
var context = this.canvas.getContext('2d');
context.clearRect(0, 0, this.canvas.width, this.canvas.height);
app.headTube = null;
app.downAngle = null;
app.frontCenter = null;
app.headTopAngle = null;
app.topSeatAngle = null;
var {
frameSize,
slopeSize,
horizontalTopTube,
seatAngle,
headAngle,
forkOffset,
bbDrop,
headCrown,
headParts,
headTubeUp,
headTubeDown,
forkSize,
} = app;

app.errors = {};
app.errors.frameSize = (frameSize === '' || frameSize < 200 || 700 < frameSize);
app.errors.slopeSize = (slopeSize === '' || slopeSize < 0 || (frameSize && frameSize / 2 < slopeSize));
app.errors.horizontalTopTube = (horizontalTopTube === '' || horizontalTopTube < 200 || 700 < horizontalTopTube);
app.errors.seatAngle = (seatAngle === '' || seatAngle < 60 || 85 < seatAngle);
app.errors.headAngle = (headAngle === '' || headAngle < 60 || 85 < headAngle);
app.errors.forkOffset = (forkOffset === '' || forkOffset < 0 || 100 < forkOffset);
app.errors.bbDrop = (bbDrop === '' || bbDrop < 0 || 100 < bbDrop);
app.errors.headCrown = (headCrown === '' || headCrown < 0 || 40 < headCrown);
app.errors.headParts = (headParts === '' || headParts < 0 || 40 < headParts);
app.errors.headTubeUp = (headTubeUp === '' || headTubeUp < 0 || 40 < headTubeUp);
app.errors.headTubeDown = (headTubeDown === '' || headTubeDown < 0 || 40 < headTubeDown);
app.errors.forkSize = (forkSize === '' || forkSize < 15 || 400 < forkSize);
if (_.values(app.errors).filter(function (v) { return v }).length) {
return;
}

frameSize = _.toNumber(frameSize);
slopeSize = _.toNumber(slopeSize);
horizontalTopTube = _.toNumber(horizontalTopTube);
forkOffset = _.toNumber(forkOffset);
bbDrop = _.toNumber(bbDrop);
headCrown = _.toNumber(headCrown);
headParts = _.toNumber(headParts);
headTubeUp = _.toNumber(headTubeUp);
headTubeDown = _.toNumber(headTubeDown);
seatAngle = _.toNumber(seatAngle);
headAngle = _.toNumber(headAngle);
forkSize = _.toNumber(forkSize);
var seatRadian = seatAngle * (Math.PI / 180);
var headRadian = headAngle * (Math.PI / 180);
var isSloping = slopeSize > 0;

var headTube = null;
var downAngle = null;
var frontCenter = null;
var headTopAngle = null;
var topSeatAngle = null;

var bbX = 800;
var bbY = bbDrop < 100 ? 900 : 900 - bbDrop;

// seatTube
var seatTubeOffsetX = frameSize * Math.cos(seatRadian);
var seatTubeHeight = frameSize * Math.sin(seatRadian);
if (seatTubeOffsetX > 200) {
bbX = 900 - seatTubeOffsetX;
}
var seatTubeRealOffsetX = seatTubeOffsetX;
var seatTubeRealHeight = seatTubeHeight;
if (isSloping) {
seatTubeRealOffsetX = (frameSize - slopeSize) * Math.cos(seatRadian);
seatTubeRealHeight = (frameSize - slopeSize) * Math.sin(seatRadian);
}
var seatGide = 80;
drowLine(context, false, bbX, bbY, (frameSize + seatGide) * Math.cos(seatRadian), (frameSize + seatGide) * Math.sin(seatRadian) * -1);
drowLine(context, true, bbX, bbY, seatTubeRealOffsetX, seatTubeRealHeight * -1);

// BB Drop base line
drowLine(context, false, 0, bbY - bbDrop, 1000, 0);

// Top Tube
var headTopTubeX = bbX + seatTubeOffsetX - horizontalTopTube;
var headTopTubeY = bbY - seatTubeHeight;
if (isSloping) {
drowLine(context, false, headTopTubeX, headTopTubeY, horizontalTopTube, 0);
}
drowLine(context, true, bbX + seatTubeRealOffsetX, bbY - seatTubeRealHeight, horizontalTopTube * -1 + (seatTubeOffsetX - seatTubeRealOffsetX), seatTubeRealHeight - seatTubeHeight);

// Head Tube
var headGideHeight = bbDrop * 2;
var headGideWidth = headGideHeight / Math.tan(headRadian);
drowLine(context, false, headTopTubeX + headGideWidth, headTopTubeY - headGideHeight, (seatTubeHeight - bbDrop + headGideHeight * 2) / Math.tan(headRadian) * -1, seatTubeHeight - bbDrop + headGideHeight * 2);

var forkOffsetRadian = (90 - headAngle) * (Math.PI / 180);
var frontX = headTopTubeX - (seatTubeHeight - bbDrop) / Math.tan(headRadian) - (forkOffset / Math.cos(forkOffsetRadian));
var frontY = bbY - bbDrop;
drowLine(context, false, frontX, frontY, forkOffset * Math.cos(forkOffsetRadian), forkOffset * Math.sin(forkOffsetRadian));

var forkRadian = (90 - (Math.asin(forkOffset / forkSize) * (180 / Math.PI)) - (90 - headAngle)) * (Math.PI / 180);
var forkHeadX = frontX + forkSize * Math.cos(forkRadian);
var forkHeadY = frontY - forkSize * Math.sin(forkRadian);
drowLine(context, false, frontX, frontY, forkHeadX - frontX, forkHeadY - frontY);

var headBottomX = forkHeadX + (headCrown + headParts) * Math.cos(headRadian);
var headBottomY = forkHeadY - (headCrown + headParts) * Math.sin(headRadian);

headTube = (headTopTubeX - headBottomX) / Math.cos(headRadian) + headTubeUp;
if (headTube < headTubeUp + headTubeDown) {
app.errors.headTube = true;
return;
}
drowLine(context, true, headBottomX, headBottomY, headTube * Math.cos(headRadian), headTube * Math.sin(headRadian) * -1);

// Down Tube
var headDownTubeX = headBottomX + headTubeDown * Math.cos(headRadian);
var headDownTubeY = headBottomY - headTubeDown * Math.sin(headRadian);
drowLine(context, true, headDownTubeX, headDownTubeY, bbX - headDownTubeX, bbY - headDownTubeY);

// Front - Center
frontCenter = bbX - frontX;
drowLine(context, false, frontX, frontY - 40, 0, 80);
drowLine(context, false, bbX - 40, bbY, 80, 0);
drowLine(context, false, bbX, bbY - bbDrop - 30, 0, 60 + bbDrop);

// Top Tube Angle
var topTubeAngle = isSloping ? Math.atan2(seatTubeHeight - seatTubeRealHeight, horizontalTopTube - (seatTubeOffsetX - seatTubeRealOffsetX)) * (180 / Math.PI) : 0;

// Down Tube Angle
downAngle = Math.atan2(bbX - headDownTubeY, bbY - headDownTubeY) * (180 / Math.PI);

// Head Tube - Top Tube Angle
headTopAngle = headAngle + topTubeAngle;

// Top Tube - Seat Tube Angle
topSeatAngle = seatAngle + topTubeAngle;


app.headTube = headTube !== null ? _.round(headTube, 1) : null;
app.downAngle = downAngle !== null ? _.round(downAngle, 1) : null;
app.frontCenter = frontCenter !== null ? _.round(frontCenter, 1) : null;
app.headTopAngle = headTopAngle !== null ? _.round(headTopAngle, 1) : null;
app.topSeatAngle = topSeatAngle !== null ? _.round(topSeatAngle, 1) : null;
}, 500);
var changed = function (newValue, oldValue) {
if (newValue != oldValue) {
drow();
}
}
var app = new Vue({
el: '#app',
data: data,
watch: {
frameSize: changed,
slopeSize: changed,
horizontalTopTube: changed,
seatAngle: changed,
headAngle: changed,
forkOffset: changed,
bbDrop: changed,
headCrown: changed,
headParts: changed,
headTubeUp: changed,
headTubeDown: changed,
forkSize: changed,
},
created: function () {
drow();
},
});
</script>
</body>
</html>
Loading

0 comments on commit ac55803

Please sign in to comment.