mirror of
https://github.com/JannisX11/blockbench.git
synced 2025-01-30 15:42:42 +08:00
Improve timeline graph editor, render keyframes
This commit is contained in:
parent
566fdfdc2c
commit
6cf0fe4230
@ -714,7 +714,7 @@
|
||||
margin-left: -2px;
|
||||
}
|
||||
|
||||
#timeline_body .keyframe {
|
||||
#timeline .keyframe {
|
||||
position: absolute;
|
||||
margin-left: -6px;
|
||||
z-index: 3;
|
||||
@ -722,14 +722,14 @@
|
||||
width: 13.5px;
|
||||
height: 23px;
|
||||
}
|
||||
#timeline_body .keyframe i {
|
||||
#timeline .keyframe i {
|
||||
margin-top: 2px;
|
||||
transform: rotate(45deg);
|
||||
font-size: 14pt;
|
||||
margin-left: -3px;
|
||||
pointer-events: none;
|
||||
}
|
||||
#timeline_body .keyframe i.keyframe_icon_smaller {
|
||||
#timeline .keyframe i.keyframe_icon_smaller {
|
||||
font-size: 11pt;
|
||||
margin-top: 4px;
|
||||
margin-left: -1px;
|
||||
@ -743,7 +743,7 @@
|
||||
font-size: 6pt;
|
||||
color: var(--color-grid);
|
||||
}
|
||||
#timeline_body .keyframe.selected {
|
||||
#timeline .keyframe.selected {
|
||||
color: var(--color-accent) !important;
|
||||
z-index: 4;
|
||||
}
|
||||
@ -916,20 +916,31 @@
|
||||
|
||||
#timeline_graph_editor {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
top: 28px;
|
||||
bottom: 9px;
|
||||
right: 6px;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
}
|
||||
#timeline_graph_editor svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-left: 9px;
|
||||
pointer-events: none;
|
||||
}
|
||||
#timeline_graph_editor svg path {
|
||||
stroke: #f72858;
|
||||
stroke-width: 2px;
|
||||
fill: none;
|
||||
}
|
||||
#timeline_graph_editor .keyframe {
|
||||
height: 16px;
|
||||
width: 11px;
|
||||
font-size: 10px;
|
||||
}
|
||||
#timeline_graph_editor .keyframe > i {
|
||||
margin-top: 0px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
|
||||
/*UV*/
|
||||
|
@ -57,6 +57,7 @@ const Timeline = {
|
||||
if (e.which !== 1 || (
|
||||
!e.target.classList.contains('keyframe_section') &&
|
||||
!e.target.classList.contains('animator_head_bar') &&
|
||||
e.target.id !== 'timeline_graph_editor' &&
|
||||
e.target.id !== 'timeline_body_inner'
|
||||
)) {
|
||||
return
|
||||
@ -123,16 +124,20 @@ const Timeline = {
|
||||
channels[kf.channel] != false &&
|
||||
(!channels.hide_empty || animator[kf.channel].length)
|
||||
) {
|
||||
var channel_index = 0 //animator.channels.indexOf(kf.channel);
|
||||
|
||||
for (var channel of animator.channels) {
|
||||
if (kf.channel == channel) break;
|
||||
if (channels[channel] != false && (!channels.hide_empty || animator[channel].length)) {
|
||||
channel_index++;
|
||||
}
|
||||
}
|
||||
if (!Timeline.vue.graph_editor_open) {
|
||||
|
||||
height = offset + channel_index*24 + 36;
|
||||
var channel_index = 0 //animator.channels.indexOf(kf.channel);
|
||||
for (var channel of animator.channels) {
|
||||
if (kf.channel == channel) break;
|
||||
if (channels[channel] != false && (!channels.hide_empty || animator[channel].length)) {
|
||||
channel_index++;
|
||||
}
|
||||
}
|
||||
var height = offset + channel_index*24 + 36;
|
||||
|
||||
} else {
|
||||
var height = Timeline.vue.graph_offset - (kf.display_value || 0) * Timeline.vue.graph_size + Timeline.vue.scroll_top;
|
||||
}
|
||||
if (height > rect.ay && height < rect.by) {
|
||||
kf.selected = true;
|
||||
Timeline.selected.push(kf);
|
||||
@ -369,6 +374,7 @@ const Timeline = {
|
||||
});
|
||||
$('#timeline_body').on('scroll', e => {
|
||||
Timeline.vue._data.scroll_left = $('#timeline_body').scrollLeft()||0;
|
||||
Timeline.vue._data.scroll_top = $('#timeline_body').scrollTop()||0;
|
||||
})
|
||||
|
||||
BarItems.slider_animation_speed.update()
|
||||
@ -644,6 +650,7 @@ onVueSetup(function() {
|
||||
length: 10,
|
||||
animation_length: 0,
|
||||
scroll_left: 0,
|
||||
scroll_top: 0,
|
||||
head_width: 180,
|
||||
timecodes: [],
|
||||
animators: Timeline.animators,
|
||||
@ -657,6 +664,7 @@ onVueSetup(function() {
|
||||
graph_editor_axis: 'x',
|
||||
graph_offset: 200,
|
||||
graph_size: 200,
|
||||
graph_keyframe_values: new Map(),
|
||||
|
||||
channels: {
|
||||
rotation: true,
|
||||
@ -665,6 +673,11 @@ onVueSetup(function() {
|
||||
hide_empty: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
graph_editor_animator() {
|
||||
return this.animators.find(animator => animator.selected && animator instanceof BoneAnimator);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleAnimator(animator) {
|
||||
animator.expanded = !animator.expanded;
|
||||
@ -686,34 +699,40 @@ onVueSetup(function() {
|
||||
return points.join(' ');
|
||||
},
|
||||
getGraph() {
|
||||
let ba = Animation.selected.getBoneAnimator();
|
||||
let ba = this.graph_editor_animator;
|
||||
let original_time = Timeline.time;
|
||||
let step = Timeline.getStep() * this.size;
|
||||
step = Math.clamp(step, 1, 5)
|
||||
let timeline_offset = this.scroll_left - 9;
|
||||
let timeline_offset_rounded = Math.round(timeline_offset/step)*step;
|
||||
let clientWidth = this.$refs.graph_editor ? this.$refs.graph_editor.clientWidth : 400;
|
||||
let clientHeight = this.$refs.graph_editor ? this.$refs.graph_editor.clientHeight : 400;
|
||||
let clientHeight = this.$refs.timeline_body ? this.$refs.timeline_body.clientHeight : 400;
|
||||
let points = [];
|
||||
let min = -1;
|
||||
let max = 1;
|
||||
|
||||
for (let time = timeline_offset_rounded; time < timeline_offset + clientWidth; time += step) {
|
||||
for (let time = 0; time < clientWidth; time += step) {
|
||||
Timeline.time = time / this.size;
|
||||
let value = ba.interpolate(this.graph_editor_channel, false, this.graph_editor_axis);
|
||||
points.push(value);
|
||||
min = Math.min(min, value);
|
||||
max = Math.max(max, value);
|
||||
}
|
||||
Timeline.time = original_time;
|
||||
|
||||
let padding = 30
|
||||
this.graph_size = (clientHeight - 2*padding) / (max-min);
|
||||
this.graph_offset = clientHeight - padding + (this.graph_size * min);
|
||||
|
||||
this.graph_keyframe_values.clear();
|
||||
ba[this.graph_editor_channel].forEach(kf => {
|
||||
|
||||
Timeline.time = kf.time;
|
||||
let value = ba.interpolate(this.graph_editor_channel, false, this.graph_editor_axis);
|
||||
kf.display_value = value;
|
||||
})
|
||||
Timeline.time = original_time;
|
||||
|
||||
let string = '';
|
||||
points.forEach((value, i) => {
|
||||
string += `${string.length ? 'L' : 'M'}${i*step - timeline_offset + timeline_offset_rounded} ${this.graph_offset - value * this.graph_size} `
|
||||
string += `${string.length ? 'L' : 'M'}${i*step} ${this.graph_offset - value * this.graph_size} `
|
||||
})
|
||||
|
||||
return string;
|
||||
@ -752,7 +771,7 @@ onVueSetup(function() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="timeline_body">
|
||||
<div id="timeline_body" ref="timeline_body">
|
||||
<div id="timeline_body_inner" v-bind:style="{width: (size*length + head_width)+'px'}" @contextmenu.stop="Timeline.showMenu($event)">
|
||||
<li v-for="animator in animators" class="animator" :class="{selected: animator.selected}" :uuid="animator.uuid" v-on:click="animator.select();">
|
||||
<div class="animator_head_bar">
|
||||
@ -827,14 +846,28 @@ onVueSetup(function() {
|
||||
<div id="timeline_empty_head" class="channel_head" v-bind:style="{left: scroll_left+'px', width: head_width+'px'}">
|
||||
</div>
|
||||
<div id="timeline_selector" class="selection_rectangle"></div>
|
||||
<div id="timeline_graph_editor" ref="graph_editor" v-if="graph_editor_open" :style="{left: head_width + 'px', top: scroll_top + 'px'}">
|
||||
<svg>
|
||||
<path :d="\`M0 \${graph_offset} L10000 \${graph_offset}\`" style="stroke: var(--color-grid);"></path>
|
||||
<path :d="getGraph()" :style="{stroke: 'var(--color-axis-' + graph_editor_axis + ')'}"></path>
|
||||
</svg>
|
||||
<keyframe
|
||||
v-for="keyframe in graph_editor_animator[graph_editor_channel]"
|
||||
v-bind:style="{left: (10 + keyframe.time * size) + 'px', top: (graph_offset - keyframe.display_value * graph_size - 8) + 'px', color: getColor(keyframe.color)}"
|
||||
class="keyframe graph_keyframe"
|
||||
v-bind:class="[keyframe.channel, keyframe.selected?'selected':'']"
|
||||
v-bind:id="keyframe.uuid"
|
||||
v-on:click.stop="keyframe.select($event)"
|
||||
v-on:dblclick="keyframe.callPlayhead()"
|
||||
:title="tl('timeline.'+keyframe.channel)"
|
||||
@contextmenu.prevent="keyframe.showContextMenu($event)"
|
||||
>
|
||||
<i class="material-icons keyframe_icon_smaller" v-if="keyframe.interpolation == 'catmullrom'">lens</i>
|
||||
<i class="material-icons" v-else>stop</i>
|
||||
</keyframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="timeline_graph_editor" ref="graph_editor" v-if="graph_editor_open" :style="{left: head_width + 'px'}">
|
||||
<svg>
|
||||
<path :d="\`M0 \${graph_offset} L10000 \${graph_offset}\`" style="stroke: var(--color-grid);"></path>
|
||||
<path :d="getGraph()" :style="{stroke: 'var(--color-axis-' + graph_editor_axis + ')'}"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user