Public
Edited
Jun 20, 2023
Insert cell
md`# Drivetrain Picker`
Insert cell
picker = {
return Preact.render(htm`<${DrivetrainPicker} page="All" />`)
}
Insert cell
class DrivetrainPicker extends Preact.Component {
constructor(){
super([]);
this.state = {wheel: 680, crank: 170};
}
handleSubmit(evt){
evt.preventDefault();

var event = new Event('addDrivetrain');
console.log(this.state.label)
if(!this.state.label || this.state.label === ''){
const co = this.state.cassetteOut;
const label = `${this.state.chainringOut.join('-')}T : ${co[0]}-${co[co.length - 1]}T`
this.setState({label: label})
}
event['drivetrain'] = this.state;

this.setState({label: null, cassetteOut: null, chainringOut: null, cassetteSearch: null, chainringSearch: null});

this.base.dispatchEvent(event);

}
handleLabel(evt){
this.setState({label: evt.target.value});
}
handleWheel(evt){
this.setState({wheel: evt.target.value});
}
handleCrank(evt){
this.setState({crank: evt.target.value});
}
handleManualCassette(evt){

const input = evt.target.value.replace(/[^\d,-]/g, '').split(/[,-]+/).sort(d3.ascending);
this.setState({cassetteOut: input, cassetteSearch: null});
}
handleManualChainring(evt){
const input = evt.target.value.replace(/[^\d,-]/g, '').split(/[,-]+/).sort(d3.descending);
this.setState({chainringOut: input, chainringSearch: null});
}
handleCassetteChange(evt) {
const match = cassette.find(d => `${d.seriesName}: ${d.name}` === evt.target.value)
this.setState({cassetteOut: match.sprockets, cassetteSearch: evt.target.value});
}
handleChainringChange(evt) {
const match = chainrings.find(d => `${d.seriesName}: ${d.chainring}` === evt.target.value)
this.setState({chainringOut: match.chainring.replace('T','').split(/[,-]+/).map(d => +d),
chainringSearch: evt.target.value});
}
render({page}, {todos = []}) {
return htm`
<div class="picker">
<form onSubmit=${(e) => this.handleSubmit(e)}>
<div class="input-group">
<label for="cassette-in">Cassette</label>
<input placeholder="Search..." name="cassette-in" type="text" list="cassette-dl" onChange=${(e) => this.handleCassetteChange(e)} value="${this.state.cassetteSearch}"></input>
<input placeholder="Enter manually (comma delimited)" name="cassette-out" type="text" value="${this.state.cassetteOut}" onChange=${(e) => this.handleManualCassette(e)} required></input>
<datalist id="cassette-dl">
${cassette.map(d => htm`
<option value="${d.seriesName}: ${d.name}"></option>
`)}
</datalist>
</div>
<div class="input-group">
<label for="chainring-in">Chainrings</label>
<input placeholder="Search..." name="chainring-in" type="text" list="chainring-dl" onChange=${(e) => this.handleChainringChange(e)} value=${this.state.chainringSearch}></input>
<input placeholder="Enter manually (comma delimited)" name="chainring-out" type="text" value="${this.state.chainringOut}" onChange="${(e) => this.handleManualChainring(e)}" required></input>
<datalist id="chainring-dl">
${chainrings.map(d => htm`
<option>${d.seriesName}: ${d.chainring}</option>
`)}
</datalist>
</div>
<div class="input-group">
<label for="name-in">Label</label>
<input name="label-in" type="text" onChange=${(e) => this.handleLabel(e)} value="${this.state.label}"></input>
</div>
<div class="input-group il">
<label for="wheel-in">Wheel diameter (mm)</label>
<input name="wheel-in" type="number" style="width: 100px" onChange=${(e) => this.handleWheel(e)} value=${this.state.wheel}></input>
</div>
<div class="input-group il">
<label for="wheel-in">Crank length (mm)</label>
<input name="crank-in" type="number" style="width: 100px" onChange=${(e) => this.handleCrank(e)} value=${this.state.crank}></input>
</div>
<div class="input-group">
<input type="submit" value="Add Drivetrain"></input>
</div>
</form>
</div>
`;
}
}
Insert cell
Insert cell
pickerStyle = {
return html`<style>
.input-group{
margin: .25em;
}
.il{
display: inline-block;
margin-right: 1em;
}
.input-group > input[type="submit"]{
font-size: 25px;
margin-bottom: .5em;
}
.input-group > label{
font-family: Helvetica;
font-size: 14px;
font-weight: bold;
display: block;
}
</style>
`
}
Insert cell
Insert cell
cassettesRaw = d3.tsv('https://raw.githubusercontent.com/tysonanderson/drivetrain/master/cassettes.csv')
Insert cell
cranksetsRaw = d3.tsv('https://raw.githubusercontent.com/tysonanderson/drivetrain/master/cranksets.csv')
Insert cell
d3 = require('d3@5');
Insert cell
htm = (await require("htm@2/dist/htm.umd.js")).bind(Preact.h)
Insert cell
Preact = require("preact@8/dist/preact.min.js").catch(() => window.preact)
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more