Initial commit

This commit is contained in:
LeeJu 2026-04-10 19:10:13 +08:00
parent 5b8129e67f
commit f72ce70ee1
54 changed files with 3341 additions and 0 deletions

16
drawing/README.md Normal file
View File

@ -0,0 +1,16 @@
# drawing
1、项目说明
本项目拟实现一个复杂函数计算及其曲线绘制系统基本功能为1用户能够设置自变量的步长和个数2程序会根据用户设置的函数以及步长和个数信息解析函数获取点集并执行绘制的操作3用户能够自定义函数并保存在可识别函数中使其能够参与新函数的构造4用户能够切换函数分别在二维和三维环境下的绘制5程序会解析用户输入的函数将多项式分成单项式并以“树”的形式呈现。
2、开发环境说明
1系统版本OpenHarmony 4.0 Release
2SDK版本API 10
3Model类型Stage
4DevEco Studio版本Deveco Studio 4.0 release
5硬件环境Unionpi Whale、RK3566开发板
6预览器参数(1)DeviceType:default;(2)Resolution:560-1280;(3)DPI:240;其余参数自定。
3、项目主要函数调用关系图与项目输出界面演进图
图3.7 项目主要函数调用关系图
图3.8 项目输出界面演进图

11
drawing/draw/.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
/node_modules
/oh_modules
/local.properties
/.idea
**/build
/.hvigor
.cxx
/.clangd
/.clang-format
/.clang-tidy
**/.test

View File

@ -0,0 +1,10 @@
{
"app": {
"bundleName": "com.test.myapplication",
"vendor": "example",
"versionCode": 1000000,
"versionName": "1.0.0",
"icon": "$media:app_icon",
"label": "$string:app_name"
}
}

View File

@ -0,0 +1,8 @@
{
"string": [
{
"name": "app_name",
"value": "MyApplication"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,49 @@
{
"app": {
"signingConfigs": [
{
"name": "default",
"material": {
"certpath": "C:\\Users\\cyf20\\.ohos\\config\\openharmony\\auto_ohos_default_draw_com.test.myapplication.cer",
"storePassword": "0000001A41B8AC51384118050B5A9A22C9E132AA02BE60C9CBE187B4D7B69A17D2C070E0DF83E06DC1E4",
"keyAlias": "debugKey",
"keyPassword": "0000001A98556E0863F7805DEA1D57929A5FF99B10F6509C866A4450C6198E40C8F4F0701876AB99F565",
"profile": "C:\\Users\\cyf20\\.ohos\\config\\openharmony\\auto_ohos_default_draw_com.test.myapplication.p7b",
"signAlg": "SHA256withECDSA",
"storeFile": "C:\\Users\\cyf20\\.ohos\\config\\openharmony\\auto_ohos_default_draw_com.test.myapplication.p12"
}
}
],
"products": [
{
"name": "default",
"signingConfig": "default",
"compileSdkVersion": 10,
"compatibleSdkVersion": 10,
"runtimeOS": "OpenHarmony",
}
],
"buildModeSet": [
{
"name": "debug",
},
{
"name": "release"
}
]
},
"modules": [
{
"name": "entry",
"srcPath": "./entry",
"targets": [
{
"name": "default",
"applyToProducts": [
"default"
]
}
]
}
]
}

6
drawing/draw/entry/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
/node_modules
/oh_modules
/.preview
/build
/.cxx
/.test

View File

@ -0,0 +1,31 @@
{
"apiType": "stageMode",
"buildOption": {
"arkOptions": {
// "apPath": "./modules.ap" /* Profile used for profile-guided optimization (PGO), a compiler optimization technique to improve app runtime performance. */
}
},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": true,
"files": [
"./obfuscation-rules.txt"
]
}
}
}
},
],
"targets": [
{
"name": "default"
},
{
"name": "ohosTest",
}
]
}

View File

@ -0,0 +1,6 @@
import { hapTasks } from '@ohos/hvigor-ohos-plugin';
export default {
system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
}

View File

@ -0,0 +1,18 @@
# Define project specific obfuscation rules here.
# You can include the obfuscation configuration files in the current module's build-profile.json5.
#
# For more details, see
# https://gitee.com/openharmony/arkcompiler_ets_frontend/blob/master/arkguard/README.md
# Obfuscation options:
# -disable-obfuscation: disable all obfuscations
# -enable-property-obfuscation: obfuscate the property names
# -enable-toplevel-obfuscation: obfuscate the names in the global scope
# -compact: remove unnecessary blank spaces and all line feeds
# -remove-log: remove all console.* statements
# -print-namecache: print the name cache that contains the mapping from the old names to new names
# -apply-namecache: reuse the given cache file
# Keep options:
# -keep-property-name: specifies property names that you want to keep
# -keep-global-name: specifies names that you want to keep in the global scope

View File

@ -0,0 +1,10 @@
{
"license": "",
"devDependencies": {},
"author": "",
"name": "entry",
"description": "Please describe the basic information.",
"main": "",
"version": "1.0.0",
"dependencies": {}
}

View File

@ -0,0 +1,29 @@
@Observed
export class basicFuncInfo{
/**
* 函数名
*/
private funcName:string
/**
* 函数体
*/
private funcBody:string
constructor(funcName: string, funcBody: string) {
this.funcName = funcName
this.funcBody = funcBody
}
setFuncName(name:string){
this.funcName = name
}
setFuncBody(body:string){
this.funcBody = body
}
getFuncName(){
return this.funcName
}
getFuncBody(){
return this.funcBody
}
}

View File

@ -0,0 +1,27 @@
export class VALUE{
/**
* 栏颜色
*/
static readonly COLOR_BAR = "#EDEDED"
/**
* 字体大小(大)
*/
static readonly BIG_SIZE_FONT = 15
/**
* 字体大小(大)
*/
static readonly MIDDLE_SIZE_FONT = 12
/**
* 字体大小(小)
*/
static readonly SMALL_SIZE_FONT = 10
/**
* controlBar的背景色
*/
static readonly COLOR_COMP_CONTROLBAR_BG = "#9490D9"
/**
* controlBar的栏颜色
*/
static readonly COLOR_COMP_CONTROLBAR_BAR = "#8767F7"
}

View File

@ -0,0 +1,67 @@
import { basicFuncInfo } from '../common/BasicFuncInfo'
import { VALUE } from '../common/CommonValue'
@Component
export struct basicFunctionsBar {
@Consume('basicFuncList') basicFuncList:Array<basicFuncInfo>
build() {
Column(){
Text("可识别基本函数")
.fontSize(VALUE.BIG_SIZE_FONT)
.fontColor(Color.Red)
.fontWeight(FontWeight.Bold)
Row(){
Row(){
Text('函数名')
.fontSize(VALUE.SMALL_SIZE_FONT)
}.justifyContent(FlexAlign.Center).width('28%')
Blank()
Row(){
Text('函数体')
.fontSize(VALUE.SMALL_SIZE_FONT)
}.justifyContent(FlexAlign.Center).width('68%')
}.width('100%').padding({left:5,right:5})
List(){
ForEach(this.basicFuncList,(item:basicFuncInfo)=>{
ListItem(){
basicFuncItem({basicFunc:item})
}
})
}.layoutWeight(1).width('100%')
}.width('100%').height('100%')
}
}
@Component
struct basicFuncItem {
@ObjectLink basicFunc:basicFuncInfo
build() {
Row(){
Scroll(){
Row(){
Text(this.basicFunc.getFuncName())
.fontSize(VALUE.MIDDLE_SIZE_FONT)
}.justifyContent(FlexAlign.Center)
}.width('28%').scrollable(ScrollDirection.Horizontal).scrollBar(BarState.Off)
Blank()
Scroll(){
Row(){
Text(this.basicFunc.getFuncBody())
.fontSize(VALUE.MIDDLE_SIZE_FONT)
}.justifyContent(FlexAlign.Center)
}.width('68%').scrollable(ScrollDirection.Horizontal).scrollBar(BarState.Off)
}.width('100%').height(25)
}
}

View File

@ -0,0 +1,317 @@
import promptAction from '@ohos.promptAction'
import { basicFuncInfo } from '../common/BasicFuncInfo'
import { VALUE } from '../common/CommonValue'
import { IBoardOption, BoardType, Dimension, Quadrant } from '../utils/drawBoard/BoardType'
import { FuncType } from '../utils/drawBoard/drawPoint'
import { handle } from '../utils/handleFunc/processFunc'
@Component
export struct controlBar {
@Link inputFuncBody:string
@Link outputState:boolean
@Link boardOption:IBoardOption
build() {
Column({space:5}){
InputFunc({funcBody:$inputFuncBody,outputState:$outputState})
InputPara({boardOption:$boardOption})
}.width('100%').height('100%').backgroundColor(VALUE.COLOR_COMP_CONTROLBAR_BG).padding({top:5,bottom:5})
}
}
@Component
struct InputFunc {
@Consume isFuncChange:boolean
@Link funcBody:string
@Link outputState:boolean
@Consume('basicFuncList') basicFuncList:Array<basicFuncInfo>
@Consume dimension:Dimension
build() {
Row({space:10}){
Text('')
.width(15)
.height(30)
Stack(){
Rect().width('100%').height('100%').fill(Color.White)
TextInput({text:this.funcBody}).width('100%').height('100%').backgroundColor(Color.White).fontColor(Color.Black).fontSize(VALUE.SMALL_SIZE_FONT)
.onChange((value)=>{
this.funcBody = value
this.isFuncChange = true
})
}.height(30).backgroundColor(Color.White).layoutWeight(1)
Button('用户命名并新增基本函数')
.height(30)
.backgroundColor(Color.Yellow)
.fontColor(Color.Black)
.fontSize(VALUE.BIG_SIZE_FONT)
.width(210)
.type(ButtonType.Normal)
.onClick(()=>{
if(handle.isValidFunc(this.funcBody)) {
handle.separateFunc(this.funcBody);
let funcName = handle.funcHead;
let funcBody = handle.funcBody;
if (funcName && handle.getFuncType(this.dimension) != FuncType.NONE) {
let info: basicFuncInfo = new basicFuncInfo(funcName, funcBody)
this.basicFuncList.push(info)
}
else {
promptAction.showToast({
message: "不支持此函数类型或未为函数命名",
duration: 1500,
bottom: 20
})
}
}
})
Button('输出')
.height(30)
.backgroundColor(Color.Pink)
.fontColor(Color.Black)
.fontSize(VALUE.BIG_SIZE_FONT)
.width(70)
.type(ButtonType.Normal)
.onClick(()=>{
for (let i: number = 0; i < this.basicFuncList.length; i++) {
let standard: RegExp = new RegExp(`(^|[^a-zA-Z])${this.basicFuncList[i].getFuncName().replace('(', '\\(').replace(')', '\\)')}($|[^a-zA-Z])`);
if (standard.test(this.funcBody)) {
let index: number = this.funcBody.indexOf(this.basicFuncList[i].getFuncName());
let length: number = this.basicFuncList[i].getFuncName().length;
this.funcBody = this.funcBody.substring(0, index) + "(" + this.basicFuncList[i].getFuncBody() + ")" + this.funcBody.substring(index + length);
break;
}
}
if (handle.isValidFunc(this.funcBody)) {
if (this.dimension == Dimension.TWO) {
handle.getPoints2D();
} else {
handle.getPoints3D();
for (let i = 0; i < handle.coPot.length; i++) {
console.log(`(${handle.coPot[i].x}, ${handle.coPot[i].y}, ${handle.coPot[i].z})`);
}
}
this.outputState = !this.outputState;
}
})
}.width('100%').padding({left:10,right:10})
}
}
@Component
struct InputPara {
@Link boardOption:IBoardOption
@Consume isFuncChange:boolean
@Consume quadrant:Quadrant
@Consume dimension:Dimension
@Builder xStep(){
Row(){
Text('x步长')
.fontSize(VALUE.SMALL_SIZE_FONT)
Stack(){
Rect().width('100%').height('100%').fill(Color.White)
TextInput().width('100%').height('100%').backgroundColor(Color.White).fontColor(Color.Black).fontSize(VALUE.SMALL_SIZE_FONT)
.onChange((value)=>{
if(this.dimension == Dimension.THREE && Number(value) < 1){
WARNING("输入的x步长过小x步长最小为1")
return
}
this.boardOption.xStep = Number(value)
handle.xStep = this.boardOption.xStep;
})
}.height(30).backgroundColor(Color.White).layoutWeight(1)
}.width('100%').layoutWeight(0.5)
}
@Builder xNumber(){
Row(){
Text('x个数')
.fontSize(VALUE.SMALL_SIZE_FONT)
Stack(){
Rect().width('100%').height('100%').fill(Color.White)
TextInput().width('100%').height('100%').backgroundColor(Color.White).fontColor(Color.Black).fontSize(VALUE.SMALL_SIZE_FONT)
.onChange((value)=>{
this.boardOption.xNumber = Number(value)
handle.xCount = this.boardOption.xNumber;
})
}.height(30).backgroundColor(Color.White).layoutWeight(1)
}.width('100%').layoutWeight(0.5)
}
@Builder yStep(){
Row(){
Text('y步长')
.fontSize(VALUE.SMALL_SIZE_FONT)
Stack(){
Rect().width('100%').height('100%').fill(Color.White)
TextInput({text:this.boardOption.yStep.toString()}).width('100%').height('100%').backgroundColor(Color.White).fontColor(Color.Black).fontSize(VALUE.SMALL_SIZE_FONT)
.onChange((value)=>{
this.boardOption.yStep = Number(value)
handle.yStep = this.boardOption.yStep;
})
}.height(30).backgroundColor(Color.White).layoutWeight(1)
}.width('100%').layoutWeight(0.5)
}
@Builder quadrantSwitch(quadrant:Quadrant){
Row(){
Radio({value:quadrant.toString(),group:"Quadrant"})
.checked(this.quadrant == quadrant)
.onClick(()=>{
this.quadrant = quadrant
this.isFuncChange = true
if(quadrant == Quadrant.FOUR){
handle.setEdge(-10, 10);
}else{
handle.setEdge(0, 20);
}
handle.updateEdge(this.boardOption.xAmplification);
})
Text(quadrant == Quadrant.ONE?"一象限":"四象限")
.fontSize(VALUE.SMALL_SIZE_FONT)
}.width('100%').height('50%').alignItems(VerticalAlign.Center).justifyContent(FlexAlign.Center)
}
@Builder dimensionSwitch(dimension:Dimension){
Row(){
Radio({value:dimension.toString(),group:"TwoDimensional"})
.checked(this.dimension == dimension)
.onClick(()=>{
this.boardOption = {
xStep:0.1,
xNumber:0,//
yStep:1,
yNumber:0,
xAmplification:1,
yAmplification:1,
zAmplification:1
}
this.dimension = dimension
this.quadrant = Quadrant.FOUR
this.isFuncChange = true
if(dimension == Dimension.TWO){
handle.setEdge(-10, 10);
handle.updateEdge(this.boardOption.xAmplification);
}else{
handle.setEdge(-5, 5, 10);
handle.updateEdge(this.boardOption.xAmplification, this.boardOption.yAmplification)
}
})
Text(dimension == Dimension.TWO?"二维":"三维")
.fontSize(VALUE.SMALL_SIZE_FONT)
}.width('100%').height('50%').alignItems(VerticalAlign.Center).justifyContent(FlexAlign.Center)
}
@Builder xAmplification(){
Row(){
Text('x放大倍数')
.fontSize(VALUE.SMALL_SIZE_FONT)
Stack(){
Rect().width('100%').height('100%').fill(Color.White)
TextInput({text:this.boardOption.xAmplification.toString()}).width('100%').height('100%').backgroundColor(Color.White).fontColor(Color.Black).fontSize(VALUE.SMALL_SIZE_FONT)
.onChange((value)=>{
this.boardOption.xAmplification = Number(value)
handle.updateEdge(this.boardOption.xAmplification);
})
}.height(30).backgroundColor(Color.White).layoutWeight(1)
}.width('100%').layoutWeight(0.5)
}
@Builder yAmplification(){
Row(){
Text('y放大倍数')
.fontSize(VALUE.SMALL_SIZE_FONT)
Stack(){
Rect().width('100%').height('100%').fill(Color.White)
TextInput({text:this.boardOption.yAmplification.toString()}).width('100%').height('100%').backgroundColor(Color.White).fontColor(Color.Black).fontSize(VALUE.SMALL_SIZE_FONT)
.onChange((value)=>{
this.boardOption.yAmplification = Number(value)
})
}.height(30).backgroundColor(Color.White).layoutWeight(1)
}.width('100%').layoutWeight(0.5)
}
@Builder zAmplification(){
Row(){
Text('z放大倍数')
.fontSize(VALUE.SMALL_SIZE_FONT)
Stack(){
TextInput({text:this.boardOption.zAmplification.toString()}).width('100%').height('100%').backgroundColor(Color.White).fontColor(Color.Black).fontSize(VALUE.SMALL_SIZE_FONT)
.onChange((value)=>{
this.boardOption.zAmplification = Number(value)
})
.fontSize(10)
}.height(30).backgroundColor(Color.White).layoutWeight(1)
}.width('100%')
}
build() {
Row({space:10}){
Column({space:5}){
this.xStep()
Blank()
if (this.dimension == Dimension.TWO){
this.xNumber()
}else{
this.yStep()
}
}.width('24%').height('100%').backgroundColor(VALUE.COLOR_COMP_CONTROLBAR_BAR)
if(this.dimension == Dimension.TWO){
Row(){
Column(){
Text("坐标轴")
.fontSize(VALUE.BIG_SIZE_FONT)
}.height('100%').justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center).width('40%')
Column(){
this.quadrantSwitch(Quadrant.FOUR)
this.quadrantSwitch(Quadrant.ONE)
}.height('100%').width('60%')
}.width('22%').height('100%').backgroundColor(VALUE.COLOR_COMP_CONTROLBAR_BAR)
}else{
Column(){
this.xAmplification()
Blank()
this.yAmplification()
}.width('22%').height('100%').backgroundColor(VALUE.COLOR_COMP_CONTROLBAR_BAR)
}
Row(){
Column(){
Text("维度")
.fontSize(VALUE.BIG_SIZE_FONT)
}.height('100%').justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center).width('40%')
Column(){
this.dimensionSwitch(Dimension.TWO)
this.dimensionSwitch(Dimension.THREE)
}.height('100%').width('60%')
}.width('22%').height('100%').backgroundColor(VALUE.COLOR_COMP_CONTROLBAR_BAR)
Column({space:5}){
if(this.dimension == Dimension.TWO){
this.xAmplification()
Blank()
this.yAmplification()
}else{
this.zAmplification()
}
}.width('28%').height('100%').backgroundColor(VALUE.COLOR_COMP_CONTROLBAR_BAR)
}.width('100%').layoutWeight(1).padding({left:10,right:10})
}
}
let WARNING = (message:string,duration?:number)=>{
promptAction.showToast({
message:message,
duration:duration??2000
})
}

View File

@ -0,0 +1,37 @@
import { handle } from '../utils/handleFunc/processFunc'
@Component
export struct functionParsingDiagram {
@Link @Watch('initNodeTree') outputState: boolean
@Link func: string
@State nodeTree: Array<Array<string>> = []
initNodeTree() {
this.nodeTree = handle.createNodeTree(this.func);
}
build() {
Column(){
if (this.nodeTree) {
ForEach(this.nodeTree, (item: string[]) => {
Row() {
ForEach(item, (node: string) => {
Scroll() {
Text(node)
.textAlign(TextAlign.Center)
.fontSize(12)
}
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)
.layoutWeight(node.length < 8 ? 1 : 2)
.borderWidth(1)
.borderColor(Color.Black)
.margin(1)
})
}
.size({ width: "100%", height: 25 })
})
}
}.justifyContent(FlexAlign.Start).alignItems(HorizontalAlign.Center).width('100%').height('100%').padding(5)
}
}

View File

@ -0,0 +1,25 @@
import { AREA_CONTEXT, BoardInfo, CONTEXT, Dimension, } from '../utils/drawBoard/BoardType'
@Component
export struct imageShow {
@Prop board:BoardInfo
@Prop loop1:string
@Prop loop2:string
build() {
Stack(){
Canvas(CONTEXT).width("100%").height(this.loop2)
.onReady(()=>{
this.board.drawAxis()
if (this.board.dimension == Dimension.TWO) {
this.board.drawGraph()
}
})
Canvas(AREA_CONTEXT).width("100%").height(this.loop1)
.onReady(()=>{
if (this.board.dimension == Dimension.THREE) {
this.board.drawGraph()
}
})
}.width('100%').height('100%')
}
}

View File

@ -0,0 +1,44 @@
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import hilog from '@ohos.hilog';
import UIAbility from '@ohos.app.ability.UIAbility';
import Want from '@ohos.app.ability.Want';
import window from '@ohos.window';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
}
onDestroy(): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage): void {
// Main window is created, set main page for this ability
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
windowStage.loadContent('pages/Index', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
});
}
onWindowStageDestroy(): void {
// Main window is destroyed, release UI related resources
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
}
onForeground(): void {
// Ability has brought to foreground
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
}
onBackground(): void {
// Ability has back to background
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
}
}

View File

@ -0,0 +1,187 @@
import { basicFuncInfo } from '../common/BasicFuncInfo';
import { basicFunctionsBar } from '../component/BasicFunctionsBar';
import { controlBar } from '../component/ControlBar';
import { functionParsingDiagram } from '../component/FunctionParsingDiagram';
import { imageShow } from '../component/ImageShow';
import { B1Q2D, B4Q2D, B4Q3D, BoardInfo, IBoardOption, Dimension, Quadrant } from '../utils/drawBoard/BoardType';
import { FuncType, IVirtualPoints, PointType } from '../utils/drawBoard/drawPoint';
import { handle } from '../utils/handleFunc/processFunc'
@Entry
@Component
struct Index {
@Provide('basicFuncList') basicFuncList:Array<basicFuncInfo> = []
//输入的函数
@State inputFunction:string = ""
//是否把输入的函数输出成图像
@State @Watch('initBoard')outputState:boolean = false
//函数是否更改
@Provide isFuncChange:boolean = false
@State loop1:string = '100%'
@State loop2:string = '100%'
//board
@State board:BoardInfo|null = null
@Provide quadrant:Quadrant = Quadrant.FOUR
@Provide dimension:Dimension = Dimension.TWO
//boardOption
//默认的option
@State boardOption:IBoardOption = {
xStep:0.1,
xNumber:0,//
yStep:1,
yNumber:0,
xAmplification:1,
yAmplification:1,
zAmplification:1
}
aboutToAppear() {
handle.setEdge(-10, 10);
handle.updateEdge(this.boardOption.xAmplification);
}
/**
* 初始化board
*/
initBoard(){
this.createBoard()
//二维测试样例
//三维测试样例
// 1.YC y=3
// point.points.push({y:3,pointType:PointType.CONTINUE})
// point.funcType = FuncType.YC
//2.XC x=3
// point.points.push({x:3,pointType:PointType.CONTINUE})
// point.funcType = FuncType.XC
//3.ZC z=3
// point.points.push({z:3,pointType:PointType.CONTINUE})
// point.funcType = FuncType.ZC
//4.YX y=x^2 [-5,5]
// let c=-5
// while(c <= 5){
// point.points.push({x:c,y:-c*c,pointType:PointType.CONTINUE})
// c+=0.1;
// }
// point.funcType = FuncType.YX
//5.YX x=y^2
// let c = -5
// while(c <= 5){
// point.points.push({x:-c*c,y:c,pointType:PointType.CONTINUE})
// c+=1;
// }
// point.funcType = FuncType.YX
//6.ZX z=x^2
// let c=-5
// while(c <= 5){
// point.points.push({x:c,z:c*c,pointType:PointType.CONTINUE})
// c+=1;
// }
// point.funcType = FuncType.ZX
//6.ZY z=y^2
// let c=-5
// while(c <= 5){
// point.points.push({y:c,z:c*c,pointType:PointType.CONTINUE})
// c+=1;
// }
// point.funcType = FuncType.ZY
//7.ZXY z= x^2 + y^2 需要先调整步长 否则报错
// let dx = -3
// let dy = -3
// for(let index = 0;index < 6;index++){//this.boardOption.xNumber
// for (let index = 0; index < 6; index++) {//this.boardOption.yNumber
// point.points.push({x:dx,y:dy,z:-(dx*dx + dy*dy),pointType:PointType.CONTINUE})
// dy+=1
// }
// dx+=1;
// dy=-3
// }
// point.funcType = FuncType.ZXY
// //获取到点集
let point:IVirtualPoints = {
points: handle.coPot,
funcType: handle.getFuncType(this.dimension)
}
console.log('testTag','points_len:',point.points.length)
console.log('testTag','points_funcType:',point.funcType)
//初始化画板下的需要绘制的坐标点
if(this.isFuncChange){
if(this.board != null){
this.boardOption = this.board.initMap(point)
}
this.isFuncChange = false
}else{
if (this.board != null) {
this.board.setOption(this.boardOption,point)
}
}
//刷新canvas组件
if(this.loop1 == '100%'){
this.loop1 = '101%'
}else{
this.loop1 = '100%'
}
if(this.loop2 == '100%'){
this.loop2 = '101%'
}else{
this.loop2 = '100%'
}
}
build() {
Column(){
Row(){
if(this.board != null){
imageShow({loop1:this.loop1,loop2:this.loop2,board:this.board})
.width('50%')
.height('100%')
.backgroundColor('#F5F5F5')
}else{
Text('')
.width('50%')
.height('100%')
.backgroundColor('#F5F5F5')
}
functionParsingDiagram({ outputState: this.outputState, func: this.inputFunction })
.width('25%')
.height('100%')
.backgroundColor('#F5F5F5')
basicFunctionsBar()
.width('25%')
.height('100%')
.backgroundColor(Color.Pink)
}.width('100%').layoutWeight(1)
controlBar({inputFuncBody:$inputFunction,outputState:$outputState,boardOption:$boardOption}).width('100%').height('30%')
}.width('100%').height('100%')
}
/**
* 创建board
*/
createBoard(){
if (this.dimension == Dimension.TWO){
if(this.quadrant == Quadrant.ONE){
B1Q2D.setOption(this.boardOption)
this.board = B1Q2D
}
if(this.quadrant == Quadrant.FOUR){
B4Q2D.setOption(this.boardOption)
this.board = B4Q2D
}
}
if(this.dimension == Dimension.THREE){
B4Q3D.setOption(this.boardOption)
this.board = B4Q3D
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,79 @@
export enum PointType{
DISCONTINUE = 0,
CONTINUE = 1,
}
export enum FuncType{
/**
* 未选择
*/
NONE = -1,
/**
* y = c型
* 为此枚举值时 只能填y的值且其为c的值 且虚拟点集长度为1 pointType字段必为CONTINUE
*/
YC = 0,
/**
* x = c型
* 为此枚举值时 只能填x的值且其为c的值 且虚拟点集长度为1 pointType字段必为CONTINUE
*/
XC = 1,
/*
* y = f(x)型
* 为此枚举值时 虚拟点集中只能填xy的值
*/
YX = 2,
/**
* z = c型
* 为此枚举值时 只能填z的值且其为c的值 且虚拟点集长度为1 pointType字段必为CONTINUE
*/
ZC = 3,
/**
* z = f(x)型
* 为此枚举值时 虚拟点集中只能填zx的值
*/
ZX = 4,
/**
* z = f(y)型
* 为此枚举值时 虚拟点集中只能填zy的值
*/
ZY = 5,
/**
* z = f(x,y)型
* 为此枚举值时 虚拟点集中只能填zxy的值
* 且必须为边界值
*
*/
ZXY = 6
}
/**
* 虚拟点集
* 根据函数关系和步长、个数直接得到的点集
*/
export interface IPoint{
x?:number
y?:number
z?:number
pointType:PointType
}
export interface IVirtualPoints{
points:Array<IPoint>
funcType:FuncType
}
/**
* 画板点集
* 以屏幕左上角为原点的平面坐标系下的点集
*/
export interface IBoardPoint{
x:number
y:number
pointType:PointType
}

View File

@ -0,0 +1,361 @@
interface replaceableVar {
char: string,
value: number
}
class MathExpressionParser {
private tokens: string[];
private currentTokenIndex: number;
private variables: replaceableVar[];
private nodeTree: string[][];
private exp: string;
private currentExpIndex: number;
private layer: number;
constructor() {
this.tokens = []
this.currentTokenIndex = 0
this.variables = []
// this.nodeTree = new Array(50).fill([])
this.nodeTree = [];
for (let i = 0; i < 50; i++) {
this.nodeTree.push([]);
}
this.exp = ""
this.currentExpIndex = 0
this.layer = 0
}
private tokenize(expression: string): string[] {
const regex: RegExp = new RegExp("(\\d+\\.?\\d*|\\.\\d+|[a-zA-Z]+|\\S)", "g");
const originalTokens = expression.match(regex) || [];
const Tokens: string[] = [];
for (let i = 0; i < originalTokens.length; i++) {
Tokens.push(originalTokens[i]);
if (i < originalTokens.length - 1) {
const currentToken = originalTokens[i];
const nextToken = originalTokens[i + 1];
if ((this.isNumber(currentToken) && this.isVariable(nextToken)) ||
(this.isVariable(currentToken) && this.isVariable(nextToken)) ||
(currentToken === ')' && (this.isVariable(nextToken) || this.isNumber(nextToken))) ||
(this.isNumber(currentToken) && nextToken === '(') ||
(this.isVariable(currentToken) && nextToken === '(')) {
Tokens.push('*');
}
}
}
return Tokens;
}
private existInArr(token: string): number {
for (let i: number = 0; i < this.variables.length; i++) {
if (this.variables[i].char == token) {
return i;
}
}
return -1;
}
private isNumber(token: string): boolean {
const num = Number(token);
return !Number.isNaN(num) && Number.isFinite(num);
}
private isVariable(token: string): boolean {
const temp: RegExp = new RegExp("^[a-zA-Z]+$")
return temp.test(token) && !this.isFunction(token) && token !== "π";
}
private isFunction(token: string): boolean {
return ['pow', 'sin', 'cos', 'tan', 'ln', 'sqrt', 'log2', 'log10'].includes(token);
}
private getCurrentToken(): string {
return this.tokens[this.currentTokenIndex];
}
private getNextToken(): string {
this.currentTokenIndex++;
return this.getCurrentToken();
}
private parsePrimaryExpression(): number {
const token = this.getCurrentToken();
if (token === '(') {
this.getNextToken(); // consume '('
const result = this.parseExpression();
if (this.getCurrentToken() !== ')') {
throw new Error("Expected ')' after expression");
}
this.getNextToken(); // consume ')'
return result;
} else if (token === 'π') {
this.getNextToken(); // consume 'π'
return Math.PI;
} else if (this.isVariable(token)) {
if (this.existInArr(token) != -1) {
const value = this.variables[this.existInArr(token)].value;
this.getNextToken(); // consume variable
return value;
} else {
throw new Error(`Unknown variable: ${token}`);
}
} else if (this.isFunction(token)) {
return this.parseFunction();
} else {
const num = Number(token);
this.getNextToken(); // consume number
return num;
}
}
private parseFunction(): number {
const functionName = this.getCurrentToken();
this.getNextToken(); // consume function name
if (this.getCurrentToken() !== '(') {
throw new Error(`Expected '(' after function name ${functionName}`);
}
this.getNextToken(); // consume '('
const argument1 = this.parseExpression();
if (functionName === 'pow') {
if (this.getCurrentToken() !== ',') {
throw new Error(`Expected ',' between arguments for function ${functionName}`);
}
this.getNextToken(); // consume ','
const argument2 = this.parseExpression();
if (this.getCurrentToken() !== ')') {
throw new Error(`Expected ')' after arguments for function ${functionName}`);
}
this.getNextToken(); // consume ')'
return Math.pow(argument1, argument2);
}
if (this.getCurrentToken() !== ')') {
throw new Error(`Expected ')' after argument for function ${functionName}`);
}
this.getNextToken(); // consume ')'
switch (functionName) {
case 'sin':
return Math.sin(argument1);
case 'cos':
return Math.cos(argument1);
case 'tan':
return Math.tan(argument1);
case 'ln':
return Math.log(argument1);
case 'sqrt':
return Math.sqrt(argument1);
case 'log2':
return Math.log2(argument1);
case 'log10':
return Math.log10(argument1);
default:
throw new Error(`Unknown function: ${functionName}`);
}
}
private parseFactor(): number {
// 处理一元负号
if (this.getCurrentToken() === '-') {
this.getNextToken(); // consume '-'
return -this.parseFactor();
}
// 处理初级表达式
let result = this.parsePrimaryExpression();
// 处理乘法和除法
while (this.getCurrentToken() === '*' || this.getCurrentToken() === '/') {
const operator = this.getCurrentToken();
this.getNextToken(); // consume operator
const operand = this.parsePrimaryExpression();
if (operator === '*') {
result *= operand;
} else if (operator === '/') {
if (operand === 0) {
throw new Error("Division by zero");
}
result /= operand;
}
}
return result;
}
private parseExpression(): number {
let result = this.parseFactor();
while (this.getCurrentToken() === '+' || this.getCurrentToken() === '-') {
const operator = this.getCurrentToken();
this.getNextToken();
const operand = this.parseFactor();
if (operator === '+') {
result += operand;
} else if (operator === '-') {
result -= operand;
}
}
return result;
}
public evaluate(expression: string, variables: replaceableVar[] = []): number {
this.tokens = this.tokenize(expression);
this.currentTokenIndex = 0;
this.variables = variables;
const result = this.parseExpression();
if (this.currentTokenIndex !== this.tokens.length) {
console.log("Token" + this.tokens);
console.log("当前index" + this.currentTokenIndex + " " + "当前length" + this.tokens.length);
throw new Error("Unexpected token");
}
return Number(result.toFixed(4));
}
private getCurrentChar(): string {
return this.exp[this.currentExpIndex];
}
private getNextChar(): string {
this.currentExpIndex++;
return this.getCurrentChar();
}
private recursivePartitioning(expression: string) {
this.exp = "";
this.tokens = [];
this.tokens = this.tokenize(expression);
for (let i = 0; i < this.tokens.length; i++) {
this.exp += this.tokens[i];
}
console.log(this.exp + "----" + this.layer)
let temp: RegExp = new RegExp("^\\-?[a-zA-Z0-9]+$");
if (temp.test(this.exp)) return;
this.currentExpIndex = 0;
let parenthesizedForms: Array<string> = [];
let leftIndex: number = 0;
let rightIndex: number = 0;
let char: string = "$";
while (this.currentExpIndex < this.exp.length) {
if (this.getCurrentChar() == '(') {
parenthesizedForms.push("");
let count: number = parenthesizedForms.length - 1;
let leftCount: number = 1;
let rightCount: number = 0;
this.getNextChar();
leftIndex = this.currentExpIndex;
let sign: number = 0;
while (true) {
if (this.getCurrentChar() == '(') leftCount++;
if (this.getCurrentChar() == ')') rightCount++;
if (leftCount == rightCount) {
rightIndex = this.currentExpIndex;
break;
}
parenthesizedForms[count] += this.getCurrentChar();
this.getNextChar();
sign++;
if (sign > 1000) {
console.log("leftCount: " + leftCount + " " + "rightCount: " + rightCount);
this.exp = "";
this.tokens = [];
this.nodeTree = [];
this.layer = 0;
this.currentExpIndex = 0;
throw new Error("The number of brackets does not match");
}
}
let repeatNum: number = parenthesizedForms[count].length - count.toString().length;
if (repeatNum >= 0) {
this.exp = this.exp.substring(0, leftIndex) + count.toString() + char.repeat(repeatNum) + this.exp.substring(rightIndex);
} else {
throw new Error("Functions with so many parentheses are not supported");
}
leftIndex = rightIndex = 0;
}
this.getNextChar();
}
let nail: number = this.nodeTree[this.layer].length;
let symbolParts: RegExpMatchArray | null = null;
let includesAS: RegExp = new RegExp("(?<=\\d|[a-zA-Z]|\\))[+-](?=\\d|[a-zA-Z]|\\()", "g");
let includesMD: RegExp = new RegExp("(?<=\\d|[a-zA-Z]|\\))[*/](?=\\d|[a-zA-Z]|\\()", "g");
let includesPow: RegExp = new RegExp("(?<=\\d|[a-zA-Z]|\\))(?:[*]{2}|[\\^])(?=\\d|[a-zA-Z]|\\()", "g");
if (includesAS.test(this.exp)) {
this.nodeTree[this.layer] = this.nodeTree[this.layer].concat(this.exp.split(includesAS));
symbolParts = this.exp.match(includesAS);
} else if (includesMD.test(this.exp)) {
this.nodeTree[this.layer] = this.nodeTree[this.layer].concat(this.exp.split(includesMD));
} else if (includesPow.test(this.exp)) {
this.nodeTree[this.layer] = this.nodeTree[this.layer].concat(this.exp.split(includesPow));
} else {
if (this.exp[0] != "(") {
let label = 0;
for (let i = 0; i < this.exp.length; i++) {
if (this.exp[i] == "(") {
label = i;
break;
}
}
this.exp = this.exp.substring(label);
}
this.nodeTree[this.layer].push(this.exp);
}
if (symbolParts) {
symbolParts.forEach((match, index) => {
if (match == "-") {
this.nodeTree[this.layer][index + 1] = "-".concat(this.nodeTree[this.layer][index + 1]);
}
})
}
// for (let i = nail; i < this.nodeTree[this.layer].length; i++) {
// console.log(this.nodeTree[this.layer][i]);
// }
// for (let i: number = 0; i < parenthesizedForms.length; i++) {
// console.log("需替换字符" + parenthesizedForms[i] + "" + i + " " + this.layer)
// }
for (let i = nail; i < this.nodeTree[this.layer].length; i++) {
for (let j = 0; j < this.nodeTree[this.layer][i].length; j++) {
if (this.nodeTree[this.layer][i][j] == "(") {
let standard: RegExp = new RegExp("(?<=\\d|[a-zA-Z]|\\))([+-]|[*/]|[*]{2}|[\\^])(?=\\d|[a-zA-Z]|\\()", "g");
let flag: Boolean = false;
if (j == 0 && !standard.test(this.nodeTree[this.layer][i])) {
flag = true;
}
let start = j + 1;
let storeIndex = Number(this.nodeTree[this.layer][i][start]);
this.nodeTree[this.layer][i] = this.nodeTree[this.layer][i].substring(0, start) + parenthesizedForms[storeIndex] + this.nodeTree[this.layer][i].substring(start + parenthesizedForms[storeIndex].length);
if (flag) this.nodeTree[this.layer][i] = this.nodeTree[this.layer][i].substring(1, this.nodeTree[this.layer][i].length - 1);
// break;
j += parenthesizedForms[storeIndex].length + 2;
}
}
}
// for (let i = nail; i < this.nodeTree[this.layer].length; i++) {
// console.log(this.layer + " " + this.nodeTree[this.layer][i]);
// }
for (let i = nail; i < this.nodeTree[this.layer].length; i++) {
this.layer++;
this.recursivePartitioning(this.nodeTree[this.layer - 1][i]);
this.layer--;
}
}
createNode(func: string) {
// this.nodeTree.length = 0;
// this.nodeTree = new Array(50).fill([]);
this.nodeTree = [];
for (let i = 0; i < 50; i++) {
this.nodeTree.push([]);
}
this.recursivePartitioning(func);
return this.nodeTree;
}
}
export let mathjs: MathExpressionParser = new MathExpressionParser();

View File

@ -0,0 +1,399 @@
import promptAction from '@ohos.promptAction';
import { BusinessError } from '@ohos.base';
import { mathjs } from '../handleFunc/analysis'
import { PointType, IPoint, FuncType } from '../drawBoard/drawPoint'
import { Dimension } from '../drawBoard/BoardType'
export class ProcessFunc {
private funcId: string; // 函数(用以查询坐标轴进而确定函数类型)
private funcText: string; // 函数体(经过一定符号转换处理,用以计算)
xMin: number; // x轴最小整数值
xMax: number; // y轴最大整数值
private yMin: number; // x轴最小整数值
private yMax: number; // y轴最大整数值
private xMinDefault: number;
private xMaxDefault: number;
private yMinDefault: number;
private yMaxDefault: number;
nodeTree: Array<Array<string>> // 节点树数组
coPot: Array<IPoint>; // 存储获取的坐标点
funcHead: string; // 存储函数头
funcBody: string; // 存储函数体
xCount: number; // 取x点个数
yCount: number; // 取y点个数
xStep: number; // x轴步长值决定每个点取点间隔
yStep: number; // y轴步长值决定每个点取点间隔
row: number; // 三维取点点集转为二维数组的行数
col: number; // 三维取点点集转为二维数组的列数
constructor() {
this.nodeTree = [];
this.coPot = [];
this.funcId = this.funcText = this.funcHead = this.funcBody = "";
this.xStep = this.yStep = 0.1;
this.xCount = this.yCount = 0;
this.xMin = this.xMax = this.yMin = this.yMax = 0;
this.xMinDefault = this.xMaxDefault = this.yMinDefault = this.yMaxDefault = 0;
this.row = this.col = 0;
}
/**
* 对promptAction.showToast()的封装。默认持续1.5s距离底部50vp
* @param message 弹窗提示的文本信息
*/
private showToast(message: string) {
try {
promptAction.showToast({
message: message,
duration: 1500,
bottom: 20
});
} catch (error) {
let message = (error as BusinessError).message
let code = (error as BusinessError).code
console.error(`showToast args error code is ${code}, message is ${message}`);
}
}
/**
* 初始化默认的坐标轴最大最小边界点
* @param xMin
* @param xMax
* @param yMin
* @param yMax
*/
setEdge(xMin: number, xMax: number, y?: number, ) {
this.xMinDefault = xMin;
this.xMaxDefault = xMax;
if (y) {
this.yMinDefault = -y;
this.yMaxDefault = y;
}
this.updateEdge(1);
}
/**
* 根据放大倍数更新边缘点
* @param xTimes
* @param yTimes
*/
updateEdge(xTimes: number, yTimes?: number) {
this.xMin = this.xMinDefault * xTimes;
this.xMax = this.xMaxDefault * xTimes;
if (yTimes) {
this.yMin = this.yMinDefault * yTimes;
this.yMax = this.yMaxDefault * yTimes;
}
}
/**
* 判断输入的数学表达式是否合法,能够运算则合法,抛出错误则不合法
* @param func 数学表达式
* @returns
*/
isValidFunc(func: string): boolean {
this.funcId = this.funcText = "";
let temp: RegExp = new RegExp("\\s+", "g");
func = func.trim().replace(temp, "");
// temp = new RegExp("(\\(([^()]+)\\)|\\w+)(?:\\*\\*|\\^)(\\(([^()]+)\\)|\\w+)", "g");
temp = new RegExp("(\\([^()]*?(?:\\([^()]*?\\)[^()]*?)*\\)|\\w+)(?:\\*\\*|\\^)(\\([^()]*?(?:\\([^()]*?\\)[^()]*?)*\\)|\\w+)", "g");
func = func.replace(temp, "pow($1, $2)");
if (func.includes("=") && func.split("=").length === 2) {
this.funcId = func.split("=")[0];
this.funcText = func.split("=")[1];
} else {
this.funcId = "";
this.funcText = func;
}
try {
let testX: number = 1;
let testY: number = 1;
let uselessRes: number = mathjs.evaluate(this.funcText, [{ char: "x", value: testX }, { char: "y", value: testY }]);
if (!Number.isNaN(uselessRes)) return true;
else return false;
} catch (err) {
console.log("错误的函数格式为:" + this.funcText)
this.showToast("函数错误!" + err);
return false;
}
}
/**
* 分离函数头和函数体
* @param func
*/
separateFunc(func: string) {
this.funcHead = this.funcBody = "";
let temp: RegExp = new RegExp("\\s+", "g");
func = func.trim().replace(temp, "");
if (func.includes("=") && func.split("=").length === 2) {
this.funcHead = func.split("=")[0];
this.funcBody = func.split("=")[1];
} else {
this.funcHead = "";
this.funcBody = func;
}
}
/**
* 获取函数类型
* @param dimension 当前的维度
* @returns
*/
getFuncType(dimension: Dimension): FuncType {
if (dimension === Dimension.TWO) {
if (!this.funcId) {
if (Number.isNaN(Number(this.funcText))) return FuncType.YX;
else this.showToast("请输入正确的函数格式");
}
if (this.funcId && this.funcId != "x") {
if (Number.isNaN(Number(this.funcText))) return FuncType.YX;
else return FuncType.YC;
}
else if (!Number.isNaN(Number(this.funcText))) return FuncType.XC;
else this.showToast("函数命名不可以与自变量同名!");
} else if (dimension === Dimension.THREE) {
let standard_x: RegExp = new RegExp("(^|[^a-zA-Z])x($|[^a-zA-Z])");
let standard_y: RegExp = new RegExp("(^|[^a-zA-Z])y($|[^a-zA-Z])");
if (!this.funcId) {
if (standard_x.test(this.funcText) && standard_y.test(this.funcText)) return FuncType.ZXY;
else if (standard_x.test(this.funcText) && !standard_y.test(this.funcText)) return FuncType.ZX;
else if (!standard_x.test(this.funcText) && standard_y.test(this.funcText)) return FuncType.ZY;
else this.showToast("请输入正确的函数格式");
}
if (this.funcId && this.funcId != "x" && this.funcId != "y") {
if (!Number.isNaN(Number(this.funcText))) return FuncType.ZC;
else if (standard_x.test(this.funcText) && standard_y.test(this.funcText)) return FuncType.ZXY;
else if (standard_x.test(this.funcText) && !standard_y.test(this.funcText)) return FuncType.ZX;
else if (!standard_x.test(this.funcText) && standard_y.test(this.funcText)) return FuncType.ZY;
}
else if (this.funcId == "x" && !Number.isNaN(Number(this.funcText))) return FuncType.XC;
else if (this.funcId == "y" && !Number.isNaN(Number(this.funcText))) return FuncType.YC;
else this.showToast("没有YX或XY类型函数||函数命名不可与自变量同名!");
}
return FuncType.NONE;
}
/**
* 判断当前点是否连续
* @param xValue 当前x值
* @param yValue 当前y值
* @param zValue 当前z值
* @param epsilon 模拟的逼近无限小值
* @param threshold 模拟的逼近无限大值
* @returns 返回一个布尔值true则表示此点连续false表示不连续
*/
private judgeContinue(xValue: number, yValue: number, zValue?: number, epsilon: number = 1e-10, threshold: number = 1e5): boolean {
if (Number.isNaN(yValue) || Number.isNaN(zValue)) {
return false;
}
let leftLimitX: number = 0;
let rightLimitX: number = 0;
let leftLimitY: number = 0;
let rightLimitY: number = 0;
let standard: RegExp = new RegExp("(^|[^a-zA-Z])y($|[^a-zA-Z])")
try {
if (!standard.test(this.funcText)) {
leftLimitX = mathjs.evaluate(this.funcText, [{ char: "x", value: xValue - epsilon }]);
rightLimitX = mathjs.evaluate(this.funcText, [{ char: "x", value: xValue + epsilon }]);
if (Math.abs(rightLimitX - leftLimitX) > 10 * epsilon) {
return false;
}
if (Math.abs(leftLimitX - yValue) > 10 * epsilon || Math.abs(rightLimitX - yValue) > 10 * epsilon) {
return false;
}
} else {
leftLimitX = mathjs.evaluate(this.funcText, [{ char: "x", value: xValue - epsilon }, { char: "y", value: yValue }]);
rightLimitX = mathjs.evaluate(this.funcText, [{ char: "x", value: xValue + epsilon }, { char: "y", value: yValue }]);
leftLimitX = mathjs.evaluate(this.funcText, [{ char: "x", value: xValue }, { char: "y", value: yValue - epsilon }]);
rightLimitX = mathjs.evaluate(this.funcText, [{ char: "x", value: xValue }, { char: "y", value: yValue + epsilon }]);
if (Math.abs(rightLimitX - leftLimitX) > 10 * epsilon && Math.abs(rightLimitY - leftLimitY) > 10 * epsilon) {
return false;
}
if ((Math.abs(leftLimitX - zValue!) > 10 * epsilon || Math.abs(rightLimitX - zValue!) > 10 * epsilon) && (Math.abs(leftLimitY - zValue!) > 10 * epsilon || Math.abs(rightLimitY - zValue!) > 10 * epsilon)) {
return false;
}
}
const isLeftInfinite: boolean = Math.abs(leftLimitX) > threshold || Math.abs(leftLimitY) > threshold;
const isRightInfinite: boolean = Math.abs(rightLimitX) > threshold || Math.abs(rightLimitY) > threshold;
if (isLeftInfinite || isRightInfinite) {
return false;
}
} catch {
this.showToast("判断是否为间断点时发生错误,默认此点非连续");
return false;
}
return true;
}
/**
* 一元函数获取点的方法封装
* @param independentVar 自变量
* @param dependentVar 因变量
* @param min 负轴坐标最大值
* @param max 正轴坐标最大值
* @param step 步长值
* @param count 个数
*/
private getPointsBasic(independentVar: string, dependentVar: string, min: number, max: number, step: number, count?: number) {
let _temp: number = Math.abs(max - min) / step;
if (_temp <= 10000) {
for (let argument: number = min; argument <= max && step > 0; argument += step) {
argument = Number(argument.toFixed(4));
let standard: RegExp = new RegExp(`(^|[^a-zA-Z])${independentVar}($|[^a-zA-Z])`)
let calculateRes: number = 0;
if (standard.test(this.funcText)) {
try {
calculateRes = mathjs.evaluate(this.funcText, [{ char: independentVar, value: argument }]);
} catch {
this.coPot.length = 0;
this.showToast("运算过程中出错");
return;
}
}
if (this.judgeContinue(argument, calculateRes)) {
// this.coPot.push({ [independentVar]: argument, [dependentVar]: calculateRes, pointType: PointType.CONTINUE });
this.coPot.push({ pointType: PointType.CONTINUE });
let index: number = this.coPot.length - 1;
if (independentVar == "x") this.coPot[index].x = argument;
else if (independentVar == "y") this.coPot[index].y = argument;
if (dependentVar == "y") this.coPot[index].y = calculateRes;
else if (dependentVar == "z") this.coPot[index].z = calculateRes;
} else {
// this.coPot.push({ [independentVar]: argument, pointType: PointType.DISCONTINUE })
this.coPot.push({ pointType: PointType.DISCONTINUE });
let index: number = this.coPot.length - 1;
if (independentVar == "x") this.coPot[index].x = argument;
else if (independentVar == "y") this.coPot[index].y = argument;
}
if (argument != max && argument + step > max) {
argument = max - step;
}
}
if (count && count > 0 && count < this.coPot.length) {
this.coPot = this.coPot.slice(0, count);
}
} else {
this.coPot.push({ x: 0, y: 0, pointType: PointType.CONTINUE });
this.coPot.length = 1;
this.showToast("请适当增大步长");
}
}
/**
* 获取用于绘制2维图像的各个坐标点
* @returns 返回坐标点信息数组
*/
getPoints2D(): IPoint[] {
this.coPot.length = 0;
if (this.getFuncType(Dimension.TWO) == FuncType.YX) {
this.getPointsBasic("x", "y", this.xMin, this.xMax, this.xStep, this.xCount);
} else if (this.getFuncType(Dimension.TWO) == FuncType.YC) {
this.coPot.push({ y: Number(this.funcText), pointType: PointType.CONTINUE })
} else if (this.getFuncType(Dimension.TWO) == FuncType.XC) {
this.coPot.push({ x: Number(this.funcText), pointType: PointType.CONTINUE })
}
return this.coPot;
}
/**
* 获取用于绘制3维图像的各个坐标点
* @returns 返回坐标点信息数组
*/
getPoints3D(): IPoint[] {
this.coPot.length = 0;
if (this.getFuncType(Dimension.THREE) == FuncType.ZXY) {
let _temp: number = (Math.abs(this.yMax - this.yMin) / this.yStep) * (Math.abs(this.xMax - this.xMin) / this.xStep);
if (_temp <= 10000) {
for (let x: number = this.xMin; x <= this.xMax && this.xStep > 0; x += this.xStep) {
for (let y: number = this.yMin; y <= this.yMax && this.yStep > 0; y += this.yStep) {
x = Number(x.toFixed(4));
y = Number(y.toFixed(4));
let standard: RegExp = new RegExp("(^|[^a-zA-Z])(?:x|y)($|[^a-zA-Z])")
let z: number = 0;
if (standard.test(this.funcText)) {
try {
z = mathjs.evaluate(this.funcText, [{ char: "x", value: x }, { char: "y", value: y }]);
} catch {
this.coPot.length = 0;
this.showToast("运算过程中出错");
return [];
}
}
if (this.judgeContinue(x, y)) {
this.coPot.push({ x: x, y: y, z: z, pointType: PointType.CONTINUE });
} else {
this.coPot.push({ x: x, y: y, pointType: PointType.DISCONTINUE })
}
if (y != this.yMax && y + this.yStep >= this.yMax) {
let temp: number = y + this.yStep + (-this.yMin);
this.col = Number((temp / this.yStep).toFixed(0)) + 1;
y = this.yMax - this.yStep;
}
}
if (x != this.xMax && x + this.xStep >= this.xMax) {
let temp: number = x + this.xStep + (-this.xMin);
this.row = Number((temp / this.xStep).toFixed(0)) + 1;
x = this.xMax - this.xStep;
}
}
} else {
this.coPot.push({ x: 0, y: 0, pointType: PointType.CONTINUE });
this.coPot.length = 1;
this.showToast("请适当增大步长");
}
// let row: number = Math.abs(this.xMax - this.xMin) / this.xStep;
// let col: number = Math.abs(this.yMax - this.yMin) / this.yStep;
// let temp: IPoint[] = [];
// if (this.xCount > 0 && this.yCount > 0 && this.xCount < row && this.yCount < col) {
// for (let i: number = 0; i < this.xCount * col; i += col) {
// temp = temp.concat(this.coPot.slice(i, i + this.yCount));
// }
// this.coPot = temp;
// } else if (this.xCount > 0 && this.xCount < row) {
// this.coPot = this.coPot.slice(0, this.xCount * col);
// } else if (this.yCount > 0 && this.xCount < col) {
// for (let i: number = 0; i < this.coPot.length; i += col) {
// temp = temp.concat(this.coPot.slice(i, i + this.yCount));
// }
// this.coPot = temp;
// }
} else if (this.getFuncType(Dimension.THREE) == FuncType.ZX) {
this.getPointsBasic("x", "z", this.xMin, this.xMax, this.xStep);
} else if (this.getFuncType(Dimension.THREE) == FuncType.ZY) {
this.getPointsBasic("y", "z", this.yMin, this.yMax, this.yStep);
} else if (this.getFuncType(Dimension.THREE) == FuncType.ZC) {
this.coPot.push({ z: Number(this.funcText), pointType: PointType.CONTINUE });
} else if (this.getFuncType(Dimension.THREE) == FuncType.XC) {
this.coPot.push({ x: Number(this.funcText), pointType: PointType.CONTINUE });
} else if (this.getFuncType(Dimension.THREE) == FuncType.YC) {
this.coPot.push({ y: Number(this.funcText), pointType: PointType.CONTINUE });
}
return this.coPot;
}
createNodeTree(func: string) {
this.separateFunc(func);
this.nodeTree = [];
if (this.isValidFunc(func)) {
let temp: RegExp = new RegExp("\\s+", "g");
let machiningFunc: string = this.funcBody;
machiningFunc = machiningFunc.trim().replace(temp, "");
this.nodeTree.push([machiningFunc]);
let leaf: Array<Array<string>> = mathjs.createNode(machiningFunc);
for (let i: number = 0; i < leaf.length; i++) {
if (leaf[i][0]) this.nodeTree.push([]);
else break;
for (let j: number = 0; j < leaf[i].length; j++) {
this.nodeTree[i + 1].push(leaf[i][j]);
}
}
}
return this.nodeTree;
}
}
export let handle: ProcessFunc = new ProcessFunc();

View File

@ -0,0 +1,44 @@
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"metadata": [
{
"name": "ArkTSPartialUpdate",
"value": "true"
}
],
"deviceTypes": [
"default",
"tablet"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"orientation": "landscape",
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
]
}
]
}
}

View File

@ -0,0 +1,8 @@
{
"color": [
{
"name": "start_window_background",
"value": "#FFFFFF"
}
]
}

View File

@ -0,0 +1,16 @@
{
"string": [
{
"name": "module_desc",
"value": "module description"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "label"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,5 @@
{
"src": [
"pages/Index"
]
}

View File

@ -0,0 +1,16 @@
{
"string": [
{
"name": "module_desc",
"value": "module description"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "label"
}
]
}

View File

@ -0,0 +1,16 @@
{
"string": [
{
"name": "module_desc",
"value": "模块描述"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "label"
}
]
}

View File

@ -0,0 +1,35 @@
import hilog from '@ohos.hilog';
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
export default function abilityTest() {
describe('ActsAbilityTest', () => {
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
beforeAll(() => {
// Presets an action, which is performed only once before all test cases of the test suite start.
// This API supports only one parameter: preset action function.
})
beforeEach(() => {
// Presets an action, which is performed before each unit test case starts.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: preset action function.
})
afterEach(() => {
// Presets a clear action, which is performed after each unit test case ends.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: clear action function.
})
afterAll(() => {
// Presets a clear action, which is performed after all test cases of the test suite end.
// This API supports only one parameter: clear action function.
})
it('assertContain', 0, () => {
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
let a = 'abc';
let b = 'b';
// Defines a variety of assertion methods, which are used to declare expected boolean conditions.
expect(a).assertContain(b);
expect(a).assertEqual(a);
})
})
}

View File

@ -0,0 +1,5 @@
import abilityTest from './Ability.test';
export default function testsuite() {
abilityTest();
}

View File

@ -0,0 +1,50 @@
import UIAbility from '@ohos.app.ability.UIAbility';
import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
import hilog from '@ohos.hilog';
import { Hypium } from '@ohos/hypium';
import testsuite from '../test/List.test';
import window from '@ohos.window';
import Want from '@ohos.app.ability.Want';
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
export default class TestAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onCreate');
hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? '');
hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? '');
let abilityDelegator: AbilityDelegatorRegistry.AbilityDelegator;
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
let abilityDelegatorArguments: AbilityDelegatorRegistry.AbilityDelegatorArgs;
abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments();
hilog.info(0x0000, 'testTag', '%{public}s', 'start run testcase!!!');
Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite);
}
onDestroy() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage) {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageCreate');
windowStage.loadContent('testability/pages/Index', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s',
JSON.stringify(data) ?? '');
});
}
onWindowStageDestroy() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageDestroy');
}
onForeground() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onForeground');
}
onBackground() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onBackground');
}
}

View File

@ -0,0 +1,17 @@
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
}
.width('100%')
}
.height('100%')
}
}

View File

@ -0,0 +1,47 @@
import hilog from '@ohos.hilog';
import TestRunner from '@ohos.application.testRunner';
import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
import Want from '@ohos.app.ability.Want';
let abilityDelegator: AbilityDelegatorRegistry.AbilityDelegator | undefined = undefined
let abilityDelegatorArguments: AbilityDelegatorRegistry.AbilityDelegatorArgs | undefined = undefined
async function onAbilityCreateCallback() {
hilog.info(0x0000, 'testTag', '%{public}s', 'onAbilityCreateCallback');
}
async function addAbilityMonitorCallback(err : Error) {
hilog.info(0x0000, 'testTag', 'addAbilityMonitorCallback : %{public}s', JSON.stringify(err) ?? '');
}
export default class OpenHarmonyTestRunner implements TestRunner {
constructor() {
}
onPrepare() {
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner OnPrepare ');
}
async onRun() {
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun run');
abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments()
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
const bundleName = abilityDelegatorArguments.bundleName;
const testAbilityName = 'TestAbility';
let lMonitor: AbilityDelegatorRegistry.AbilityMonitor = {
abilityName: testAbilityName,
onAbilityCreate: onAbilityCreateCallback,
};
abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback)
const want: Want = {
bundleName: bundleName,
abilityName: testAbilityName
};
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
abilityDelegator.startAbility(want, (err, data) => {
hilog.info(0x0000, 'testTag', 'startAbility : err : %{public}s', JSON.stringify(err) ?? '');
hilog.info(0x0000, 'testTag', 'startAbility : data : %{public}s',JSON.stringify(data) ?? '');
})
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun end');
}
}

View File

@ -0,0 +1,37 @@
{
"module": {
"name": "entry_test",
"type": "feature",
"description": "$string:module_test_desc",
"mainElement": "TestAbility",
"deviceTypes": [
"default",
"tablet"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:test_pages",
"abilities": [
{
"name": "TestAbility",
"srcEntry": "./ets/testability/TestAbility.ets",
"description": "$string:TestAbility_desc",
"icon": "$media:icon",
"label": "$string:TestAbility_label",
"exported": true,
"startWindowIcon": "$media:icon",
"startWindowBackground": "$color:start_window_background",
"skills": [
{
"actions": [
"action.system.home"
],
"entities": [
"entity.system.home"
]
}
]
}
]
}
}

View File

@ -0,0 +1,8 @@
{
"color": [
{
"name": "start_window_background",
"value": "#FFFFFF"
}
]
}

View File

@ -0,0 +1,16 @@
{
"string": [
{
"name": "module_test_desc",
"value": "test ability description"
},
{
"name": "TestAbility_desc",
"value": "the test ability"
},
{
"name": "TestAbility_label",
"value": "test label"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@ -0,0 +1,5 @@
{
"src": [
"testability/pages/Index"
]
}

View File

@ -0,0 +1,5 @@
import localUnitTest from './LocalUnit.test';
export default function testsuite() {
localUnitTest();
}

View File

@ -0,0 +1,33 @@
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
export default function localUnitTest() {
describe('localUnitTest',() => {
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
beforeAll(() => {
// Presets an action, which is performed only once before all test cases of the test suite start.
// This API supports only one parameter: preset action function.
});
beforeEach(() => {
// Presets an action, which is performed before each unit test case starts.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: preset action function.
});
afterEach(() => {
// Presets a clear action, which is performed after each unit test case ends.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: clear action function.
});
afterAll(() => {
// Presets a clear action, which is performed after all test cases of the test suite end.
// This API supports only one parameter: clear action function.
});
it('assertContain', 0, () => {
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
let a = 'abc';
let b = 'b';
// Defines a variety of assertion methods, which are used to declare expected boolean conditions.
expect(a).assertContain(b);
expect(a).assertEqual(a);
});
});
}

View File

@ -0,0 +1,18 @@
{
"hvigorVersion": "3.0.9",
"dependencies": {
"@ohos/hvigor-ohos-plugin": "3.0.9"
},
"execution": {
// "daemon": true, /* Enable daemon compilation. Default: true */
// "incremental": true, /* Enable incremental compilation. Default: true */
// "parallel": true, /* Enable parallel compilation. Default: true */
// "typeCheck": false, /* Enable typeCheck. Default: false */
},
"logging": {
// "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */
},
"debugging": {
// "stacktrace": false /* Disable stacktrace compilation. Default: false */
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,6 @@
import { appTasks } from '@ohos/hvigor-ohos-plugin';
export default {
system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
}

48
drawing/draw/hvigorw Normal file
View File

@ -0,0 +1,48 @@
#!/bin/bash
# ----------------------------------------------------------------------------
# Hvigor startup script, version 1.0.0
#
# Required ENV vars:
# ------------------
# NODE_HOME - location of a Node home dir
# or
# Add /usr/local/nodejs/bin to the PATH environment variable
# ----------------------------------------------------------------------------
HVIGOR_APP_HOME="`pwd -P`"
HVIGOR_WRAPPER_SCRIPT=${HVIGOR_APP_HOME}/hvigor/hvigor-wrapper.js
warn() {
echo ""
echo -e "\033[1;33m`date '+[%Y-%m-%d %H:%M:%S]'`$@\033[0m"
}
error() {
echo ""
echo -e "\033[1;31m`date '+[%Y-%m-%d %H:%M:%S]'`$@\033[0m"
}
fail() {
error "$@"
exit 1
}
# Determine node to start hvigor wrapper script
if [ -n "${NODE_HOME}" ];then
EXECUTABLE_NODE="${NODE_HOME}/bin/node"
if [ ! -x "$EXECUTABLE_NODE" ];then
fail "ERROR: NODE_HOME is set to an invalid directory,check $NODE_HOME\n\nPlease set NODE_HOME in your environment to the location where your nodejs installed"
fi
else
EXECUTABLE_NODE="node"
which ${EXECUTABLE_NODE} > /dev/null 2>&1 || fail "ERROR: NODE_HOME is not set and not 'node' command found in your path"
fi
# Check hvigor wrapper script
if [ ! -r "$HVIGOR_WRAPPER_SCRIPT" ];then
fail "ERROR: Couldn't find hvigor/hvigor-wrapper.js in ${HVIGOR_APP_HOME}"
fi
# start hvigor-wrapper script
exec "${EXECUTABLE_NODE}" \
"${HVIGOR_WRAPPER_SCRIPT}" "$@"

64
drawing/draw/hvigorw.bat Normal file
View File

@ -0,0 +1,64 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Hvigor startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
set WRAPPER_MODULE_PATH=%APP_HOME%\hvigor\hvigor-wrapper.js
set NODE_EXE=node.exe
goto start
:start
@rem Find node.exe
if defined NODE_HOME goto findNodeFromNodeHome
%NODE_EXE% --version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: NODE_HOME is not set and no 'node' command could be found in your PATH.
echo.
echo Please set the NODE_HOME variable in your environment to match the
echo location of your NodeJs installation.
goto fail
:findNodeFromNodeHome
set NODE_HOME=%NODE_HOME:"=%
set NODE_EXE_PATH=%NODE_HOME%/%NODE_EXE%
if exist "%NODE_EXE_PATH%" goto execute
echo.
echo ERROR: NODE_HOME is not set and no 'node' command could be found in your PATH.
echo.
echo Please set the NODE_HOME variable in your environment to match the
echo location of your NodeJs installation.
goto fail
:execute
@rem Execute hvigor
"%NODE_EXE%" "%WRAPPER_MODULE_PATH%" %*
if "%ERRORLEVEL%" == "0" goto hvigorwEnd
:fail
exit /b 1
:hvigorwEnd
if "%OS%" == "Windows_NT" endlocal
:end

View File

@ -0,0 +1,13 @@
{
"lockfileVersion": 1,
"ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
"specifiers": {
"@ohos/hypium@1.0.11": "@ohos/hypium@1.0.11"
},
"packages": {
"@ohos/hypium@1.0.11": {
"resolved": "https://repo.harmonyos.com/ohpm/@ohos/hypium/-/hypium-1.0.11.tgz",
"integrity": "sha512-KawcLnv43C3QIYv1UbDnKCFX3MohtDxGuFvzlUxT/qf2DBilR56Ws6zrj90LdH6PjloJQwOPESuBQIHBACAK7w=="
}
}
}

View File

@ -0,0 +1,12 @@
{
"license": "",
"devDependencies": {
"@ohos/hypium": "1.0.11"
},
"author": "",
"name": "myapplication",
"description": "Please describe the basic information.",
"main": "",
"version": "1.0.0",
"dependencies": {}
}

58
drawing/draw/package-lock.json generated Normal file
View File

@ -0,0 +1,58 @@
{
"name": "draw",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"dependencies": {
"echarts": "^5.5.0"
}
},
"node_modules/echarts": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/echarts/-/echarts-5.5.0.tgz",
"integrity": "sha512-rNYnNCzqDAPCr4m/fqyUFv7fD9qIsd50S6GDFgO1DxZhncCsNsG7IfUlAlvZe5oSEQxtsjnHiUuppzccry93Xw==",
"dependencies": {
"tslib": "2.3.0",
"zrender": "5.5.0"
}
},
"node_modules/tslib": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
},
"node_modules/zrender": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/zrender/-/zrender-5.5.0.tgz",
"integrity": "sha512-O3MilSi/9mwoovx77m6ROZM7sXShR/O/JIanvzTwjN3FORfLSr81PsUGd7jlaYOeds9d8tw82oP44+3YucVo+w==",
"dependencies": {
"tslib": "2.3.0"
}
}
},
"dependencies": {
"echarts": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/echarts/-/echarts-5.5.0.tgz",
"integrity": "sha512-rNYnNCzqDAPCr4m/fqyUFv7fD9qIsd50S6GDFgO1DxZhncCsNsG7IfUlAlvZe5oSEQxtsjnHiUuppzccry93Xw==",
"requires": {
"tslib": "2.3.0",
"zrender": "5.5.0"
}
},
"tslib": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
},
"zrender": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/zrender/-/zrender-5.5.0.tgz",
"integrity": "sha512-O3MilSi/9mwoovx77m6ROZM7sXShR/O/JIanvzTwjN3FORfLSr81PsUGd7jlaYOeds9d8tw82oP44+3YucVo+w==",
"requires": {
"tslib": "2.3.0"
}
}
}
}

View File

@ -0,0 +1,5 @@
{
"dependencies": {
"echarts": "^5.5.0"
}
}

BIN
drawing/figs/evolution.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

BIN
drawing/figs/relation.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 KiB