Skip to content

Commit 6d15060

Browse files
committed
文本支持、填充支持、展开选项
1 parent bc365b8 commit 6d15060

File tree

7 files changed

+234
-72
lines changed

7 files changed

+234
-72
lines changed

src/App.vue

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<pre>{{ formatted }}</pre>
1616
</div>
1717
</div>
18-
<Graph :key="cnt" :graphData="graphData" ref="graphRef" />
18+
<Graph :key="graphKey" :graphData="graphData" ref="graphRef" />
1919
</div>
2020
</template>
2121

@@ -29,25 +29,25 @@ import JSON5 from "json5";
2929
import prettier from "prettier/standalone";
3030
import prettierPluginBabel from "prettier/plugins/babel";
3131
import prettierPluginEstree from "prettier/plugins/estree";
32-
import prettierPluginPostcss from "prettier/plugins/postcss";
32+
import { cloneDeep } from "lodash-es";
3333
3434
const graphRef = ref<InstanceType<typeof Graph>>();
3535
const graphData = reactive<FunctionPlotDatum[]>([{ fn: "x^2" }]);
36-
const cnt = ref(0);
36+
const graphKey = ref(0);
3737
const formatted = ref("");
3838
watch(
3939
graphData,
4040
() => {
41-
cnt.value++;
41+
graphKey.value++;
42+
const dataArr = cloneDeep(graphData);
43+
dataArr.forEach((item) => {
44+
if (item.graphType === "text") delete item.fnType;
45+
});
4246
prettier
43-
.format(JSON5.stringify({ data: graphData }), {
47+
.format(JSON5.stringify({ data: dataArr }), {
4448
parser: "json5",
4549
printWidth: 40,
46-
plugins: [
47-
prettierPluginBabel,
48-
prettierPluginEstree,
49-
prettierPluginPostcss,
50-
],
50+
plugins: [prettierPluginBabel, prettierPluginEstree],
5151
})
5252
.then((value) => (formatted.value = value));
5353
},
@@ -86,7 +86,6 @@ watch(
8686
#editor {
8787
width: 33vw;
8888
border-right: var(--c-border) 1px solid;
89-
9089
position: relative;
9190
}
9291
.editor-inner {
@@ -98,7 +97,7 @@ watch(
9897
bottom: 300px;
9998
}
10099
#graph {
101-
width: 60vw;
100+
flex-grow: 1;
102101
position: relative;
103102
}
104103
.add-data {
@@ -129,10 +128,10 @@ watch(
129128
}
130129
.plot-data.output pre {
131130
position: absolute;
132-
top:60px;
133-
bottom:15px;
134-
left:15px;
135-
right:15px;
131+
top: 60px;
132+
bottom: 15px;
133+
left: 15px;
134+
right: 15px;
136135
margin: 0;
137136
overflow: scroll;
138137
user-select: all;

src/components/dataBlock.vue

Lines changed: 121 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
{{ type.label }}
88
</option>
99
</select>
10-
<select v-model="dataItem.graphType">
10+
<select v-model="dataItem.graphType" v-if="dataItem.graphType !== 'text'">
1111
<option
12-
v-if="!getFnType(dataItem.fnType).notAllowedInIntervel"
12+
v-if="!getFnType(dataItem.fnType).notAllowedInInterval"
1313
:value="undefined"
1414
>
1515
{{ graphTypeArr[0].label }}
@@ -22,7 +22,14 @@
2222
{{ type.label }}
2323
</option>
2424
</select>
25-
<button class="delete" @click="emit('delete')">删除</button>
25+
<button class="delete blockBtn" @click="emit('delete')">删除</button>
26+
<button
27+
class="fold blockBtn"
28+
:class="{ active: !blockFolded }"
29+
@click="blockFolded = !blockFolded"
30+
>
31+
更多
32+
</button>
2633
</div>
2734

2835
<div class="inputs">
@@ -36,25 +43,47 @@
3643
</div>
3744
<template v-if="getFnType(dataItem.fnType).coord">
3845
<div
39-
v-for="input in getFnType(dataItem.fnType).coord"
46+
v-for="input in getFnType(dataItem.fnType).coord?.filter(
47+
({ folded }) => !(folded && blockFolded)
48+
)"
4049
class="input-box coord"
4150
:class="{ optional: input.optional }"
4251
>
4352
<span class="coord-label">{{ input.label }}</span>
4453
<input
4554
type="number"
4655
@input="handleCoordInput(dataItem!, input, 0, $event)"
47-
:placeholder="input.placeholder1"
56+
:placeholder="input.placeholder[0]"
4857
/>
4958
<span class="coord-label">{{ input.sep }}</span>
5059
<input
5160
type="number"
5261
@input="handleCoordInput(dataItem!, input, 1, $event)"
53-
:placeholder="input.placeholder2"
62+
:placeholder="input.placeholder[1]"
5463
/>
5564
<span class="coord-label">{{ input.fin }}</span>
5665
</div>
5766
</template>
67+
68+
<template v-if="getFnType(dataItem.fnType).switches">
69+
<div
70+
v-for="input in getFnType(dataItem.fnType).switches?.filter(
71+
({ folded }) => !(folded && blockFolded)
72+
)"
73+
class="input-box switches"
74+
@click="
75+
dataItem[input.value]
76+
? delete dataItem[input.value]
77+
: (dataItem[input.value] = true)
78+
"
79+
>
80+
<span
81+
class="switch"
82+
:class="dataItem[input.value] ? 'on' : 'off'"
83+
></span>
84+
{{ input.label }}
85+
</div>
86+
</template>
5887
</div>
5988
</div>
6089
</template>
@@ -66,14 +95,26 @@ import { ref } from "vue";
6695
const emit = defineEmits(["delete"]);
6796
const dataItem = defineModel<FunctionPlotDatum>();
6897
const block = ref<HTMLDivElement>();
69-
function fnTypeChange(dataItem: FunctionPlotDatum) {
70-
if (getFnType(dataItem.fnType).notAllowedInIntervel && !dataItem.graphType)
71-
dataItem.graphType = "polyline";
72-
if (dataItem.fnType === "implicit") delete dataItem.graphType;
98+
const blockFolded = ref(true);
99+
function fnTypeChange(
100+
dataItem:
101+
| (Omit<FunctionPlotDatum, "fnType"> & {
102+
fnType: "text" | FunctionPlotDatum["fnType"];
103+
})
104+
| FunctionPlotDatum
105+
) {
73106
inputTypeArr.forEach((key) => delete dataItem[key]);
74-
if (dataItem.fnType === "vector") dataItem.vector = [0, 0];
75-
if (block.value)
76-
block.value.querySelectorAll("input").forEach((ele) => (ele.value = ""));
107+
if (dataItem.fnType === "text") {
108+
dataItem.graphType = "text";
109+
} else {
110+
if (dataItem.graphType === "text" || dataItem.fnType === "implicit")
111+
delete dataItem.graphType;
112+
if (getFnType(dataItem.fnType).notAllowedInInterval && !dataItem.graphType)
113+
dataItem.graphType = "polyline";
114+
if (dataItem.fnType === "vector") dataItem.vector = [0, 0];
115+
if (block.value)
116+
block.value.querySelectorAll("input").forEach((ele) => (ele.value = ""));
117+
}
77118
}
78119
function handleCoordInput(
79120
dataItem: FunctionPlotDatum,
@@ -105,22 +146,27 @@ function handleCoordInput(
105146
position: relative;
106147
padding: 20px 15px;
107148
}
108-
.delete {
109-
position: absolute;
110-
top: 0;
111-
bottom: 0;
112-
right: 0;
149+
.blockBtn {
150+
height: 100%;
151+
float: right;
113152
color: var(--c-text);
114153
padding: 8px 15px;
115154
border: none;
116-
background: var(--c-red);
155+
background: var(--c-border);
156+
margin-left: 10px;
117157
border-radius: 5px;
118158
opacity: 0.75;
119159
}
120-
.delete:hover {
160+
.delete {
161+
background: var(--c-red);
162+
}
163+
.blockBtn.active {
164+
background: var(--c-accent);
165+
}
166+
.blockBtn:hover {
121167
opacity: 1;
122168
}
123-
.delete:active {
169+
.blockBtn:active {
124170
opacity: 0.3;
125171
}
126172
.selectors {
@@ -195,4 +241,58 @@ function handleCoordInput(
195241
font-size: 18px;
196242
flex-shrink: 1;
197243
}
244+
245+
.input-box.switches {
246+
align-items: center;
247+
gap: 10px;
248+
padding-left: 5px;
249+
}
250+
251+
.switch:before,
252+
.switch:after {
253+
position: absolute;
254+
transition: all 0.2s cubic-bezier(0, 0.48, 0.27, 0.98);
255+
}
256+
257+
.switch {
258+
width: 40px;
259+
height: 20px;
260+
border-radius: 5px;
261+
position: relative;
262+
}
263+
264+
.switch {
265+
border-radius: 10px;
266+
}
267+
268+
.switch.on {
269+
background: var(--c-accent);
270+
}
271+
272+
.switch.off {
273+
background: var(--c-border);
274+
}
275+
.switch:after {
276+
content: "";
277+
background: #fff;
278+
width: 12px;
279+
height: 12px;
280+
border-radius: 50%;
281+
top: 0;
282+
bottom: 0;
283+
margin: auto 0;
284+
}
285+
.switch.off:after {
286+
left: 4px;
287+
}
288+
.switch.on:after {
289+
left: 24px;
290+
}
291+
.switch:hover {
292+
filter: brightness(110%);
293+
}
294+
295+
.switch:active {
296+
filter: brightness(90%);
297+
}
198298
</style>

src/components/editor.vue

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/components/graph.vue

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66

77
<script setup lang="ts">
88
import { onMounted, onUnmounted, ref, watch } from "vue";
9-
import functionPlot from "function-plot";
10-
import { throttle } from "lodash-es";
9+
import { throttle, cloneDeep } from "lodash-es";
1110
import type { FunctionPlotDatum } from "function-plot";
1211
import { getFnType } from "../consts";
1312
const { graphData } = defineProps<{ graphData: FunctionPlotDatum[] }>();
@@ -22,17 +21,18 @@ const handleResize = () => {
2221
height.value = shellRef.value.clientHeight;
2322
}
2423
};
25-
onMounted(() => {
24+
onMounted(async () => {
25+
const functionPlot = (await import("function-plot")).default;
2626
handleResize();
2727
window.addEventListener("resize", handleResize);
2828
watch(
2929
[width, height],
3030
throttle(() => {
31-
const data = <FunctionPlotDatum[]>JSON.parse(JSON.stringify(graphData));
31+
const data = <FunctionPlotDatum[]>cloneDeep(graphData);
3232
let flag = 0;
3333
outer: for (const [index, dataItem] of data.entries()) {
3434
const fnType = getFnType(dataItem.fnType);
35-
if (fnType.notAllowedInIntervel && !dataItem.graphType) {
35+
if (fnType.notAllowedInInterval && !dataItem.graphType) {
3636
flag = index;
3737
break;
3838
}
@@ -72,7 +72,7 @@ onUnmounted(() => window.removeEventListener("resize", handleResize));
7272
right: 0;
7373
left: 0;
7474
bottom: 0;
75-
filter: invert(100%) hue-rotate(210deg) brightness(133%);
75+
filter: invert(100%) hue-rotate(180deg) brightness(133%);
7676
color: black;
7777
user-select: none;
7878
}

0 commit comments

Comments
 (0)